建造者模式(Builder Pattern)

23种软件设计模式完整教程

介绍

将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。建造者模式是一种对象创建型模式。对比现实世界,类似于:

       要造一台计算机主机,需要CPU、内存卡、显卡、电源等。组装过程也相对复杂,比如一些接线的处理。
       要造一辆汽车,需要底盘、方向盘、发动机、座椅、轮子等等。
       要造航空母舰,需要甲板、起飞装置、机库、动力系统、武器库等。

意图:

把复杂的对象创建过程进行剥离,尤其是内部部件的配置,进行独立变化和维护。

何时使用:

复杂对象的构建和实现分离,比如客户端的对话框的构建。

多参数方法的改良,如果一个对象的创建需要多个可选参数,而且参数还会变化和扩展,应用建造者模式可以让代码简洁,易与扩展与编写。

优点:

屏蔽细节:使用者不需要完全了解建造细节。

易于扩展:不同的建造者相互独立,新的产品可以创建新的建造者。

缺点:

局限性:产品组成部分必须大部分相同。

类膨胀:如果产品数量过多,也会导致建造者的数量膨胀。

使用场景:

       JDK:Locale
       JDK:StringBuilder
       Gson:GsonBuilder
       OkHttp:OkHttpClient.Builder

注意事项:

多个产品差异很大的情况下,不推荐使用建造者。

只有一种产品时,可以使用无抽象建造者,指挥者和建造者在一个类里面实现。

与抽象工厂的区别:

建造者模式返回一个完整产品,抽象工厂返回一套产品(一个产品族)。

建造者模式侧重构造和组建复杂产品,工厂模式侧重生产不同类型的产品。

 

代码实现

(实现一)有抽象建造者

主要角色有:

       抽象建造者(Abstract Builder),声明需要的部件。
       具体建造者(Concrete Builder),定义明确的部件。
       指挥者(Director),指挥组装过程。
       产品(Product),产品,由多个部件组成。

类图:

package com.knowledge.system.software_design_pattern.builder_pattern.myself_instance2;

public class Product {
    private String partA;
    private String partB;
    private String partC;

    public String getPartA() {
        return partA;
    }

    public void setPartA(String partA) {
        this.partA = partA;
    }

    public String getPartB() {
        return partB;
    }

    public void setPartB(String partB) {
        this.partB = partB;
    }

    public String getPartC() {
        return partC;
    }

    public void setPartC(String partC) {
        this.partC = partC;
    }

    @Override
    public String toString() {
        return "Product{" +
                "partA='" + partA + '\'' +
                ", partB='" + partB + '\'' +
                ", partC='" + partC + '\'' +
                '}';
    }
}

抽象建造者: 

package com.knowledge.system.software_design_pattern.builder_pattern.myself_instance2;

public interface IBuilder {
    void buildA();
    void buildB();
    void buildC();
    Product getResult();
}

 具体建造者:

package com.knowledge.system.software_design_pattern.builder_pattern.myself_instance2;

public class BuilderA implements IBuilder {

    private Product product;

    public BuilderA() {
        this.product = new Product();
    }

    @Override
    public void buildA() {
        product.setPartA("A1");
    }

    @Override
    public void buildB() {
        product.setPartA("A2");
    }

    @Override
    public void buildC() {
        product.setPartA("A3");
    }

    @Override
    public Product getResult() {
        return product;
    }
}

 指挥者:

package com.knowledge.system.software_design_pattern.builder_pattern.myself_instance2;

public abstract class Director implements IBuilder {
    private IBuilder builder;

    public Director(IBuilder builder) {
        this.builder = builder;
    }

    public Product construct(){
        builder.buildA();
        builder.buildB();
        builder.buildC();
        return builder.getResult();
    }
}

 使用示例:

package com.knowledge.system.software_design_pattern.builder_pattern.myself_instance2;

import com.alibaba.fastjson.JSON;

public class Test {
    public static void main(String[] args) {

        IBuilder builder=new BuilderA();
        Director director=new Director(builder);
        Product product=director.construct();

        System.out.println(JSON.toJSON(product));
    }
}

