创建型模式之--创建者模式

Posted ~无关风月~

tags:

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

1、变化是永恒的

制作奔驰、宝马的车辆模型,汽车的启动、停止、喇叭声音、引擎声音 先后顺序由客户控制。

![创建者模式](https://img-blog.csdnimg.cn/20210627165637623.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3p4bTEzMDYxOTI5ODg=,size_16,color_FFFFFF,t_70
每个车都是一个产品。
在CarModel中我们定义了一个setSequence方法, 车辆模型的这几个动作要如何排布, 是在这个ArrayList中定义的。 然后run()方法根据sequence定义的顺序完成指定的顺序动作。

车辆模型抽象类

public abstract class CarModel {

    /**
     * 汽车启动顺序
     */
    private List<String> sequence = new ArrayList<>();

    /**
     * 汽车启动
     */
    protected abstract void start() ;

    /**
     * 汽车停止
     */
    protected abstract void stop();

    /**
     * 汽车响铃
     */
    protected abstract void alarm();

    /**
     * 汽车引擎响
     */
    protected abstract void engineBoom();

    /**
     * 汽车启动
     */
    final public void run() {
        for (String funcName : this.sequence) {
            if (funcName.equalsIgnoreCase("start")) {
                this.start();
            } else if (funcName.equalsIgnoreCase("stop")) {
                this.stop();
            } else if (funcName.equalsIgnoreCase("alarm")) {
                this.alarm();
            } else if (funcName.equalsIgnoreCase("enginBoom")) {
                this.engineBoom();
            }
        }
    }

    /**
     * 设置启动顺序
     * @param sequence
     */
    public void setSequence(List<String> sequence) {
        this.sequence = sequence;
    }

}

奔驰模型

public class BenzModel extends CarModel{
    /**
     * 汽车启动
     */
    @Override
    protected void start() {
        System.out.println("奔驰车开跑");
    }
    /**
     * 汽车停止
     */
    @Override
    protected void stop() {
        System.out.println("奔驰车停车");
    }
    /**
     * 汽车响铃
     */
    @Override
    protected void alarm() {
        System.out.println("奔驰车响喇叭");
    }
    /**
     * 汽车引擎响
     */
    @Override
    protected void engineBoom() {
        System.out.println("奔驰车引擎声");
    }
}

抽象汽车组装者

public abstract class CarBuilder {
    /**
     * 设置顺序
     * @param sequence
     */
    public abstract void setSequence(List<String> sequence);
    /**
     * 得到模型
     * @return
     */
    public abstract CarModel getCarModel();
}

奔驰车组装者

public class BMWBuilder extends CarBuilder {
    private BMWModel bmwModel = new BMWModel();
    /**
     * 设置顺序
     *
     * @param sequence
     */
    @Override
    public void setSequence(List<String> sequence) {
        this.bmwModel.setSequence(sequence);
    }
    /**
     * 得到模型
     *
     * @return
     */
    @Override
    public CarModel getCarModel() {
        return this.bmwModel;
    }
}

导演类
负责按照指定顺序生产模型

public class Director {
    private List<String> sequence = new ArrayList<>();
    private BenzBuilder benzBuilder = new BenzBuilder();
    private BMWBuilder bmwBuilder = new BMWBuilder();

    public BenzModel getABenzModel() {
        this.sequence.clear();
        this.sequence.add("start");
        this.sequence.add("stop");
        this.benzBuilder.setSequence(this.sequence);
        return (BenzModel)this.benzBuilder.getCarModel();
    }

    public BMWModel getCBMWModel() {
        this.sequence.clear();
        this.sequence.add("alarm");
        this.sequence.add("start");
        this.sequence.add("stop");
        this.bmwBuilder.setSequence(this.sequence);
        return (BMWModel)this.bmwBuilder.getCarModel();
    }
}

场景类
生产A 类型的奔驰车100万辆,C类型的宝马车200万辆

public class Client {

    public static void main(String[] args) {
        Director director = new Director();
        for (int i = 0; i < 100; i++) {
            director.getABenzModel().run();
        }
        for (int i = 0; i < 200; i++) {
            director.getCBMWModel().run();
        }
    }
}

2、建造者模式定义

建造者模式(Builder Pattern)也叫做生成器模式。

Separate the construction of a complex object from its representation so that the same construction precess can create different representaions.(将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。)

创建者模式
4个角色:

  • Product产品类
    通常是实现了模板方法模式, 也就是有模板方法和基本方法。

  • Builder抽象创建者
    规范产品的组建,一般是由子类实现。

  • ConcreteBuilder具体创建者
    实现抽象类定义的所有方法, 并且返回一个组建好的对象。 例子中的BenzBuilder和BMWBuilder就属于具体建造者。

  • Director导演类
    负责安排已有模块的顺序, 然后告诉Builder开始建造, 在上面的例子中就是我们的老大, ××公司找到老大, 说我要这个或那个类型的车辆模型, 然后老大就把命令传递给我, 我和我的团队就开始拼命地建造, 于是一个项目建设完毕了。

通用源代码

Product类
通常它是一个组合或继承(如模板方法模式) 产生的类

public class Product {
	public void doSomething(){
		//独立业务处理
	}
}

抽象建造者

public abstract class Builder {
	//设置产品的不同部分, 以获得不同的产品
	public abstract void setPart();
	//建造产品
	public abstract Product buildProduct();
}

setPart方法是零件的配置, 什么是零件? 其他的对象, 获得一个不同零件, 或者不同的装配顺序就可能产生不同的产品。

具体建造者

public class ConcreteProduct extends Builder {
	private Product product = new Product();
	//设置产品零件
	public void setPart(){
		/*
		* 产品类内的逻辑处理
		*/
	}
	//组建一个产品
	public Product buildProduct() {
		return product;
	}
}

注意:如果有多个产品类就有几个具体的建造者, 而且这多个产品类具有相同接口或抽象类。

导演类

public class Director {
	private Builder builder = new ConcreteProduct();
	//构建不同的产品
	public Product getAProduct(){
		builder.setPart();
		/*
		* 设置不同的零件, 产生不同的产品
		*/
		return builder.buildProduct();
	}
}

3、建造者模式的应用

建造者模式的优点

封装性
使用建造者模式可以使客户端不必知道产品内部组成的细节, 如例子中我们就不需要关心每一个具体的模型内部是如何实现的, 产生的对象类型就是CarModel。

建造者独立, 容易扩展
BenzBuilder和BMWBuilder是相互独立的, 对系统的扩展非常有利。

便于控制细节风险
由于具体的建造者是独立的, 因此可以对建造过程逐步细化, 而不对其他的模块产生任何影响。

建造者模式的使用场景

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

建造者模式的注意事项

建造者模式关注的是零件类型和装配工艺(顺序),这是它与工厂方法模式最大不同的地方, 虽然同为创建类模式, 但是注重点不同。

建造者模式最主要的功能是基本方法的调用顺序安排, 也就是这些基本方法已经实现了, 通俗地说就是零件的装配, 顺序不同产生的对象也不同; 而工厂方法则重点是创建, 创建零件是它的主要职责, 组装顺序则不是它关心的。

建造者模式中还有一个角色没有说明, 就是零件, 建造者怎么去建造一个对象? 是零件的组装, 组装顺序不同对象效能也不同, 这才是建造者模式要表达的核心意义, 而怎么才能更好地达到这种效果呢? 引入模板方法模式是一个非常简单而有效的办法。

Builder模式

public class Person {
    private String name;
    private int age;

    private Person(Builder builder) {
        this.name = builder.name;
        this.age = builder.age;
    }

    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }

    public Builder newBuilder() {
        return new Builder(this);
    }

    public static class Builder {
        private String name;
        private int age;

        public Builder() {
            this.age = 0;
            this.name = "";
        }

        Builder(Person person) {
            this.name = person.name;
            this.age = person.age;
        }

        public Builder setAge(int age) {
            this.age = age;
            return this;
        }

        public Builder setName(String name) {
            this.name = name;
            return this;
        }

        public Person create() {
            return new Person(this);
        }
    }
}

将对象的创建与表示相分离,用户不用关心它的内在是什么样的。只需要知道传给他什么参数。在一些有很多参数的产品类中使用该模式,可以避免我们在构造函数中传入大量的默认参数来赋值的尴尬。

如果我们给Person类每一个参数都设置一个set方法,这样会增加Person类的功能和职责。违反了单一原则,不利于后期的维护。Builder模式更符合封装的原则,不对外公开属性的写操作!

以上是关于创建型模式之--创建者模式的主要内容,如果未能解决你的问题,请参考以下文章

创建型模式之建造者模式

(转自精通Python设计模式)Python设计模式之创建型模式——1.工厂模式

创建型设计模式之原型模式

设计模式创建型模式之单例设计模式

创建型模式之工厂方法模式实例及代码操作

创建型模式之单例模式