建造者模式
作者:访客发布时间:2023-10-24分类:程序开发学习浏览:118
一、什么是建造者模式
建造者模式(构建器模式)是一种创建型设计模式,它可以将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的展示。建造者模式可以让用户在不知道内部构建细节的情况下,更精细地控制对象的构造流程.
建造者模式的主要角色有:
- 产品(产品):要创建的复杂对象,通常由多个部件组成。
- 抽象建造者(构建商):定义了产品的创建过程和各个部件的构造方法,一般是一个接口或抽象类。
- 具体建造者(混凝土建造商):实现了抽象建造者的接口,提供具体的构造方法和返回产品的方法。
- 指挥者(导演):负责调用合适的建造者来组合产品,一般只有一个实例。
二、安卓源码中的实例
安卓开发中经常使用到建造者模式,例如警报对话框、通知、StringBuilder等类都是采用了建造者模式来创建对象。下面以警报对话框为例,分析其源码实现。
警报对话框是一个常用的对话框类,它可以显示标题、消息、图标、按钮等组件,也可以自定义布局。警报对话框的构造方法是私有的,不能直接创建对象,而是通过生成器类来构建。Builder类是警报对话框的一个静态内部类,它实现了抽象建造者的角色,提供了各种设置对话框属性的方法,例如设置标题、设置消息、设置图标、设置位置按钮等。这些方法都返回生成器对象本身,实现了链式调用。Builder类还提供了一个创建方法,用于返回一个警报对话框对象。这个方法会调用警报对话框的私有构造方法,并将生成器对象作为参数传入。在警报对话框的构造方法中,会根据生成器对象的属性来设置对话框的各个组件,并创建一个警报控制器对象来管理对话框的显示和交互。警报控制器类相当于指挥者的角色,它负责调用合适的生成器方法来组合对话框。
下面是警报对话框和生成器类的部分源码:
public class AlertDialog extends Dialog implements DialogInterface {
// 省略其他代码
// 私有构造方法
protected AlertDialog(Context context, int themeResId) {
super(context, resolveDialogTheme(context, themeResId));
mWindow.alwaysReadCloseOnTouchAttr();
mAlert = new AlertController(getContext(), this, getWindow());
}
// 静态内部类Builder
public static class Builder {
// 产品对象
private final AlertController.AlertParams P;
// 主题资源ID
private int mTheme;
// 构造方法
public Builder(Context context) {
this(context, resolveDialogTheme(context, 0));
}
// 构造方法
public Builder(Context context, int themeResId) {
P = new AlertController.AlertParams(new ContextThemeWrapper(
context, resolveDialogTheme(context, themeResId)));
mTheme = themeResId;
}
// 设置标题
public Builder setTitle(@StringRes int titleId) {
P.mTitle = P.mContext.getText(titleId);
return this;
}
// 设置标题
public Builder setTitle(CharSequence title) {
P.mTitle = title;
return this;
}
// 省略其他设置方法
// 创建对话框对象
public AlertDialog create() {
// Context has already been wrapped with the appropriate theme.
final AlertDialog dialog = new AlertDialog(P.mContext, mTheme);
P.apply(dialog.mAlert);
dialog.setCancelable(P.mCancelable);
if (P.mCancelable) {
dialog.setCanceledOnTouchOutside(true);
}
dialog.setOnCancelListener(P.mOnCancelListener);
dialog.setOnDismissListener(P.mOnDismissListener);
if (P.mOnKeyListener != null) {
dialog.setOnKeyListener(P.mOnKeyListener);
}
return dialog;
}
}
}
使用生成器类创建警报对话框对象的示例代码如下:
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("提示")
.setMessage("确定要退出吗?")
.setIcon(R.drawable.ic_launcher)
.setPositiveButton("确定", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
finish();
}
})
.setNegativeButton("取消", null)
.create()
.show();
从上面的代码可以看出,使用建造者模式可以让用户更灵活地构建对话框对象,而不需要关心对话框的内部实现细节.
三、Kotlin实现建造者模式
下面以一个电脑类为例,举例如何用kotlin实现建造者模式.
我们要根据不同的配置来构建一个电脑类的实例,希望可以自由配置电脑处理器、内存、显示器、键盘以及USB端口,从而组装出不同的Computer实例。如果使用JAVA来实现的话,最好的选择就是使用构建者模式。但是如果使用kotlin来实现的话,有一个更简单的方法,那就是使用命名参数和默认参数.
命名参数是指在调用函数时,可以通过参数名来指定参数值,而不需要按照参数顺序来传递.默认参数是指在定义函数时,可以给参数指定一个默认值,这样在调用函数时,如果没有传递该参数,就会使用默认值.利用这两个特性,我们可以直接在电脑类的主构造函数中定义所有的属性,并给它们赋予默认值.然后在创建电脑对象时,只需要传递需要修改的属性即可.这样就避免了定义一个额外的生成器类,并且代码更加简洁。
下面是电脑类的Kotlin实现:
class Computer(
val cpu: String = "Intel Core i5",
val ram: Int = 8,
val monitor: String = "Dell 24寸",
val keyboard: String = "罗技无线键盘",
val usb: Int = 4
) {
override fun toString(): String {
return "Computer(cpu='$cpu', ram=$ram, monitor='$monitor', keyboard='$keyboard', usb=$usb)"
}
}
创建电脑对象的示例代码如下:
val computer1 = Computer()
println(computer1)
val computer2 = Computer(cpu = "AMD Ryzen 7", ram = 16, monitor = "华硕 27```markdown
寸\") .build()
println(computer2)
val computer3 = Computer(keyboard = "雷柏机械键盘", usb = 6) .build()
println(computer3)
输出结果如下:
Computer(cpu='Intel Core i5', ram=8, monitor='Dell 24寸', keyboard='罗技无线键盘', usb=4)
Computer(cpu='AMD Ryzen 7', ram=16, monitor='华硕 27寸', keyboard='罗技无线键盘', usb=4)
Computer(cpu='Intel Core i5', ram=8, monitor='Dell 24寸', keyboard='雷柏机械键盘', usb=6)
从上面的代码可以看出,使用Kotlin的命名参数和默认参数,可以非常方便地实现建造者模式,而不需要定义额外的Builder类.当然,这种方法也有一些局限性,例如不能保证对象的不可变性,不能控制对象的创建顺序,不能实现复杂的构造逻辑等.因此,在实际开发中,需要根据具体的需求和场景来选择合适的方法.
四、JAVA实现建造者模式
下面以一个计算机类为例,举例如何用JAVA实现建造者模式。
我们要根据不同的配置来构建一个计算机类的实例,希望可以自由配置计算机、内存、硬盘、显卡、主板、电源等部件,从而组装出不同的Computer实例。如果使用JAVA的构造方法或者设置器方法来实现的话,会有以下几个问题:
- 如果使用构造方法,参数过多时会导致代码可读性和可维护性降低,而且无法灵活地指定某些可选参数.
- 如果使用Setter方法,对象会产生不一致的状态,而且对象是可变的,不利于保证线程安全性和封装性。
因此,使用建造者模式可以解决这些问题,让用户更方便地构建复杂对象.具体步骤如下:
- 定义一个计算机类(产品),包含各种属性,并提供一个私有的构造方法和一个静态内部类生成器。
- 定义一个建筑商类(混凝土建筑商),包含与产品类相同的属性,并提供一个公有的构造方法和各种设置属性的方法,这些方法都返回建筑商对象本身,实现链式调用。Builder类还提供了一个Build方法,用于返回一个产品对象。这个方法会调用产品类的私有构造方法,并将构建器对象作为参数传入。
- 在产品类的私有构造方法中,根据构建器对象的属性来初始化自身的属性。
下面是计算机类和生成器类的部分源码:
public class Computer {
// 必选属性
private String cpu;
private String ram;
// 可选属性
private String hardDisk;
private String keyboard;
private String mouse;
// 私有构造方法
private Computer(Builder builder) {
this.cpu = builder.cpu;
this.ram = builder.ram;
this.hardDisk = builder.hardDisk;
this.keyboard = builder.keyboard;
this.mouse = builder.mouse;
}
// 静态内部类Builder
public static class Builder {
// 必选属性
private String cpu;
private String ram;
// 可选属性
private String hardDisk;
private String keyboard;
private String mouse;
// 公有构造方法
public Builder(String cpu, String ram) {
this.cpu = cpu;
this.ram = ram;
}
// 设置硬盘
public Builder setHardDisk(String hardDisk) {
this.hardDisk = hardDisk;
return this;
}
// 设置键盘
public Builder setKeyboard(String keyboard) {
this.keyboard = keyboard;
return this;
}
// 设置鼠标
public Builder setMouse(String mouse) {
this.mouse = mouse;
return this;
}
// 返回产品对象
public Computer build() {
return new Computer(this);
}
}
}
创建计算机对象的示例代码如下:
Computer computer1 = new Computer.Builder("Intel Core i7", 16).build();
System.out.println(computer1);
Computer computer2 = new Computer.Builder("AMD Ryzen 9", 32)
.setHardDisk("Samsung SSD 1TB")
.setKeyboard("Logitech G915")
.setMouse("Logitech G502")
.build();
System.out.println(computer2);
输出结果如下:
Computer{cpu='Intel Core i7', ram=16, hardDisk='null', keyboard='null', mouse='null'}
Computer{cpu='AMD Ryzen 9', ram=32, hardDisk='Samsung SSD 1TB', keyboard='Logitech G915', mouse='Logitech G502'}
从上面的代码可以看出,使用建造者模式可以让用户更清晰地构建复杂对象,而不需要关心对象的内部实现细节.同时,使用生成器类可以保证对象的不可变性和线程安全性,以及对象创建过程的顺序性和逻辑性。
五、优缺点和使用场景
语言 | 优点 | 缺点 | 使用场景 |
---|---|---|---|
科特林 | 代码简洁,调用方便,实现灵活 | 对象可变,不能保证线程安全,不能控制创建顺序和逻辑 | 需要创建简单、灵活、可变的对象 |
爪哇 | 对象不可变,可以保证线程安全,可以控制创建顺序和逻辑 | 代码冗长,调用繁琐,实现固定 | 需要创建复杂、固定、不可变的对象 |
#kotlin的优点:
- 代码更简洁,不需要定义额外的生成器类。
- 调用更方便,可以通过命名参数来指定需要修改的属性,而不需要按照顺序来传递参数.
- 实现更灵活,可以根据需要给属性赋予默认值,也可以在主构造函数中添加逻辑判断或者初始化代码.
#kotlin的缺点:
- 对象是可变的,不能保证对象的不可变性和线程安全性.
- 不能控制对象的创建顺序,如果对象的属性之间有依赖关系,可能会导致错误或异常.
- 不能实现复杂的构造逻辑,如果对象的创建过程涉及到多个步骤或者条件判断,可能会导致代码冗长或者混乱.
#kotlin适用于以下场景:
- 需要创建的对象比较简单,没有复杂的内部结构或者依赖关系.
- 需要创建的对象的属性比较多,但是大部分都是可选的或者有默认值.
- 需要创建的对象不需要保证不可变性或者线程安全性.
#JAVA的优点:
- 对象是不可变的,可以保证对象的不可变性和线程安全性.
- 可以控制对象的创建顺序,如果对象的属性之间有依赖关系,可以通过生成器类来保证正确的构造过程。
- 可以实现复杂的构造逻辑,如果对象的创建过程涉及到多个步骤或者条件判断,可以通过生成器类来封装和隐藏这些细节。
#JAVA的缺点:
- 代码更冗长,需要定义一个额外的生成器类来封装对象的构造过程。
- 调用更繁琐,需要按照顺序来传递参数,而且不能通过参数名来指定参数值.
- 实现更固定,不能根据需要给属性赋予默认值,也不能在主构造函数中添加逻辑判断或者初始化代码.
#JAVA适用于以下场景:
- 需要创建的对象比较复杂,有复杂的内部结构或者依赖关系.
- 需要创建的对象的属性比较少,但是大部分都是必选的或者没有默认值.
- 需要创建的对象需要保证不可变性或者线程安全性.
##六、与其他相似设计模式对比
设计模式 | 相似之处 | 不同之处 | 使用场景 |
---|---|---|---|
建造者模式 | 都是创建型模式,都可以将对象的创建过程封装起来,对客户端隐藏细节 | 建造者模式有指导者这个角色,直接返回一个组装好的复杂产品,而其他创建型模式返回的是单一或相关的产品,建造者模式更关注产品的构造过程和表示,而其他创建型模式更关注产品的创建 | 建造者模式适用于创建复杂对象的情况,特别是当对象的构造过程涉及到多个步骤或者条件判断时 |
工厂方法模式 | 都是创建型模式,都可以将对象的创建过程封装起来,对客户端隐藏细节 | 工厂方法模式只关注对象的创建,而建造者模式关注对象的构造过程和表示,工厂方法模式只有一个抽象产品类,而建造者模式有多个部件类 | 工厂方法模式适用于创建单一产品的情况,建造者模式适用于创建复杂产品的情况 |
抽象工厂模式 | 都是创建型模式,都可以将对象的创建过程封装起来,对客户端隐藏细节 | 抽象工厂模式返回一系列相关的产品,这些产品位于不同的产品等级结构,构成了一个产品族,而建造者模式返回一个组装好的复杂产品,抽象工厂模式没有指导者这个角色 | 抽象工厂模式适用于创建多个产品族的情况,建造者模式适用于创建复杂产品的情况 |
原型模式 | 都是创建型模式,都可以将对象的创建过程封装起来,对客户端隐藏细节 | 原型模式通过复制一个现有的对象生成新对象,而建造者模式通过调用不同的方法生成新对象,原型模式不需要指导者和抽象建造者这两个角色 | 原型模式适用于创建重复或相似的对象的情况,建造者模式适用于创建复杂对象的情况 |
标签:模式
- 上一篇:比较了7个最佳WordPress备份插件(利弊)
- 下一篇:装饰者模式
- 程序开发学习排行
-
- 1鸿蒙HarmonyOS:Web组件网页白屏检测
- 2HTTPS协议是安全传输,为啥还要再加密?
- 3HarmonyOS鸿蒙应用开发——数据持久化Preferences
- 4记解决MaterialButton背景颜色与设置值不同
- 5鸿蒙HarmonyOS实战-ArkUI组件(RelativeContainer)
- 6鸿蒙HarmonyOS实战-ArkUI组件(Stack)
- 7[Android][NDK][Cmake]一文搞懂Android项目中的Cmake
- 8Android广播如何解决Sending non-protected broadcast问题
- 9鸿蒙HarmonyOS实战-ArkUI组件(mediaquery)
- 最近发表
-
- WooCommerce最好的WordPress常用插件下载博客插件模块的相关产品
- 羊驼机器人最好的WordPress常用插件下载博客插件模块
- IP信息记录器最好的WordPress常用插件下载博客插件模块
- Linkly for WooCommerce最好的WordPress常用插件下载博客插件模块
- 元素聚合器Forms最好的WordPress常用插件下载博客插件模块
- Promaker Chat 最好的WordPress通用插件下载 博客插件模块
- 自动更新发布日期最好的WordPress常用插件下载博客插件模块
- WordPress官方最好的获取回复WordPress常用插件下载博客插件模块
- Img to rss最好的wordpress常用插件下载博客插件模块
- WPMozo为Elementor最好的WordPress常用插件下载博客插件模块添加精简版