您现在的位置是:首页 >技术教程 >设计模式详解(五)——建造者模式网站首页技术教程

设计模式详解(五)——建造者模式

Yarrow-Y 2024-06-17 10:15:01
简介设计模式详解(五)——建造者模式

建造者模式简介

建造者模式定义
建造者模式,相当于是对工厂生产产品的一种装配,由于这种装配可能随时改变,所以需要抽取出来,实现产品局部与整体的解耦。
它是将一个复杂对象的构建过程与它的实现表示分离,使得同样的构建过程可以创建不同的表示,属于创建型模式。使用创建者模式对于用户而言只需要制定需要建造的类就可以获得对象,建造过程及细节不需要了解。
建造者模式适用于创建对象需要很多步骤,但是步骤的顺序不一定固定。如果一个对象有非常复杂的内部结构(很多属性),可以将复杂对象的创建和使用进行分离。

建造者模式的设计主要有四个角色:

  • 抽象建造者(Builder)角色:给 出一个抽象接口,以规范产品对象的各个组成成分的建造。一般而言,此接口独立于应用程序的商业逻辑。模式中直接创建产品对象的是具体建造者 (ConcreteBuilder)角色。具体建造者类必须实现这个接口所要求的两种方法:一种是建造方法,另一种是返还结构方法。建造者的抽象类,规范产品对象的各个组成部分的建造,一般由子类实现具体的建造过程。
  • 具体建造者(ConcreteBuilder)角色:担任这个角色的是与应用程序紧密相关的一些类,它们在应用程序调用下创建产品的实例。具体的Builder类,根据不同的业务逻辑,具体化对象的各个组成部分的创建。这个角色要完成的任务包括:1.实现抽象建造者Builder所声明的接口,给出一步一步地完成创建产品实例的操作。2.在建造过程完成后,提供产品的实例。
  • 指挥者类(Director):调用具体建造者来创建复杂对象的各个部分,在指导者中不涉及具体产品的信息,只负责保证对象各部分完整创建或按某种顺序创建。
  • 产品(Product)角色:产品便是建造中的复杂对象。一般来说,一个系统中会有多于一个的产品类,而且这些产品类并不一定有共同的接口,而完全可以是不相关联的。

建造者模式优缺点:
优点

  1. 封装性好,创建和使用分离
  2. 扩展性好,建造类之间独立,一定程度上实现了解耦
  3. 在建造者模式中,客户端不必知道产品内部组成的细节,将产品本身与产品的创建过程解耦,使得相同的创建过程可以创建不同的产品对象。
  4. 每一个具体建造者都相对独立,而与其他的具体建造者无关,因此可以很方便地替换具体建造者或者增加新的具体建造者,用户使用不同的具体建造者即可得到不同的产品对象。由于指挥者类针对抽象建造者编程,增加新的具体建造者无须修改原有类库的代码,系统扩展方便,符合开闭原则。
  5. 具体的建造者类之间是相互独立的,这有利于系统的扩展.增加新的具体建造者无需修改原有类库的代码,符合“开闭原则”。

缺点

  1. 产生多余的 Builder 对象
  2. 产品内部发生变化时,建造者都需要修改,成本较大
  3. 建造者模式所创建的产品一般具有较多的共同点,其组成部分相似,如果产品之间的差异性很大,例如很多组成部分都不相同,不适合使用建造者模式,因此其使用范围受到一定的限制。
  4. 具体的建造者类之间是相互独立的,这有利于系统的扩展.增加新的具体建造者无需修改原有类库的代码,符合“开闭原则”。

使用场景

  1. 相同的方法,不同的执行顺序,产生不同的事件结果时,可以采用建造者模式。
  2. 多个部件或零件,都可以装配到一个对象中,但是产生的运行结果又不相同时,则可以使用该模式。
  3. 产品类非常复杂,或者产品类中的调用顺序不同产生了不同的效能,这个时候使用建造者模式非常合适。
  4. 在对象创建过程中会使用到系统中的一些其他对象,这些对象在产品对象的创建过程 中不易得到时,也可以采用建造者模式封装该对象的创建过程。该种场景只能是一个补偿方法,因为一个对象不容易获得,而在设计阶段竟然没有发觉,而要通过创建者模式柔化创建过程,本身已经违反设计的最初目标。

