1

Java 23种设计模式之构建者Builder模式

一:定义
建造者模式:指的是将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示,这样的设计模式称为建造者模式。
它是将一个复杂的对象分解为多个简单的对象,然后一步一步构建而成。它将变与不变相分离,即产品的组成部分是不变的,但每一部分是可以灵活选择的
二.Builder模式的结构
1.产品角色(Product):它是包含多个组成部件的复杂对象,由具体建造者来创建其各个零部件。
2.抽象建造者(Builder):它是一个包含创建产品各个子部件的抽象方法的接口,通常还包含一个返回产品的方法getResult().
3.具体的建造者(Concrete Builder):实现Builder接口,完成复杂产品的各个部件的具体创建方法
4.指挥者(Director):它调用建造者对象中的部件构造与装配方法完成复杂对象的创建,在指挥中不涉及具体产品的信息
image.png
聚合关系:聚合关系是一种特殊的关联关系,聚合关系强调的是整体和部分的关系,其中部分可以脱离整体而存在。比如雁群和一只大雁的关系,就是聚合关系,大雁离开雁群还是可以独立存在的。
依赖关系:依赖关系是一种很弱的关系,一般是指一个类使用另一个类,这里学生捡到钱交给警察叔叔,学生和警察叔叔就是一种依赖关系
泛化关系:泛化关系在Java中也叫作继承关系,在UML中我们用带空心三角形的直线来表示,我们增加两个类,一个ConcreteBuilder1类,一个ConcreteBuilder2类,两个类均继承自Builder类
三:Builder模式的实现
1.我们要建造一个产品Product--组装电脑
2.抽象的Builder---装CPU,内存条,硬盘等抽象的步骤
3.Builder的具体实现ConcreteBuilder -- 对上述抽象步骤的实现,比如装i5CPU、8G内存条、1T硬盘
4.使用者Director -- 电脑装机人员
(1)产品的Product:电脑

public class Computer {
    /*CPU*/
    private String CPU;
    /*内存*/
    private String memory;
    /*硬盘*/
    private String hardDisk;
    /*键盘*/
    private String keyboard;
    /*鼠标*/
    private String mouse;
//配置内存
 
    public void setCPU(String CPU) {
        this.CPU = CPU;
    }

 
//配置内存
    public void setMemory(String memory) {
        this.memory = memory;
    }

  //配置硬盘

    public void setHardDisk(String hardDisk) {
        this.hardDisk = hardDisk;
    }

  
//配置键盘
    public void setKeyboard(String keyboard) {
        this.keyboard = keyboard;
    }

  //配置鼠标
    public void setMouse(String mouse) {
        this.mouse = mouse;
    }

    @Override
    public String toString() {
        return "Computer{" +
                "CPU='" + CPU + '\'' +
                ", memory='" + memory + '\'' +
                ", hardDisk='" + hardDisk + '\'' +
                ", keyboard='" + keyboard + '\'' +
                ", mouse='" + mouse + '\'' +
                '}';
    }
}

(2)抽象的构建者Builder类通过接口实现,也可以通过抽象类


public interface ComputerConfigBuilder {
    /*电脑组装一般都需要安装CPU、内存条、硬盘、键盘鼠标等,我们把这一安装过程给抽象出来,也就是这里的ComputerConfigBuilder ,至于具体安装什么需要其实现类来实现,另外其中还定义了一个获取Conputer的方法。*/
    void setCPU();
    void setMemery();
    void setHardDisk();
    void setKeyboard();
    void setMouse();
    //定义了一个获取产品Computer的方法返回的computer对象
    Computer getComputer();
}

使用抽象类可以这一使用

//这里需要了解抽象类和接口的区别
public abstract class ComputerConfigBuilder1 {
   public abstract void setCPU();
    public abstract   void setMemery();
    public abstract  void setHardDisk();
    public abstract void setKeyboard();
    public abstract void setMouse();
    //定义了一个获取产品Computer的方法返回的computer对象
    public abstract Computer getComputer();
}

(3)创建一个低配版的套餐LowConfigBuilder ,让其实现ComputerConfigBuilder

public class LowConfigBuilder implements ComputerConfigBuilder {
    //产品类Computer类
    private Computer computer;

    public LowConfigBuilder() {
        //构造方法中创建产品类
        this.computer = new Computer();
    }

    @Override
    public void setCPU() {
        computer.setCPU("i5");

    }

    @Override
    public void setMemery() {
        computer.setMemory("8G");

    }

    @Override
    public void setHardDisk() {
        computer.setHardDisk("500G");

    }