(实现二)无抽象建造者

实现上去掉抽象接口,具体实现省略。

 

有无抽象创建者的选择方法:

有抽象创建者:

产品由多个部件组成,不同部件可以更换,不同部件的配置和更换为新的产品。部件之间存在复杂的依赖关系。创建过程中还依赖到外部环境的对象。

无抽象创建者:

产品由多个部件组成。部件之间的依赖关系简单。创建过程中不需要依赖外部环境。

 

其他使用案例:(实际研发中使用到的场景)

1. 复杂对象构建举例

一个对话框由多个部件组成,比如标题栏、内容、确定按钮、取消按钮等等。有的页面需要标题栏,有的页面不需要,有的页面需要确定按钮,有的不需要,这些都通过 Builder 来构建这个复杂的对话框。

CommonAlertDialogFragment builder = new CommonAlertDialogFragment.Builder(getActivity())
	.setMessage(xxxx)
	.setCancelable(true)
	.setNegativeButtonText(xxx, null)
	.setPositiveButtonText(xxx, null)
	.setOnDismissListener(new OnDismissListener() {
		@Override
		public void onDismiss() {
			...
        }
	});
CommonAlertDialogFragment dialog = builder.create()

2.多参数方法改良举例

在方法参数类型较多的时候,我们会使用方法多态,但这样会造成构造方法数量膨胀。

假设我们现在要设计一个下载器,有这么一些配置:

必选项
        下载的 url 地址
        下载后的文件的保存地址
可选项
        是否支持多线程,默认不支持
        是否支持文件覆盖,默认可以
        下载失败重试次数,默认10次

如果直接用方法多态的方式,如果想要尽可能地覆盖这些条件的组合所有的情况,需要很多的重载方法,于是有这样的代码:

void downloadFile(String url, String savePath);
void downloadFile(String url, String savePath, boolean multiThread);
void downlaodFile(String url, String savePath, boolean multiThread, boolean overwrite);
void downloadFile(String url, String savePath, boolean multiThread, boolean overwrite, int retryNum);
void downloadFile(String url, String savePath, int retryNum);
...

后续增减参数类型,都会修改到这些构造方法,不符合开闭原则。

所以,我们用建造者模式来改善它:

public static class Builder {
	private String url;
	private String savePath;
	private int retryNum = 0;
	private boolean multiThread = false;
	private boolean overwrite = true;

	public Builder(String url, String savePath) {
		this.url = url;
		this.savePath = savePath;
	}

	public Builder addRetryNum(int retryNum) {
		this.retryNum = retryNum;
		return this;
	}

	public Builder addMultiThread(boolean multiThread) {
		this.multiThread = multiThread;
		return this;
	}

	public Builder addOverwrite(boolean overwrite) {
		this.overwrite = overwrite;
		return this;
	}

	public DownloadParams build() {
		return new DownloadParams(url, savePath, retryNum, callBack, multiThread, overwrite, sync);
	}
}

3. JDK:Locale

 Locale aLocale = new Builder()
 	.setLanguage("sr")
 	.setScript("Latn")
 	.setRegion("RS")
 	.build();

4. JDK:StringBuilder

String str = (new StringBuilder())
	.append(1)
	.append(1.2f)
	.append("Hello World!")
	.toString();

5. Gson:GsonBuilder

GsonBuilder buider = new GsonBuilder().
	.registerTypeAdapter(MediaBean.class, new MediaBeanDeserializer())
	.registerTypeAdapter(UserBean.class, new UserBeanDeserializer())
	.registerTypeAdapter(LiveBean.class, new LiveBeanDeserializer());
Gson gson = builder.create();

6. OkHttp:OkHttpClient.Builder

OkHttpClient.Builder builder = new OkHttpClient.Builder()
	.connectTimeout(20, TimeUnit.MILLISECONDS)
	.readTimeout(60, TimeUnit.MILLISECONDS)
	.writeTimeout(60, TimeUnit.MILLISECONDS)
	.followRedirects(true);
	.followSslRedirects(true);
	.retryOnConnectionFailure(true);
OkHttpClient okHttpClient = builder.build();

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值