设计模式之构造者模式

Posted 1314xf

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了设计模式之构造者模式相关的知识,希望对你有一定的参考价值。

建造者模式

一:建造者概述

我们大家可能都会开小汽车,但是当你得到一辆小汽车的时候,你可以用它驰骋马路,但是你知道它组件复杂的构造过程吗,并不知道。而我们今天要讲的建造者模式其实就是复杂的创建型模式客户端无需知道复杂对象的内部组成和装配方式,只需要知道建造者的类型即可。它关注的是一步步的创建独立的复杂对象,不同的具体构造者定义不同的创建过程。其定义如下:

建造者模式(Builder Pattern):将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。建造者模式是一种对象创建型模式


二:建造者结构图

技术分享图片

在结构图中包含以下几个角色

  • Builder(抽象建造者): 是一个抽象接口,为了创建一个产品对象的各个部件 ,主要有两类方法,一类是buildXX,用于创建复杂对象的各个部件,一类是getProduct,用于返回复杂对象。
  • ActualBuilder(实际的建造者):实现Builder接口,实现各个部件的建造方法,返回创建好的复杂对象。
  • Product(产品角色):被构建出来的复杂对象,包含多个部件。
  • Director(指挥者):负责安排部件创建的顺序,客户端一般只和指挥者进行交互,在客户端确定实际的建造者,然后通过指挥者的构造函数或者setter方法将该对象传入到指挥者类中。

三:典型代码

Builder(抽象建造者)

public abstract class Builder {
    // 创建产品对象
    protected  Product product = new Product();

    // 具体部件建造过程在ActualBuilder中实现
    public  abstract void buildPartA();
    public  abstract void buildPartB();
    public  abstract void buildPartC();

    // 定义工厂方法,返回一个完整产品对象
    public Product getProduct(){
        return product;
    }
}

ActualBuilder(实际的建造者)

public class ActualBuilder extends Builder {
    @Override
    public void buildPartA() {
        product.setPartA("设置部件A");
    }

    @Override
    public void buildPartB() {
        product.setPartA("设置部件B");
    }

    @Override
    public void buildPartC() {
        product.setPartA("设置部件C");
    }
}

Product(产品角色)

// 产品对象
public class Product {
    // 定义部件
    private String partA;
    private String partB;
    private String partC;

    public String getPartA() {
        return partA;
    }

    public void setPartA(String partA) {
        this.partA = partA;
    }

    public String getPartB() {
        return partB;
    }

    public void setPartB(String partB) {
        this.partB = partB;
    }

    public String getPartC() {
        return partC;
    }

    public void setPartC(String partC) {
        this.partC = partC;
    }
}

Director(指挥者)

public class Director {
    private  Builder builder;

    // 方式一:通过构造函数设置实际的构造者
    // 传入类型是基类,面向抽象编程,符合里氏替换原则
    public  Director(Builder builder) {
        this.builder=builder;
    }

    // 方式二:通过setter方法设置实际的构造者
    public  void setBuilder(Builder builder) {
        this.builder=builder;
    }

    // 构建复杂产品对象
    public Product construct(){
        // 指挥者可以决定产品部件的构建顺序
        builder.buildPartC();
        builder.buildPartA();
        builder.buildPartB();
        return builder.getProduct();
    }
}

四:组装小汽车案例

结构图:

技术分享图片

案例代码:

产品对象汽车


// 产品对象
public class Car {
    // 定义部件
    // 轮胎
    private String tire;
    // 座椅
    private String seat;
    // 发动机
    private String engine;

    public String getTire() {
        return tire;
    }

    public void setTire(String tire) {
        this.tire = tire;
    }

    public String getSeat() {
        return seat;
    }

    public void setSeat(String seat) {
        this.seat = seat;
    }

    public String getEngine() {
        return engine;
    }

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

汽车的抽象建造者

public abstract class CarBuilder {
    // 创建汽车
    protected Car car = new Car();

    // 创建轮胎
    public  abstract void buildTire();
    // 创建座椅
    public  abstract void buildSeat();
    // 创建发动机
    public  abstract void buildEngine();

    // 定义工厂方法,返回一个完整汽车
    public Car getCar(){
        return car;
    }
}

具体建造者:大众

// 大众汽车
public class DaZhongCarBuilder extends CarBuilder {
    @Override
    public void buildTire() {
        car.setTire("大众轮胎");
    }

    @Override
    public void buildSeat() {
        car.setSeat("大众座椅");
    }

    @Override
    public void buildEngine() {
        car.setEngine("大众发动机");
    }
}

具体建造者:丰田

// 丰田汽车
public class FenTianCarBuilder extends CarBuilder {

    @Override
    public void buildTire() {
        getCar().setTire("丰田轮胎");
    }

    @Override
    public void buildSeat() {
        getCar().setSeat("丰田座椅");
    }

    @Override
    public void buildEngine() {
        getCar().setEngine("丰田发动机");
    }
}

指挥者

public class CarDirector {
    private CarBuilder carBuilder;

    // 方式一:通过构造函数设置实际的构造者
    // 传入类型是基类,面向抽象编程,符合里氏替换原则
    public CarDirector(CarBuilder carBuilder) {
        this.carBuilder = carBuilder;
    }

    // 方式二:通过setter方法设置实际的构造者
    public  void setCarBuilder(CarBuilder carBuilder) {
        this.carBuilder = carBuilder;
    }