    @Override
    public void setKeyboard() {
        computer.setKeyboard("薄膜键盘");

    }

    @Override
    public void setMouse() {
        computer.setMouse("有线鼠标");

    }
/**具体实现类返回产品*/
    @Override
    public Computer getComputer() {
        return computer;
    }
}

高配的组装类

public class HighConfigBuider  implements ComputerConfigBuilder{
    private Computer mComputer;

    public HighConfigBuider(){
        this.mComputer = new Computer();
    }
    @Override
    public void setCPU() {
        mComputer.setCPU("i7");
    }

    @Override
    public void setMemery() {
        mComputer.setMemory("16G");
    }

    @Override
    public void setHardDisk() {
        mComputer.setHardDisk("1T");
    }

    @Override
    public void setKeyboard() {
        mComputer.setKeyboard("机械键盘");
    }

    @Override
    public void setMouse() {
        mComputer.setMouse("无线鼠标");
    }

    @Override
    public Computer getComputer() {
        return mComputer;
    }
}

(4)需要一个装配人员Director

public class Director {
    private ComputerConfigBuilder mBuilder;
    //这里setBuilder是拿到具体的建造者对象
    public void setBuilder(ComputerConfigBuilder builder){
        this.mBuilder=builder;

    }
    //装配人员director通过建造者装配具体的产品过程
    public void createComputer(){
        mBuilder.setCPU();
        mBuilder.setMemery();
        mBuilder.setHardDisk();
        mBuilder.setKeyboard();
        mBuilder.setMouse();
    }
    //装配人员装配好产品电脑返回
    public Computer getComputer(){
        return mBuilder.getComputer();
    }
}

(5)调用

public class ThirdTeenActivity extends AppCompatActivity {
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_third_teen);
        Director director=new Director();//创建装机人员
        director.setBuilder(new LowConfigBuilder());//告诉装机人员的电脑配置,这里是低配版
        director.createComputer();//装机人员开始组装
       Computer computer= director.getComputer();//从装机人员获取组装好的电脑
        System.out.println("低配电脑配置:"+computer.toString());
        Log.d("aa",computer.toString());
        
        Director director1=new Director();
        director1.setBuilder(new HighConfigBuider());//高配组装
        director1.createComputer();
        Computer computer1=director1.getComputer();
        System.out.println("高配电脑配置:"+computer1.toString());
        Log.d("aa",computer1.toString());

    }
}

//结果
System.out: 低配电脑配置:Computer{CPU='i5', memory='8G', hardDisk='500G', keyboard='薄膜键盘', mouse='有线鼠标'}
aa: Computer{CPU='i5', memory='8G', hardDisk='500G', keyboard='薄膜键盘', mouse='有线鼠标'}
System.out: 高配电脑配置:Computer{CPU='i7', memory='16G', hardDisk='1T', keyboard='机械键盘', mouse='无线鼠标'}
aa: Computer{CPU='i7', memory='16G', hardDisk='1T', keyboard='机械键盘', mouse='无线鼠标'}

四:变种Builder模式
需要创建一个不可变的Person对象,这个Person可以拥有以下几个属性:名字、性别、年龄、职业、车、鞋子、衣服、钱、房子。其中名字和性别是必须有的

public class Person {
    /*名字(必须)*/
    private final String name;
    /*性别(必须)*/
    private final String gender;
    /*年龄(非必须)*/
    private final String age;
    /*鞋子(非必须)*/
    private final String shoes;
    /*衣服(非必须)*/
    private final String clothes;
    /*钱(非必须)*/
    private final String money;
    /*房子(非必须)*/
    private final String house;
    /*汽车(非必须)*/
    private final String car;
    /*职业(非必须)*/
    private final String career;

    private Person(Builder builder) {
        this.name = builder.name;
        this.gender = builder.gender;
        this.age = builder.age;
        this.shoes = builder.shoes;
        this.clothes = builder.clothes;
        this.money = builder.money;
        this.house = builder.house;
        this.car = builder.car;
        this.career = builder.career;
    }
    //静态内部类
    public static class Builder{
        private final String name;
        private final String gender;
        private String age;
        private String shoes;
        private String clothes;
        private String money;
        private String house;
        private String car;
        private String career;
        public Builder(String name,String gender) {
            this.name = name;
            this.gender = gender;
        }
        public Builder age(String age) {
            this.age = age;
            return this;
        }

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

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

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

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

        public Builder house(String house) {
            this.house = house;
            return this;
        }
        public Builder career(String career) {
            this.career = career;
            return this;
        }

