序言
在看Retrofit源码时,可以看到里面用到了大量的设计模式,如果我们非常了解设计模式对理解是很有帮助的,在Rerofit里有用到建造者模式。
定义
将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以生成不同的表示。建造者模式也是对象创建行模式。
说明: 单看这个定义初学者也是很蒙, 大概意思是不需要关心复杂对象创建过程,只需要知道建造者类型即可,建造者才关心这个复杂对象是如何一步一步创建一个复杂对象的。 根据不同类型的建造者生成不同的复杂的对象。也是有具有良好的扩展性。
建造者模式类图
在建造者模式中包含如下几个角色:
- Builder(抽象的建造者) : 它是创建Product对象各个部分的抽象接口。 在该接口一般有两类接口 ,一种是biuldPartX()方法,用于创建该复杂对象各个部分; 另一种方法是getResult, 它用于返回这个复杂对象。 Build可以是一个接口,也可以是抽象类。
- ConcreteBuilder(具体的建造者): 它实现了Builder接口,具体实现该复杂对象的各个部分,然后返回具体的复杂对象。
- Product(产品角色): 它是复杂对象,里面包含该对象有哪些部分组成。
- Director(指挥者):它负责对象的建造次序。指挥者和抽象的建造者存在关联关系,可以在construct中完成复杂对象的创建过程。
上面有提到复杂对象,那什么是复杂对象呢,简单来说就是包含多个成员属性的对象。代码示例如下:
//产品
class Product{
private String partA;//定义产品的属性,属性可以是其它类型, 值类型和引用类型都行。
private String partB;
private String partC;
//Setter和Getter方法省略就不写了
}
在抽象建造者定义产品的创建方法和获取产品对象的方法。代码示例如下:
//抽象建造者
interface Builder{
void buildPartA();//创建产品的属性
void buildPartB();
void buildPartC();
Product getResult(); //返回产品对象
}
抽象建造者中申明了一系列的buildPartX()方法,但是具体的实现还是需要具体的建造者。 不同的建造者实现的buildPartX有所区别。代码示例如下:
//具体的建造者 A
public class AConcreteBuilder implements Builder {
Product productA=new Product();
@Override
public void buildPartA() {
productA.setPartA("PartA from AConcreteBuilder");
}
@Override
public void buildPartB() {
productA.setPartA("PartB from AConcreteBuilder");
}
@Override
public void buildPartC() {
productA.setPartA("PartC from AConcreteBuilder");
}
@Override
public Product getResult() {
return productA;
}
}
//具体的建造者 B
public class BConcreteBuilder implements Build {
Product productB=new Product();
@Override
public void buildPartA() {
productB.setPartA("PartA from BConcreteBuilder");
}
@Override
public void buildPartB() {
productB.setPartA("PartB from BConcreteBuilder");
}
@Override
public void buildPartC() {
productB.setPartA("PartC from BConcreteBuilder");
}
@Override
public Product getResult() {
return productB;
}
}
我们可以看到每个建造者实现的东西是不同的。但是返回的产品还是一类的,只是产品的属性不一样。
在建造者模式还有个Director角色(导演者或指挥者),该类主要有两个作用: 其一就是控制产品的创建过程,包括biuldPartX方法是否被调用以及调用的顺序; 其二 就是隔离了客户与创建的过程, Director只需要指挥抽象的建造者(Build),客户端需要具体的建造者然后调用指挥者的相关方法,返回一个完整的对象(Product)。 代码示例如下
//指挥者
public class Director {
private Builder mBuilder; //抽象的建造者
public Director(Builder build) {
this.mBuilder = build;
}
public Product construct(){
mBuilder.buildPartA();
mBuilder.buildPartB();
mBuilder.buildPartC();
return mBuilder.getResult();
}
}
//客户端 代码片段如下
Builder Abuilder=new AConcreteBuilder();//创建具体的建造者
Director director=new Director(Abuilder);//创建指挥者
Product productA=director.construct();//返回产品A
Builder Bbuilder=new BConcreteBuilder();//创建具体的建造者
Director director=new Director(Bbuilder);//创建指挥者
Product productA=director.construct();//返回产品B
例子
如某个公司要开发个APP(Product),就需要开发者(Builder), 如果有多端的话就需要不同的开发者(ConcreteBuilder),技术经理(Director)就充当指挥者来指示不同的开发者来开发。
APP (Product)
public class APP {
String code;//代码
String note;//注释及文档
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public String getNote() {
return note;
}
public void setNote(String note) {
this.note = note;
}
@Override
public String toString() {
return "APP = {" +
"code='" + code + '\'' +
", note='" + note + '\'' +
'}';
}
}
开发者 (Builder)
public interface Developer {
void writeCode();//写代码
void writeNote();//写文档及注释
APP getAPP();//返回APP
}
Andoird开发者(ConcreteBuilder)
public class AndroidDeveloper implements Developer {
APP app = new APP();
@Override
public void writeCode() {
app.setCode("Android code");
}
@Override
public void writeNote() {
app.setNote("Android note ");
}
@Override
public APP getAPP() {
return app;
}
}
技术经理 (指挥者)
public class TechnicalManager {
Developer mDeveloper;
public void setDeveloper(Developer mDeveloper) {
this.mDeveloper = mDeveloper;
}
public APP getAPP() {
mDeveloper.writeCode();
mDeveloper.writeNote();
return mDeveloper.getAPP();
}
}
测试:
public static void main(String[] args) {
TechnicalManager manager = new TechnicalManager();//创建技术经理对象(指挥者)
AndroidDeveloper javaDeveloper = new AndroidDeveloper();//创建Android开发者(具体的建造者)
manager.setDeveloper(javaDeveloper);//技术经理指挥Android程序员去干活
APP app = manager.getAPP(); //完成 Android端 APP
System.out.println(app);
}
运行结果:
APP = {code='Android code', note='Android note'}
如果公司想在苹果商店也要上款APP,那就需要ios开发,这样我们就不用修改源代码,只需要另创建一个ios的建造者就OK。
ios 开发者(ConcreteBuilder)
public class IosDeveloper implements Developer {
APP app = new APP();
@Override
public void writeCode() {
app.setCode("ios code");
}
@Override
public void writeNote() {
app.setNote("ios note");
}
@Override
public APP getAPP() {
return app;
}
}
测试:
public static void main(String[] args) {
TechnicalManager manager = new TechnicalManager();//创建技术经理对象(指挥者)
IosDeveloper iosDeveloper = new IosDeveloper();//创建ios开发者(具体的建造者)
manager.setDeveloper(iosDeveloper);//技术经理指挥ios程序员去干活
APP app = manager.getAPP(); //完成 ios端 APP
System.out.println(app);
}
运行结果:
APP {code='ios code', note='ios note'}
如果需要其他端的APP,只需另创建个建造者就可以完成APP。
但是我们看大多数的源码,里面的建造者模式是没有指挥者的(Director),这个又是怎样实现的呢。 在Android中的弹框(dialog)的实现就用了建造者模式,我们就大致实现下它是怎么创建的。 源码中还是很复杂的,这里只是简单实现。
在Android中创建一个dialog的代码
AlertDialog.Builder builder = new AlertDialog.Builder(this)
.setTitle("提示")
.setMessage("消息")
.setIcon(R.drawable.icon);
AlertDialog alertDialog=builder.create();
这是Android创建dialog最简单的方式。 现在我们就实现这样的写法。
// Product
public class AlertDialog{
String msg;//消息
String tilte;//标题
int icon; //图标
@Override
public String toString() {
return "AlertDialog{" +
"msg='" + msg + '\'' +
", tilte='" + tilte + '\'' +
", icon=" + icon +
'}';
}
//建造者 (Builder)
static class Builder{
private AlertDialog mDialog=new AlertDialog();
public Builder setIcon(int icon){
mDialog.icon=icon;
return this;
}
public Builder setTitle(String title){
mDialog.tilte=title;
return this;
}
public Builder setMsg(String msg){
mDialog.msg=msg;
return this;
}
public AlertDialog create(){
return mDialog;
}
}
}
测试 :
public static void main(String args[]) {
//因为Builder是AlertDialog的成员内部类,所以这样调用AlertDialog.Builder
AlertDialog.Builder builder = new AlertDialog.Builder();
builder.setIcon(1)
.setMsg("消息")
.setTitle("提示");
AlertDialog dialog = builder.create();
System.out.println(dialog);
}
运行结果:
AlertDialog{msg='消息', tilte='提示', icon=1}
可以看到我们也按照Android源码这样的调用方法创建了自己的dialog。 Android中的dialog实现比我这复杂,dialog属性更多,逻辑更复杂。
我们可以再看看Retrofit中使用的建造者模式
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(API_URL)
.addConverterFactory(GsonConverterFactory.create())
.build();
这是创建Retrofit对象。可以看到也是用了建造者模式。 这里就不说了,下次分析源码时再说。
总结:建造者模式只要明白四个角色Product、Builder、ConcreteBuilder、Director的作用,就差不多明白建造者模式是怎么回事了。
优点:
- 将产品的本身与产品的创建过程解耦,使得相同的创建过程可以创建不同的产品对象。
- 每一个具体建造者都是相对独立的,不依赖其他的具体建造者,可以方便地替换和增加新的具体建造者,用户使用不同的具体建造者就能得到不同的产品对象。 由于指挥者(Director)是针对抽象的建造者(Builder)编程,增加新的建造者无需修改原来的建造者,符合‘开闭原则’。
缺点:
- 所创建的产品具有较多的共同点,其组成部分相似。 如果产品之间的差异性很大的话,就不适用建造者模式。
- 产品的内部变化复杂的话,可能会导致定义很多的具体建造者来应对这样的变化,这样会导致系统的复杂性。