设计模式之建造者模式

序言

在看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)编程,增加新的建造者无需修改原来的建造者,符合‘开闭原则’。

缺点:

  • 所创建的产品具有较多的共同点,其组成部分相似。 如果产品之间的差异性很大的话,就不适用建造者模式。
  • 产品的内部变化复杂的话,可能会导致定义很多的具体建造者来应对这样的变化,这样会导致系统的复杂性。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值