        //创建一个Person类的对象
        public Person build(){
            return new Person(this);
        }
    }
//输出对象
    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", gender='" + gender + '\'' +
                ", age='" + age + '\'' +
                ", shoes='" + shoes + '\'' +
                ", clothes='" + clothes + '\'' +
                ", money='" + money + '\'' +
                ", house='" + house + '\'' +
                ", car='" + car + '\'' +
                ", career='" + career + '\'' +
                '}';
    }
}

//使用
 Person person=new Person.Builder("Rocky", "男").age("18").build();
        System.out.println("person"+person);
        
        //结果
        System.out: personPerson{name='Rocky', gender='男', age='18', shoes='null', clothes='null', money='null', house='null', car='null', career='null'}
        

这里使用Person类似于产品,Builder内部类等价于构建者
由于这个Person对象是不可变的,所以毫无疑问我们给他的所有属性都加了final修饰,当然如果没有不可变的需求也是可以不加的,
然后在Person类中定义一个内部类Builder,这个Builder内部类中的属性要和Person中的相同,并且必须有的属性要用final修饰,防止这些属性没有被赋值,其他非必须的属性不能用final,因为如果加了final,就必须对其进行初始化,这样这些非必须的属性又变成必须的。
然后内部类中定义了一个构造方法,传入必须有的属性。其他非必须的属性都通过方法设置,每个方法都返回Builder对象自身。
最后定义了一个build方法,将Builder对象传入Person的私有构造方法,最终返回一个对象。
五:Android中网络请求OKHttp3创建请求信息的Request的源码
这里运用的变种的Builder构建者模型

由于这个Request 对象是不可变的,所有属性都加了final修饰
public final class Request {
//这里定义的属性是不可更改的
  final HttpUrl url;
  final String method;
  final Headers headers;
  final @Nullable RequestBody body;
  final Object tag;

  private volatile CacheControl cacheControl; // Lazily initialized.

  Request(Builder builder) {
    this.url = builder.url;
    this.method = builder.method;
    this.headers = builder.headers.build();
    this.body = builder.body;
    this.tag = builder.tag != null ? builder.tag : this;
  }
  //这里配置的url是为了外部获取url属性值

  public HttpUrl url() {
    return url;
  }

  public String method() {
    return method;
  }

  public Headers headers() {
    return headers;
  }

  public String header(String name) {
    return headers.get(name);
  }

  public List<String> headers(String name) {
    return headers.values(name);
  }

  public @Nullable RequestBody body() {
    return body;
  }

  public Object tag() {
    return tag;
  }

  public Builder newBuilder() {
    return new Builder(this);
  }
  
//打印请求的数据
  @Override public String toString() {
    return "Request{method="
        + method
        + ", url="
        + url
        + ", tag="
        + (tag != this ? tag : null)
        + '}';
  }
   public static class Builder {
    HttpUrl url;//url链接
    String method;//请求方式get,post,head等
    Headers.Builder headers;//请求头
    RequestBody body;//请求体
    Object tag;
//默认的请求方式是get请求
    public Builder() {
      this.method = "GET";
      this.headers = new Headers.Builder();
    }

    Builder(Request request) {
      this.url = request.url;
      this.method = request.method;
      this.body = request.body;
      this.tag = request.tag;
      this.headers = request.headers.newBuilder();
    }
//构建的url
    public Builder url(HttpUrl url) {
      if (url == null) throw new NullPointerException("url == null");
      this.url = url;
      return this;
    }
    。。。。。
    //构建的请求头
     public Builder header(String name, String value) {
      headers.set(name, value);
      return this;
    }
    //get请求
     public Builder get() {
      return method("GET", null);
    }
//head请求
    public Builder head() {
      return method("HEAD", null);
    }
//post请求
    public Builder post(RequestBody body) {
      return method("POST", body);
    }
    //这里build是创建Request对象,url是必须有的
     public Request build() {
      if (url == null) throw new IllegalStateException("url == null");
      return new Request(this);
    }
    }
    }
    
    //使用
     Request mRequest=new Request.Builder()
                .get()
                .url("https://www.baidu.com")
                .build();
    

优点:我可以不必知道你的内部构造是怎样的,我可以直接使用Builder建造自己需要的客户端;代码清晰,易维护,易扩展;将构造和表示分离,降低耦合
缺点:代码也可能不清晰,不易维护(怎么说:比如你的客户端实现了很多接口,当你每当修改接口的时候,每次都要对应修改你的客户端);使用不恰当消耗内存

END:达到目标的唯一力量就是我的坚持精神。


Rocky_ruan
57 声望5 粉丝

不积跬步,无以至千里