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

Posted ~无关风月~

tags:

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

1、变化是永恒的

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


每个车都是一个产品。
在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模式

  1. 创建一个名为ThisClassBuilder的内部静态类,并具有和实体类形同的属性(称为构建器)。
  2. 在构建器中:对于目标类中的所有的属性和未初始化的final字段,都会在构建器中创建对应属性。
  3. 在构建器中:创建一个无参的default构造函数。
  4. 在构建器中:对于实体类中的每个参数,都会对应创建类似于setter的方法,只不过方法名与该参数名相同。 并且返回值是构建器本身(便于链式调用)。
  5. 在构建器中:一个build()方法,调用此方法,就会根据设置的值进行创建实体对象。
  6. 在构建器中:同时也会生成一个toString()方法。
  7. 在实体类中:会创建一个builder()方法,它的目的是用来创建构建器。
@Builder
public class User 
    private final Integer code = 200;
    private String username;
    private String password;


// 编译后:
public class User 
    private String username;
    private String password;
    User(String username, String password) 
        this.username = username; this.password = password;
    
    public static User.UserBuilder builder() 
        return new User.UserBuilder();
    

    public static class UserBuilder 
        private String username;
        private String password;
        UserBuilder() 

        public User.UserBuilder username(String username) 
            this.username = username;
            return this;
        
        public User.UserBuilder password(String password) 
            this.password = password;
            return this;
        
        public User build() 
            return new User(this.username, this.password);
        
        public String toString() 
            return "User.UserBuilder(username=" + this.username + ", password=" + this.password + ")";
        
    

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

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

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

设计模式之创建型工厂模式

设计模式工厂模式(创建型)

设计模式之 简单工厂模式

设计模式之创建型抽象工厂模式

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

创建型模式之建造者模式实例及代码操作