建造者模式(Builder)及其应用

简单来说,就是一步步创建一个对象,它对用户屏蔽了里面构建的细节,但却可以精细地控制对象的构造过程。

类UML图

Builder:可以是一个接口或者一个抽象类,主要是统一标准,便于我们使用多态而已

ConcreteBuilder:Builder的实现类,主要负责组建Product。

导演类(Director):主要负责统一指挥构建组装Product,但是它是不知道Product里面具体是怎样做的。

Product:产品类,是我们需要建造的复杂对象,可以是抽象类也可以是具体类,视对象的复杂程度而定

2) 建造者模式的应用场景,小Demo及优缺点分析


假设我们现在是手机生产商,主要负责手机的组装,手机的品牌有挺多的,有索尼,三星,小米等品牌,同一个品牌的手机的分辨率,CPU,摄像头肯能一样也可能不一样,你会怎么做呢?

有人说用抽象工厂模式?

刚开始想这样也是挺好的?

对于不同的手机品牌,我们单独有一个工厂实现子类,接着再交给工厂子类自己去实现手机。

不过后面自己想了一下,工厂模式诞生的初衷只是负责生产对象,而不必要知道生产手机的细节,而题目中要求同一个品牌的手机的分辨率,CPU,摄像头,这不就要求我们需要生产手机的细节了吗?所以使用抽象工厂模式不是最好的选择

下面我们来看一下使用Builder模式设计的UML图

下面我们一起来看一下例子代码

抽象Product类

//抽象Product类

public abstract class Phone {

protected String mCPU;

protected String mCamera;

protected String mScreen;

protected String mSystem;

public abstract void setSystem();

public void setmCPU(String cpu){

this.mCPU=cpu;

}

public void setmCamera(String camera) {

this.mCamera = camera;

}

public void setmScreen(String screen) {

this.mScreen = screen;

}

}

具体Product类

/**

  • ContreteProduct类

  • @author xujun

*/

public class SonyPhone extends Phone {

@Override

public void setSystem() {

mSystem=“Android”;

}

@Override

public String toString() {

return “SonyPhone [mCPU=” + mCPU + “, mCamera=” + mCamera

  • “, mScreen=” + mScreen + “, mSystem=” + mSystem + “]”;

}

}

抽象Builder类

/**

  • 抽象Builder类

  • @author xujun

*/

public abstract class Builder {

public abstract void builderScreen(String screen);

public abstract void buildCamera(String camrea);

public abstract void buildCpu(String cpu);

/**

  • 获得我们建造的Product对象

  • @return

*/

public abstract Phone creat();

public abstract void buildSystem();

}

Builder类实现类

public class SonyBuilder extends Builder {

SonyPhone sonyPhone;

public SonyBuilder() {

sonyPhone=new SonyPhone();

}

@Override

public void builderScreen(String screen) {

sonyPhone.setmScreen(screen);

}

@Override

public void buildCamera(String camrea) {

sonyPhone.setmCamera(camrea);

}

@Override

public void buildCpu(String cpu) {

sonyPhone.setmCPU(cpu);

}

@Override

public Phone creat() {

return sonyPhone;

}

@Override

public void buildSystem() {

sonyPhone.setSystem();

}

}

Director类

public class Director {

Builder mBuilder;

String mScreen=“1920x720”;

String mCPU=“双核”;

String mCamera=“默认品牌摄像头”;

public Director(Builder builder){

mBuilder=builder;

}

//在这个方法里面调用builder相应的方法

public void construct(String camera,String screen,String cpu){

mBuilder.buildCamera(camera);

mBuilder.builderScreen(screen);

mBuilder.buildCpu(cpu);

mBuilder.buildSystem();

}

public void construct(String camera){

this.construct(camera, mScreen, mCPU);

}

public void construct(){

this.construct(mCamera,mScreen,mCPU);

}

}

public class TestBuilder {

public static void main(String[] str){

Builder builder = new SonyBuilder();

//导演持有builder的引用

Director director = new Director(builder);

director.construct(“索尼摄像头”, “1280x720像素”, “4核因特尔CPU”);

Phone phone = builder.creat();

System.out.println(phone.toString());

director.construct(“索尼摄像头”);

Phone phone2 = builder.creat();

System.out.println(phone2.toString());

director.construct();

Phone phone3 = builder.creat();

System.out.println(phone3.toString());

}

}

运行以上测试程序,将可以看到以下的输出结果

SonyPhone [mCPU=4核因特尔CPU, mCamera=索尼摄像头, mScreen=1280x720像素, mSystem=Android]

SonyPhone [mCPU=双核, mCamera=索尼摄像头, mScreen=1920x720, mSystem=Android]

SonyPhone [mCPU=双核, mCamera=默认品牌摄像头, mScreen=1920x720, mSystem=Android]

分析与讨论

  • 看了上面的代码,你是不是觉得很烦,组装索尼手机品牌的不同型号,干嘛需要这么多类?其实这个只是表象而已,试想一下,如果有一天我们突然借了新的业务,需要组装小米手机?那我们只需要增加两个类就OK了,一个是XiaoMiPhone,另外一个是XiaoMiBuilder。

  • 那假如有一天小米又推出了新的手机,比如是小米6,配置是16核,摄像头是索尼品牌,屏幕分辨率是2560*1920,我们基本是不用修改代码的,只需要在在director 传入相应的参数就OK了

