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”);
缺点
建造者模式所创建的产品一般具有较多的共同点,其组成部分相似,如果产品之间的差异性很大,则不适合使用建造者模式,因此其使用范围受到一定的限制。
适用场景
-
产品对象内部具有复杂的结构,产品对象包含多个成员属性,适用建造者模式可以隔离复杂对象的创建和适用,并使得相同的 创建过程可以创建不同的对象;
-
相同的方法,不同的执行顺序,产生不同的事件结果时;
还记得我们平时在使用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的其他代码省略 …
// 2 : 设置各种参数
public Builder setTitle(CharSequence title) {
P.mTitle = title;
return this;
}
public Builder setMessage(CharSequence message) {
P.mMessage = message;
return this;
}
public Builder setIcon(int iconId) {
P.mIconId = iconId;
return this;
}
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数初中级安卓工程师,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年最新Android移动开发全套学习资料》送给大家,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频
如果你觉得这些内容对你有帮助,可以添加下面V无偿领取!(备注Android)
最后
给大家送上我成功跳槽复习中所整理的资料,由于文章篇幅有限,所以只是把题目列出来了,我自己手头上整理的资料均和上面的答案可免费分享,需要这些资料和答案的朋友,可以点击这里免费领取。
710699462527)]
[外链图片转存中…(img-R82YifOa-1710699462527)]
[外链图片转存中…(img-1ZCXFTJP-1710699462528)]
[外链图片转存中…(img-JZa0xFzq-1710699462529)]
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频
如果你觉得这些内容对你有帮助,可以添加下面V无偿领取!(备注Android)
[外链图片转存中…(img-SEkE8g5n-1710699462529)]
最后
给大家送上我成功跳槽复习中所整理的资料,由于文章篇幅有限,所以只是把题目列出来了,我自己手头上整理的资料均和上面的答案可免费分享,需要这些资料和答案的朋友,可以点击这里免费领取。
[外链图片转存中…(img-e9iGOsDG-1710699462530)]
[外链图片转存中…(img-ATVRoE7M-1710699462530)]