zoukankan      html  css  js  c++  java
  • 设计模式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)

  • 相关阅读:
    CodeForces gym Nasta Rabbara lct
    bzoj 4025 二分图 lct
    CodeForces 785E Anton and Permutation
    bzoj 3669 魔法森林
    模板汇总——快读 fread
    bzoj2049 Cave 洞穴勘测 lct
    bzoj 2002 弹飞绵羊 lct裸题
    HDU 6394 Tree 分块 || lct
    HDU 6364 Ringland
    nyoj221_Tree_subsequent_traversal
  • 原文地址:https://www.cnblogs.com/fortunely/p/9556595.html
Copyright © 2011-2022 走看看