director.construct(“索尼摄像头”, “2560*1920”, “16核因特尔CPU”);

  • 有人会说这些事情,其实在Contrete类里面,自己就能完成了,根本就不需要Builder了?

其实如果Product管理的对象很少,有比较简单,确实是不需要Builder的,但我们Product里面需要管理的对象比较多,有比较复杂的话,如果把代码全部封装到Product里面,那岂不是破坏了Product的封装性,违背了单一责则的基本原则。

综上所述,建造者模式的 优点可概括如下

  • 建造者模式的封装性很好。使用建造者模式可以有效的封装变化,在使用建造者模式的场景中,一般产品类和建造者类是比较稳定的,因此,将主要的业务逻辑封装在导演类中对整体而言可以取得比较好的稳定性。

  • 在建造者模式中,客户端不必知道产品内部组成的细节,将产品本身与产品的创建过程解耦,使得相同的创建过程可以创建不同的产品对象。

  • 可以更加精细地控制产品的创建过程 。将复杂产品的创建步骤分解在不同的方法中,使得创建过程更加清晰,也更方便使用程序来控制创建过程。

  • 其次,建造者模式很容易进行扩展。如果有新的需求,通过实现一个新的建造者类就可以完成,基本上不用修改之前已经测试通过的代码,因此也就不会对原有功能引入风险。符合开闭原则。

在实际中的引用

其实在实际项目开发中,我们往往用不到上面的标准的Builder模式,因为我们的对象往往没有那么复杂,假如我们现在手机生产商只复制生产索尼手机,那Builder设计的UML图可以简略如下,去除Director。改为下面的链式调用。

SonyPhone phone=new SonyBuilder().buildCamera(“索尼摄像机”).buildCPU(“8核”).buildScreen(“1280*720”);

缺点

建造者模式所创建的产品一般具有较多的共同点,其组成部分相似,如果产品之间的差异性很大,则不适合使用建造者模式,因此其使用范围受到一定的限制。

适用场景

  • 产品对象内部具有复杂的结构,产品对象包含多个成员属性,适用建造者模式可以隔离复杂对象的创建和适用,并使得相同的 创建过程可以创建不同的对象;

  • 相同的方法,不同的执行顺序,产生不同的事件结果时;


3)Builder在Android中源码的体现。


还记得我们平时在使用Dialog的时候的这种用法吗?

new AlertDialog.Builder(this).setCancelable(true)

.setIcon(R.mipmap.app_logo).setMessage(“温馨提醒”).show();

哈哈,你是不是惊喜的发现这与我们上面简化的Builder模式几乎是一样的?没错,其实AlertDialog里面也使用了Builder模式

下面我们一起来看一下AlertDialog的源码

// AlertDialog

public class AlertDialog extends Dialog implements DialogInterface {

// Controller, 接受Builder成员变量P中的各个参数

private AlertController mAlert;

// 构造函数

protected AlertDialog(Context context, int theme) {

this(context, theme, true);

}

// 4 : 构造AlertDialog

AlertDialog(Context context, int theme, boolean createContextWrapper) {

super(context, resolveDialogTheme(context, theme), createContextWrapper);

mWindow.alwaysReadCloseOnTouchAttr();

mAlert = new AlertController(getContext(), this, getWindow());

}

// 实际上调用的是mAlert的setTitle方法

@Override

public void setTitle(CharSequence title) {

super.setTitle(title);

mAlert.setTitle(title);

}

// 实际上调用的是mAlert的setCustomTitle方法

public void setCustomTitle(View customTitleView) {

mAlert.setCustomTitle(customTitleView);

}

public void setMessage(CharSequence message) {

mAlert.setMessage(message);

}

// AlertDialog其他的代码省略

// ************ Builder为AlertDialog的内部类 *******************

public static class Builder {

// 1 : 存储AlertDialog的各个参数, 例如title, message, icon等.

private final AlertController.AlertParams P;

// 属性省略

public Builder(Context context) {

this(context, resolveDialogTheme(context, 0));

}

public Builder(Context context, int theme) {

P = new AlertController.AlertParams(new ContextThemeWrapper(

context, resolveDialogTheme(context, theme)));

mTheme = theme;

}

// Builder的其他代码省略 …

最后

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助

因此我收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点!不论你是刚入门Android开发的新手,还是希望在技术上不断提升的资深开发者,这些资料都将为你打开新的学习之门

如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
// Builder的其他代码省略 …

最后

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助

因此我收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

[外链图片转存中…(img-z8y4CB5m-1715903763402)]

[外链图片转存中…(img-GisJvtbk-1715903763403)]

[外链图片转存中…(img-juRRIuBG-1715903763404)]

[外链图片转存中…(img-JCzYUkMP-1715903763405)]

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点!不论你是刚入门Android开发的新手,还是希望在技术上不断提升的资深开发者,这些资料都将为你打开新的学习之门

如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值