23种设计模式之Builder模式
来源:互联网 发布:淘宝蛋糕店 编辑:程序博客网 时间:2024/06/06 01:54
Builder定义:将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
Builder使用场景:
- 相同的方法,不同的执行顺序,产生不同的事件结果时
- 多个部件或零件,都可以装配到一个对象中,但是产生的运行结果又不相同时
- 产品类非常复杂,或者产品类中的调用顺序不同产生了不同的作用,这个时候使用建造者模式非常合适
- 当初始化一个对象特别复杂,如参数多,且很多参数都具备默认值时
Builder的简单应用
大家考虑一下这种场景,假如有一个类(Computer),里面有很多属性,就像下面的代码:
//计算机的抽象类,即Product角色public class Computer { private String mModel; //型号 (必传参数) private int mMemory; //内存 (必传参数) private int mGraphics; //显卡 (不必传参数) private String mBoard; //主机 (不必传参数) private String mDisplay; //显示器 (不必传参数) private String mProcessor; //处理器 (不必传参数)}
在这个类中,有些参数是必要的,而有些参数是非必要的。就好比在买电脑的时候,只需要知道型号,内存等些重要的信息,其他的信息可以关注也可以不关注的时候,那么问题就来了,如何创建这个类的对象呢?
一种可行的方案就是实用构造方法。第一个构造方法只包含两个必需的参数,第二个构造方法中,增加一个可选参数,第三个构造方法中再增加一个可选参数,依次类推,直到构造方法中包含了所有的参数,也就是构造方法的重构:
public Computer(String mModel, int mMemory) { this.mModel = mModel; this.mMemory = mMemory; } public Computer(String mModel, int mMemory, int mGraphics) { this.mModel = mModel; this.mMemory = mMemory; this.mGraphics = mGraphics; } public Computer(String mModel, int mMemory, int mGraphics, String mBoard) { this.mModel = mModel; this.mMemory = mMemory; this.mGraphics = mGraphics; this.mBoard = mBoard; } public Computer(String mModel, int mMemory, int mGraphics, String mBoard, String mDisplay) { this.mModel = mModel; this.mMemory = mMemory; this.mGraphics = mGraphics; this.mBoard = mBoard; this.mDisplay = mDisplay; } public Computer(String mModel, int mMemory, int mGraphics, String mBoard, String mDisplay, String mProcessor) { this.mModel = mModel; this.mMemory = mMemory; this.mGraphics = mGraphics; this.mBoard = mBoard; this.mDisplay = mDisplay; this.mProcessor = mProcessor; }
这种做法可以实现,但是大家试想,如果参数多了怎么办?可读性不好,且代码维护成本高。而且对调用者来说也比较的麻烦,还要传入不需要参数的默认值,搞不好还会出错。
第二种解决办法就出现了,我们同样可以根据JavaBean的习惯,设置一个空参数的构造方法,然后为每一个属性设置setters和getters方法。就像下面一样:
public Computer() { } public String getmModel() { return mModel; } public void setmModel(String mModel) { this.mModel = mModel; } public int getmMemory() { return mMemory; } public void setmMemory(int mMemory) { this.mMemory = mMemory; } public int getmGraphics() { return mGraphics; } public void setmGraphics(int mGraphics) { this.mGraphics = mGraphics; } public String getmBoard() { return mBoard; } ...
这种方法看起来可读性不错,而且易于维护。作为调用者,创建一个空的对象,然后只需传入我感兴趣的参数。那么缺点呢?也很明显: 对象会产生不一致的状态。当你想要传入6个参数的时候,你必需将所有的setXX方法调用完成之后才行。然而一部分的调用者看到了这个对象后,以为这个对象已经创建完毕,就直接用了,其实User对象并没有创建完成。
说了那么多,就是为了衬托Builder的好处,它处理这种事情最合适不过
//计算机的抽象类,即Product角色public class Computer { private final String mModel; //型号 (必传参数) private final int mMemory; //内存 (必传参数) private final int mGraphics; //显卡 (不必传参数) private final String mBoard; //主机 (不必传参数) private final String mDisplay; //显示器 (不必传参数) private final String mProcessor; //处理器 (不必传参数) private Computer(ComputerBuilder builder) { this.mModel = builder.mModel; this.mMemory = builder.mMemory; this.mGraphics = builder.mGraphics; this.mBoard = builder.mBoard; this.mDisplay = builder.mDisplay; this.mProcessor = builder.mProcessor; } public String getModel() { return mModel; } public int getMemory() { return mMemory; } public int getGraphics() { return mGraphics; } public String getBoard() { return mBoard; } public String getDisplay() { return mDisplay; } public String getProcessor() { return mProcessor; } public static class ComputerBuilder { private final String mModel; //型号 private final int mMemory; //内存 private int mGraphics; //显卡 private String mBoard; //主机 private String mDisplay; //显示器 private String mProcessor; //处理器 public ComputerBuilder(String mModel, int mMemory) { this.mModel = mModel; this.mMemory = mMemory; } public ComputerBuilder graphics(int graphics) { this.mGraphics = graphics; return this; } public ComputerBuilder board(String board) { this.mBoard = board; return this; } public ComputerBuilder display(String display) { this.mDisplay = display; return this; } public ComputerBuilder processor(String processor) { this.mProcessor = processor; return this; } public Computer build() { return new Computer(this); } }}
有几个重要的地方需要说明一下:
- Computer类的构造方法是私有的。也就是说调用者不能直接创建Computer对象
- Computer类的属性都是不可变的。所有的属性都添加了final修饰符,并且在构造方法中设置了值。并且,对外只提供getter()方法。
- Builder模式使用了链式调用。可读性更佳。
- Builder的内部类构造方法中只接收必传的参数,并且该必传的参数适用了final修饰符
写了那么久了,现在怎么构建一个对象?so easy
new Computer.ComputerBuilder("ThinkPad x1",8) .graphics(4) .board("华硕") .display("高分屏") .processor("i7-4600u") .build();
传说中的链式调用有没有,是不是相当的整洁,一行代码搞定。
builder的总结
优点:
a.良好的封装性,使用建造者模式可以使客户端不必知道产品内部组成的细节
b.建造者独立,容易扩展
缺点
a.会产生多余的Builder对象以及Director对象,消耗内存。
Builder模式的自动化生成
上面的builder虽然非常棒,但是需要写的东西重复性很高,这怎么能是我们该做的事情呢?在Android Studio中,可以通过安装名为InnerBuilder的插件来简化Builder模式的创建过程,在Plugins面板中搜索builder即可找到这个插件,如图:
下载完成后,会重启Android Studio使插件生效。这里以User类代码为例,在编写时,只需把属性名确定下来,然后单击鼠标右键,打开Generate菜单,选择Builder按钮,
点击Builder,在弹出的配置中勾选相关配置,如图:
点击OK,即可自动生成Builder相关代码,生成的是普通的,咱们要根据实际情况进行少量修改即可
public class User { private final String mFirstName; // 必选 private final String mLastName; // 必选 private final String mGender; // 非必选 private final int mAge; // 非必选 private final String mPhoneNo; // 非必选 private User(Builder builder) { mFirstName = builder.mFirstName; mLastName = builder.mLastName; mGender = builder.mGender; mAge = builder.mAge; mPhoneNo = builder.mPhoneNo; } public static final class Builder { private String mFirstName; private String mLastName; private String mGender; private int mAge; private String mPhoneNo; public Builder() { } public Builder mFirstName(String val) { mFirstName = val; return this; } public Builder mLastName(String val) { mLastName = val; return this; } public Builder mGender(String val) { mGender = val; return this; } public Builder mAge(int val) { mAge = val; return this; } public Builder mPhoneNo(String val) { mPhoneNo = val; return this; } public User build() { return new User(this); } }}
到这里已经将Builder模式说的差不多了,有什么问题可以直接留言给我。
- 23种设计模式之Builder模式
- 设计模式之Builder
- 设计模式之Builder
- 设计模式之Builder
- 设计模式之Builder
- 设计模式之Builder
- 设计模式之Builder
- 设计模式之Builder
- 设计模式之Builder
- 设计模式之Builder
- 设计模式之Builder
- 设计模式之Builder
- 设计模式之Builder
- 设计模式之Builder
- 设计模式之Builder
- 设计模式之Builder
- 设计模式之 builder
- 设计模式之Builder
- ajax 在html 的操作,获取表单的所有表单内容
- 一个经典例子让你彻彻底底理解java回调机制
- 指针数组 数组指针 函数指针 函数指针数组 函数指针数组的指针
- Q3DSurface 配置使用教程
- 顶点缓存对象(VBO)
- 23种设计模式之Builder模式
- java中synchronized关键字的用法
- <<Linux内核设计与实现>>读书笔际(五)-系统调用
- static的作用
- C#--02--mysql数据库
- java Print流 和 重定向
- Java 多线程下的单例模式
- Android模块化分层化之: maven 库中上传的 aar 包 获取 BuildConfig 相关常量值
- listview去掉分割线