设计模式之建造者模式

一、概述

1、简介:
  • 允许用户在不知道内部构建细节的情况下,可以更精细的控制对象的构造流程
  • 将部件和组装过程分离,使得构建过程和部件都可以*扩展,两者之间的耦合也降到最低
2、 定义:
  • 将一个复杂对象的构建与他的表示分离,使得同样的构建过程可以创建不同的表示
3、 使用场景:
  • 相同的方法,不同的执行顺序,产生不同的事件结果时
  • 多个部件或零件,都可以装配到一个对象中,但是产生的运行结果又不相同时
  • 产品类非常复杂,或者产品类中的调用顺序不同产生了不同的作用
  • 当初始化一个对象特别复杂,如参数多,且很多参数都具有默认值时
4、优缺点
  • 优点:

    • 良好的封装性,使用者可以不必知道产品内部组成的细节
    • 建造者独立,易于解耦
    • 容易扩展
  • 缺点:

    • 会产生多余的Builder对象,消耗内存
5、UML类图

设计模式之建造者模式

  • (1)Product:产品的抽象类
    • 具体的产品类实现
  • (2)Builder:抽象的Builder类。规范产品的组建,一般是由子类实现具体的组装过程
  • (3)ConcreteBuilder:具体的builder类
  • (4)Director:统一组装过程(具体的构造)

二、实现

1、 经典实现
  • 背景:小成希望去电脑城买一台组装的台式主机

  • 过程:

    • 电脑城老板(Diretor)和小成(Client)进行需求沟通(买来打游戏?学习?看片?)
    • 了解需求后,电脑城老板将小成需要的主机划分为各个部件(Builder)的建造请求(CPU、主板blabla)
    • 指挥装机人员(ConcreteBuilder)去构建组件;
    • 将组件组装起来成小成需要的电脑(Product)
  • (1)Builder(定义组装过程)

    public  abstract class Builder {  
    
    //第一步:装CPU
    //声明为抽象方法,具体由子类实现 
        public abstract void  BuildCPU();
    
    //第二步:装主板
    //声明为抽象方法,具体由子类实现 
        public abstract void BuildMainboard();
    
    //第三步:装硬盘
    //声明为抽象方法,具体由子类实现 
        public abstract void BuildHD();
    
    //返回产品的方法:获得组装好的电脑
        public abstract Computer GetComputer();
    }
    
  • (2)Director(老板委派任务给装机人员)

    public class Director{
                    //指挥装机人员组装电脑
                    public void Construct(Builder builder){
    
                             builder.BuildCPU();
                             builder.BuildMainboard();
                             builder.BuildHD();
                          }
    }
    
  • (3)ConcreteBuilder(创建具体的建造者)

    //装机人员
    public class ConcreteBuilder extend  Builder{
        //创建产品实例
        Computer computer = new Computer();
    
        //组装产品
        @Override
        public void BuildCPU(){  
            computer.Add("组装CPU")
        }  
    
        @Override
        public void BuildMainboard(){  
            computer.Add("组装主板")
        }  
    
        @Override
        public void  BuildHD(){  
            computer.Add("组装主板")
        }  
    
        //返回组装成功的电脑
        @Override
        public  Computer GetComputer(){  
            return computer
        }  
    }
    
  • (4)product(定义具体的产品类)

    public class Computer{
    
        //电脑组件的集合
        private List<String> parts = new ArrayList<String>();
    
        //用于将组件组装到电脑里
        public void Add(String part){
        parts.add(part);
        }
    
        public void Show(){
            for (int i = 0;i<parts.size();i++){    
                System.out.println(“组件”+parts.get(i)+“装好了”);
            }
            System.out.println(“电脑组装完成,请验收”);
        }
    }
    
  • Test

    public class Builder Pattern{
        public static void main(String[] args){
        //逛了很久终于发现一家合适的电脑店
        //找到该店的老板和装机人员
        Director director = new Director();
        Builder builder = new ConcreteBuilder();
    
        //沟通需求后,老板叫装机人员去装电脑
        director.Construct(builder);
    
        //装完后,组装人员搬来组装好的电脑
        Computer computer = builder.GetComputer();
        //组装人员展示电脑给小成看
        computer.Show();
        }
    }
    
2、链式调用实现
 public class User {

     private final String firstName;     // 必传参数
     private final String lastName;      // 必传参数
     private final int age;              // 可选参数
     private final String phone;         // 可选参数
     private final String address;       // 可选参数 

     private User(UserBuilder builder) {
         this.firstName = builder.firstName;
         this.lastName = builder.lastName;
         this.age = builder.age;
         this.phone = builder.phone;
         this.address = builder.address;
     }

     public String getFirstName() {
         return firstName;
     }

     public String getLastName() {
         return lastName;
     }

     public int getAge() {
         return age;
     }

     public String getPhone() {
         return phone;
     }

     public String getAddress() {
         return address;
     }

     //UserBuilder静态内部类,每次返回的都是this
     public static class UserBuilder {
         private final String firstName;
         private final String lastName;
         private int age;
         private String phone;
         private String address;

         public UserBuilder(String firstName, String lastName) {
             this.firstName = firstName;
             this.lastName = lastName;
         }

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

         public UserBuilder phone(String phone) {
             this.phone = phone;
             return this;
         }

         public UserBuilder address(String address) {
             this.address = address;
             return this;
         }
 
         public User build() {
             return new User(this);
         }
     }
 }
  • User类的构造方法是私有的。也就是说调用者不能直接创建User对象。

  • User类的属性都是不可变的。所有的属性都添加了final修饰符,并且在构造方法中设置了值。并且,对外只提供getters方法。

  • 由于Builder是非线程安全的,所以如果要在Builder内部类中检查一个参数的合法性,必需要在对象创建完成之后再检查。

    // 线程安全
    
    public User build() {
        User user = new user(this);  //先实例化好对象
        if (user.getAge() > 120) {
            throw new IllegalStateException(“Age out of range”);   
        }
        return user;
    }    
    
    //线程不安全
    
    public User build() {
        if (age > 120) {
            throw new IllegalStateException(“Age out of range”); 
        }
        return new User(this);  //最后才实例化对象
    }