Java 23种设计模式之构建者Builder模式
一:定义
建造者模式:指的是将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示,这样的设计模式称为建造者模式。
它是将一个复杂的对象分解为多个简单的对象,然后一步一步构建而成。它将变与不变相分离,即产品的组成部分是不变的,但每一部分是可以灵活选择的
二.Builder模式的结构
1.产品角色(Product):它是包含多个组成部件的复杂对象,由具体建造者来创建其各个零部件。
2.抽象建造者(Builder):它是一个包含创建产品各个子部件的抽象方法的接口,通常还包含一个返回产品的方法getResult().
3.具体的建造者(Concrete Builder):实现Builder接口,完成复杂产品的各个部件的具体创建方法
4.指挥者(Director):它调用建造者对象中的部件构造与装配方法完成复杂对象的创建,在指挥中不涉及具体产品的信息
聚合关系:聚合关系是一种特殊的关联关系,聚合关系强调的是整体和部分的关系,其中部分可以脱离整体而存在。比如雁群和一只大雁的关系,就是聚合关系,大雁离开雁群还是可以独立存在的。
依赖关系:依赖关系是一种很弱的关系,一般是指一个类使用另一个类,这里学生捡到钱交给警察叔叔,学生和警察叔叔就是一种依赖关系
泛化关系:泛化关系在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:达到目标的唯一力量就是我的坚持精神。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。