• 设计模式01 创建型模式


    参考

    1. Builder Design Pattern | Youtube

    2. 建造者模式(Builder和Director)| 博客园

    3. 深入理解Builder模式 | 简书

    建造者模式(Builder Pattern)

    将一个复杂对象的构建与表示分离,使得同样的构建过程可以不同的表示。

    通常,在建造者Builder中包含多个不同的属性(基本类型或者别的类对象),这些属性由Builder的方法构建,由Director来组装出一种产品Product。 也就是说,Builder Pattern的目的是为了构建一个或多个Product,不同的构建过程可以表示不同Product。每一个Builder至少代表了一种不同属性的组合,以组装成产品。

    组成 

    Builder 为创建一个Product对象的各个部件指定的抽象接口
    ConcreteBuilder 

    实现Builder接口,构造和装配Product产品的各个部件;

    定义并明确所创建的表示;

    提供一个获取Product的接口。

    Director 构造一个使用Builder接口对象
    Product

    被构造的复杂对象;

    由ConcreteBuilder内部表示和定义它的装配过程;

    包含了组成部件/属性的类,包括将这些部件装配成最终产品的接口。

    适用场景

    [参考1~2]:建造者模式用于创建的Product对象,由其他多个对象组成。

    1)当你想建造的对象由其他对象(称为部件)组成;

    2)当你想这些组件的创建独立于主要对象;

    3)隐藏来自client的部分的创建,以至于这部分和创建对象是相互独立的;

    4)建造者知道细节,并且别人不知道;

    通俗讲,当自己想创建的对象由多个其他类对象组成,并且希望自己创建的对象独立于其他对象的创建,用户不必知道创建这个对象的细节,只需要指定特定Builder来负责建造组件、Director负责何时组装以及如何组装即可。

    特点

    1) 分步构建一个复杂对象。Product通常由别的多个不同的子对象组成,builder提供构建接口和获取最终产品对象的接口。

    2) 支持多种构建表示。Builder模式封装了构建的过程,用户只需传入关心的参数和必须的参数,而不用关心复杂的构建过程,就能创建出不同的表示。

    3) 将部件的创建和部件的组装方式解耦,部件类型和部件装配方式互不影响。

    缺点

    1) 不适合包含同类别子对象的Product创建,如组合模式;

    2) 当Product增加部件时,可能会导致Builder及其子类, Director的大量修改;

    与工厂模式,抽象工厂比较

    工厂模式:提供统一的抽象接口,让子类决定实例化哪一个类,使对象的初始化延迟到子类进行。

    抽象工厂:为创建一组相关或者相互依赖的对象提供一个接口,而无需指定他们具体的类。

    1. 建造者 vs 工厂模式

    工厂模式通常只生产一种产品,而且产品之间没有必然联系。侧重于表示接口和Product之间的关系。

    建造者模式可以产生一种或多种产品表示,不同的构建过程可以表示不同Product。侧重于用多个部件构建复杂产品表示的过程。

    2. 建造者 vs 抽象工厂

    抽象工厂往往产出多个Product,并且Product之间存在一定关联或依赖关系。每个具体Product要求用工厂来创建。抽象工厂的具体工厂生产产品,可以用Builder模式来创建。侧重于表示一组方案。

    建造者模式通常产生1个产品,不同的构建过程有不同的Product表示。侧重于表示1个复杂产品的构建的过程。

    通用类图

     Figure1 Builder Pattern通用类图

    demo 

    下面这个例程跟网上流传的“造人”"造船"例程很像,能体现Builder模式的基本特点,“将对象的创建与表示分离”。但是有一个缺点,就是一个Builder只能生产一种产品对象,因为产品组件在Builder中的创建已经固化了,当需要添加一种对象时,就需要添加一种Builder。

    [参考1] Client要创建Robot,就需要通过RobotBuilder创建OldStyleRobotBuilder,然后再创建RobotEngineer(Robot工程师),在RobotEngineer通过RobotPlan(Robot设计)创建Robot对象。创建过程如Figure2.

    Figure2 Client创建Robot过程

     

    Figure3 demo的UML类图

    代码

     1. 创建Robot接口RobotPlan,定义各属性设置的公共方法

    RoboPlan.java

    public interface RobotPlan {
        
        public void setHead(String head);
        
        public void setTorso(String torso);
        
        public void setArms(String arms);
        
        public void setLegs(String legs);
    }

    2.定义Robot,实现RobotPlan接口,这里的几个属性用String类型

    Robot.java

    public class Robot implements RobotPlan {
        private String head;
        private String torso;
        private String arms;
        private String legs;
    
        @Override
        public void setHead(String head) { this.head = head; }
        
        public String getHead() { return head; }
    
        @Override
        public void setTorso(String torso) { this.torso = torso; }
        
        public String getTorso() { return torso; }
        
        @Override
        public void setArms(String arms) { this.arms = arms; }
    
        public String getArms() { return arms; }
        
        @Override
        public void setLegs(String legs) { this.legs = legs; }
        
        public String getLegs() { return legs; }
    }

    3.定义Robot的Builder 接口RobotBuilder,声明构建Robot子对象/属性的公共方法,读取Robot的方法

    RobotBuilder.java

    public interface RobotBuilder {
        
        public void buildHead();
        
        public void buildTorso();
        
        public void buildArms();
        
        public void buildLegs();
        
        public Robot getRobot();
    }

    4.定义OldStyleRobotBuilder,实现接口RobotBuilder,负责具体构建Robot的子对象/属性

    OldStyleRobotBuilder.java

    /* 将robot各子部件固化到builder中 */
    public class OldStyleRobotBuilder implements RobotBuilder {
    
        private Robot robot;
        
        public OldStyleRobotBuilder(){
            robot = new Robot();
        }
        
        @Override
        public void buildHead() {
            robot.setHead("Tin Head");
        }
    
        @Override
        public void buildTorso() {
            robot.setTorso("Tin Torso");
        }
    
        @Override
        public void buildArms() {
            robot.setArms("Blowtorch Arms");
        }
    
        @Override
        public void buildLegs() {
            robot.setLegs("Roller Legs");
        }
    
        @Override
        public Robot getRobot() {
            return robot;
        }
    
    }

    5. 定义Director RobotEngineer,指导RobotBuilder构建Robot

    RobotEngineer.java

    /* 指导RobotBuilder构建Robot*/
    public class RobotEngineer {
        private RobotBuilder robotBuilder;
        
        public RobotEngineer (RobotBuilder robotBuilder){
            this.robotBuilder = robotBuilder;
        }
        
        public void makeRobot(){
            robotBuilder.buildHead();
            robotBuilder.buildTorso();
            robotBuilder.buildArms();
            robotBuilder.buildLegs();
            
            // 另外一种方式是在此处创建Robot, 然后将build构建的结果复制给Robot
        }
        
        public Robot getRobot(){
            return robotBuilder.getRobot();
        }
    }

    6. RobotBuilderDemo(Client)测试例程

    1) 第一步是创建RobotBuilder具体对象

    2) 第二步是创建Director RobotEngineer,用于指导构建Robot

    3) 第三步是制造/组装Robot

    4) 第四步是测试组装的Robot属性

    public class RobotBuilderDemo {
    
        public static void main(String[] args){
            RobotBuilder robotBuilder = new OldStyleRobotBuilder();
            RobotEngineer robotEngineer = new RobotEngineer(robotBuilder);
            robotEngineer.makeRobot();
            
            Robot robot = robotEngineer.getRobot();
            System.out.println("Robot build component:");
            System.out.println("Robot Head: "+robot.getHead());
            System.out.println("Robot Torso: "+robot.getTorso());
            System.out.println("Robot Arms:"+robot.getArms());
            System.out.println("Robot Legs:"+robot.getLegs());
        }
    }

    7. 运行结果

    总结

    1. 产品的参数往往由外部Client来决定,因此可以将Builder中构建Product属性的方法设为由外部参数决定。

    例如,public void buildHead(); 可修改为public void buildHead(String head)

  • 相关阅读:
    (Windows)VMware虚拟机安装Linux系统
    C++调用HNSW实现图像配准
    (Windows) OpenCV 3.1.0 + opencv_contrib编译
    (Windows)VS2017下编译FLANN1.8.4
    C++读写txt
    数据类型转换
    tensorflow模型的保存与恢复,以及ckpt到pb的转化
    Linux系统安装MySql步骤及截屏
    实时多项式拟合
    Linux系统安装NoSQL(MongoDB和Redis)步骤及问题解决办法
  • 原文地址:https://www.cnblogs.com/fortunely/p/9556595.html
Copyright © 2020-2023  润新知