用途
1.需要生成的产品对象有复杂的内部结构,每一个内部成分本身可以是对象,也可以仅仅是一个对象(即产品对象)的一个组成部分。
2.需要生成的产品对象的属性相互依赖。建造模式可以强制实行一种分步骤进行的建造过程,因此,如果产品对象的一个属性必须在另一个属性被赋值之后才可以被赋值,使用建造模式是一个很好的设计思想。
3.在对象创建过程中会使用到系统中的其他一些对象,这些对象在产品对象的创建过程中不易得到。

以下举一个例子:
汽车购买者:你只需要说出你需要的型号(对象的类型和内容),然后直接购买就可以使用了

  1. 产品(Product):要创建的产品对象
/**
 * @author yyx
 */
public class Car {
    private String engine;
    private String wheel;

    public String getEngine() {
        return engine;
    }

    public void setEngine(String engine) {
        this.engine = engine;
    }

    public String getWheel() {
        return wheel;
    }

    public void setWheel(String wheel) {
        this.wheel = wheel;
    }
}
  1. 建造者抽象(Builder):建造者的抽象类,规范产品对象的各个组成部分的建造,一般由子类实现具体的建造过程。
/**
 * @author yyx
 */
public abstract class Builder {
    protected Car car = new Car();

    public abstract void buildEngine();

    public abstract void buildWheel();

    public abstract Car createCar();

}
  1. 建造者(ConreteBuilder):具体的Builder类,根据不同的业务逻辑,具体化对象的各个组成部分的创建。
/**
 * @author yyx
 */
public class BMWBuilder extends Builder {
    @Override
    public void buildEngine() {
        car.setEngine("BMW发动机");
    }

    @Override
    public void buildWheel() {
        car.setWheel("BMW轮子");
    }

    @Override
    public Car createCar() {
        return car;
    }
}
/**
 * @author yyx
 */
public class BenzBuilder extends Builder {
    @Override
    public void buildEngine() {
        car.setEngine("奔驰发动机");
    }

    @Override
    public void buildWheel() {
        car.setWheel("奔驰轮子");
    }

    @Override
    public Car createCar() {
        return car;
    }
}
  1. 调用者(Diretor):调用具体的建造者,来创建对象的各个部分,在调用者中不涉及具体产品的信息,只负责保证对象各部分完整创建或按某种顺序创建。
/**
 * @author yyx
 */
public class Director {
    private Builder builder;

    public Director(Builder builder) {
        this.builder = builder;
    }
    public Car construct() {
        builder.buildEngine();
        builder.buildWheel();
        return builder.createCar();
    }
}
  1. 测试类Client
/**
 * @author yyx
 */
public class Client {
    public static void main(String[] args) {
        System.out.println("=====BMW=====");
        //创建指挥者对象
        Director director = new Director(new BMWBuilder());
        //指挥者组装汽车
        Car car = director.construct();
        System.out.println(car.getEngine());
        System.out.println(car.getWheel());

        System.out.println("=====奔驰=====");
        //创建指挥者对象
        Director director1 = new Director(new BenzBuilder());
        //指挥者组装汽车
        Car car1 = director1.construct();
        System.out.println(car1.getEngine());
        System.out.println(car1.getWheel());

    }
}

运行结果如下所示:

=====BMW=====
BMW发动机
BMW轮子
=====奔驰=====
奔驰发动机
奔驰轮子

总而言之:
  建造者模式的原理和实现比较简单,需要注意的是使用的场景,避免过度使用。
实际上某些场景使用构造函数加set()方法就可以直接完成的场景,也没有必要非要是用建造者模式。
  

以上代码下载请点击该链接:https://github.com/Yarrow052/Java-package.git

风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。