    // 构建复杂产品对象
    public Car construct(){
        // 指挥者可以决定产品部件的构建顺序
        carBuilder.buildTire();
        carBuilder.buildSeat();
        carBuilder.buildEngine();
        return carBuilder.getCar();
    }
}

客户端

public class Client {

    public static void main(String[] args) {
        // 创建一个实际车的构造者
        CarBuilder carBuilder = new FenTianCarBuilder();
        // 创建指挥者
        CarDirector carDirector = new CarDirector(carBuilder);
        // 构建出完整产品
        Car product = carDirector.construct();

    }
}

说明整个流程其实很简单,指挥者指导构建者一步步的构造完整产品,根据指挥者定义的构造过程可以创建出完全不同的产品


五:如何控制构造者不生产某个部件

我们发现构造整个产品的构造过程都是按照指挥者构建部件的顺序逐步构建,但是可能有的具体的构造者不需要某个部件,比如大众汽车不需要座椅(当然这是不可能的),那么它就不需要调用buildSeat()方法。为了解决这个问题,我们引入一个钩子方法,通常钩子方法名为isXXX(),其定义在抽象构造者类中,我们可以定义一个isSeat()的方法,来判断是否需要座椅,并为之提供一个默认实现为false。

抽象构造者中设置是否需要座椅的钩子方法

public abstract class CarBuilder {
    // 创建汽车
    protected Car car = new Car();

    // 创建轮胎
    public  abstract void buildTire();
    // 创建座椅
    public  abstract void buildSeat();
    // 创建发动机
    public  abstract void buildEngine();

    // 定义一个钩子方法,是否需要座椅, 默认为true
    public boolean isSeat(){
        return  true;
    }

    // 定义工厂方法,返回一个完整汽车
    public Car getCar(){
        return car;
    }
}

具体构造者覆盖钩子方法,返回false,表示不需要座椅

// 大众汽车
public class DaZhongCarBuilder extends CarBuilder {
    @Override
    public void buildTire() {
        car.setTire("大众轮胎");
    }

    @Override
    public void buildSeat() {
        car.setSeat("大众座椅");
    }

    @Override
    public void buildEngine() {
        car.setEngine("大众发动机");
    }

    @Override
    public boolean isSeat() {
        return false;
    }
}

指挥者根据具体构造者的需求构建产品

public class CarDirector {
    private CarBuilder carBuilder;
    // ........省略部分代码

    // 构建复杂产品对象
    public Car construct(){
        // 指挥者可以决定产品部件的构建顺序
        carBuilder.buildTire();
        // 钩子方法 用来确定是否需要构建某个部件
        if(carBuilder.isSeat()){
            // 表示需要座椅的时候才会构建
            carBuilder.buildSeat();
        }
        carBuilder.buildEngine();
        return carBuilder.getCar();
    }
}

六:建造者模式总结

  • 优点

    1. 客户端不需要知道具体创建对象的细节,将产品本身和产品的创建过程解耦,相同的创建过程可以创建出不同的产品对象。
    2. 每个具体建造者相对独立,增加新的具体建造者不会影响现有的类库代码,符合开闭原则。
    3. 可以采用钩子方法精确的控制某个具体建造者是否需要某个部件。可以针对的控制产品构建流程。
  • 缺点

    1. 如果产品之间的差异性较大,那么即使使用钩子方法来控制,那也是极其麻烦,且公共接口很难抽象。非常不适合。
  • 适用场景

    1. 需要生成的产品对象有复杂的内部结构,这些产品对象通常包含多个成员属性。
    2. 需要生成的产品对象的属性相互依赖,需要指定其生成顺序。
    3. 对象的创建过程独立于创建该对象的类。在建造者模式中通过引入了指挥者类,将创建过程封装在指挥者类中,而不在建造者类和客户类中。
    4. 隔离复杂对象的创建和使用,并使得相同的创建过程可以创建不同的产品。

七:抽象工厂模式和建造者模式的区别

  1. 抽象工厂模式返回的是一系列相关的产品,而建造者模式返回的是一个具体的完整对象。
  2. 抽象工厂模式的客户端是通过选择具体工厂来生成所需要的对象,而建造者模式是通过Director类去指导如何一步步的生成部件,返回完整对象。
  3. 简单的理解:抽象工厂模式就是汽车配件生产厂,生产不同类型的汽车配件,而建造者模式就是一个汽车组装厂,组装配件返回完整汽车。

参考:https://blog.csdn.net/lovelion/article/details/7426015


号外号外:

  • 如果有小伙伴觉得我写的不错的话可以关注一下我的博客哦
  • 可以关注下方我的公众号java架构师小密圈,回复1获取2Tjava架构师必备干货另外:小伙伴可以回复任意想学的技术,可以免费帮你搜寻其实我们还需要学很多!!!!!!

技术分享图片

  • 还会分享一些赚钱理财的小套路哦,欢迎大家来支持,一起学习成长,程序员不仅仅是搬瓦工!

公众号:分享系列好文章
技术分享图片

交流群:一起奔着java架构师努力
技术分享图片



以上是关于设计模式之构造者模式的主要内容,如果未能解决你的问题,请参考以下文章

设计模式之GOF23建造者模式

设计模式之建造者模式

设计模式

《设计模式》之建造者模式(Builder)

《Java设计模式》之构建者模式

设计模式之建造者模式(builder)