相关阅读:
JAVA编程思想(一)通过依赖注入增加扩展性
JAVA编程思想(二)如何面向接口编程
JAVA编程思想(三)去掉别扭的if,自注册策略模式优雅满足开闭原则
JAVA基础(三)ClassLoader实现热加载
HikariPool源码(二)设计思想借鉴
人在职场(一)IT大厂生存法则Builder模式,工厂模式,new都可以用于创建对象实例,它们三者的应用场景和区别如下:
创建方式 | 应用场景 |
---|---|
new | 创建逻辑简单,没有影响实例生成的参数或条件 |
工厂模式 | 根据参数或条件生成不同实例 |
Builder模式 | 创建实例时可以设置不同的参数组合,每种组合可以表现不同的行为 |
在选择以上三种方式创建对象时,不要考虑A方式能不能替代B方式,因为如果它们只是替代关系,那就没有体现它们各自的价值,只有当一个事物有不可替代性时,才有其价值,所以应该考虑的是:我是不是不得不选择它。
如果A,B互相可替代,那么就使用最简单的方式,比如new能搞定,就不要硬整一个工厂模式,不要为了用模式而用模式。
如在 JAVA编程思想(三)去掉别扭的if,自注册策略模式优雅满足开闭原则 中的例子,税策略工厂根据不同的税类型生成了不同的税策略实例去算税。
在这种场景下用new创建实例是不合适的,不得不使用工厂模式来创建实例。
Builder模式创建实例时可以使用不同的参数,使得最后创建的实例有不同的行为,举个例子,IPhone有时针对不同的颜色区分不同的具体机型参数,例如(举例用,不是完全和实际一致):
颜色 | 摄像头个数 | MAX版 | 内存 |
---|---|---|---|
红色 | 2,3个摄像头可选 | 普通版和MAX版 | 256G和512G |
黑色 | 仅有2个摄像头 | 普通版 | 128G,256G和512G |
此时用工厂模式就不合适,因为组合参数有很多种,每种组合都写一个创建方法很冗余,更好的处理方式是在创建实例时可以设置参数,由调用者自行设置需要的参数。
下面举例说明。
public enum Color { RED, BLACK } public enum Model { NORMAL, MAX } public enum CameraNum { TWO, THREE } public enum MemorySize { G128, G256, G512 } 复制代码
public class IPhone { private Color color; private Model model; private CameraNum cameraNum; private MemorySize memorySize; public IPhone(Color color, Model model, CameraNum cameraNum, MemorySize memorySize) { this.color = color; this.model = model; this.cameraNum = cameraNum; this.memorySize = memorySize; } // 1.独立的创建者,职责更清晰。2. 作为内部类,功能更内聚 3.不需要访问IPhone的成员变量-【静态】内部类 public static final class Builder { private Color color; private Model model; private CameraNum cameraNum; private MemorySize memorySize; public Builder setColor(Color color) { this.color = color; return this; } public Builder setModel(Model model) { this.model = model; return this; } public Builder setCameraNum(CameraNum cameraNum) { this.cameraNum = cameraNum; return this; } public Builder setMemorySize(MemorySize memorySize) { this.memorySize = memorySize; return this; } public IPhone build() { IPhone iPhone = new IPhone(this.color, this.model, this.cameraNum, this.memorySize); return iPhone; } } @Override public String toString() { StringBuilder builder = new StringBuilder(); builder.append("color=").append(color.toString()).append(", "); builder.append("model=").append(model.toString()).append(", "); builder.append("cameraNum=").append(cameraNum.toString()).append(", "); builder.append("memorySize=").append(memorySize.toString()); return builder.toString(); } } 复制代码
public class BuilderDemo { public static void main(String[] args) { IPhone.Builder builder = new IPhone.Builder(); // 红色 IPhone redPhone = builder.setColor(Color.RED) .setCameraNum(CameraNum.THREE) .setMemorySize(MemorySize.G512) .setModel(Model.MAX).build(); // 黑色 IPhone blackPhone = builder.setColor(Color.BLACK) .setCameraNum(CameraNum.THREE) .setMemorySize(MemorySize.G128) .setModel(Model.NORMAL).build(); System.out.println(redPhone); System.out.println(blackPhone); } } 复制代码
输出结果:
color=RED, model=MAX, cameraNum=THREE, memorySize=G512 color=BLACK, model=NORMAL, cameraNum=THREE, memorySize=G128 复制代码
至此,创建者模式完成,一般的创建者设计模式举例,包括大厂的代码(例如Android中的JobInfo.Builder)也就到此为止了,但不知细心的读者是否发现了例子中存在的问题?
例子中的错误为:创建了一个错误的黑色IPhone,按照前面表格说明,并没有3个摄像头的黑色IPhone,但却创建了一个这样的黑色IPhone。
这种错误的解决方式有:
下面,我们就通过第4种方式在早期避免犯错。
// 用于红色IPhone,限定内存范围 public enum RedMemorySize { G256 { @Override public MemorySize getMemorySize() { return MemorySize.G256; } }, G512 { @Override public MemorySize getMemorySize() { return MemorySize.G512; } }; public abstract MemorySize getMemorySize(); } 复制代码
public class IPhone { // 成员定义不变 private Color color; private Model model; private CameraNum cameraNum; private MemorySize memorySize; // 构造器不变 public IPhone(Color color, Model model, CameraNum cameraNum, MemorySize memorySize) { this.color = color; this.model = model; this.cameraNum = cameraNum; this.memorySize = memorySize; } // 黑色IPhone Builder public static final class BlackBuilder { private MemorySize memorySize; // 其他参数没得选,只需保留此方法 public BlackBuilder setMemorySize(MemorySize memorySize) { this.memorySize = memorySize; return this; } public IPhone build() { // 限定的参数直接传入 IPhone iPhone = new IPhone(Color.BLACK, Model.NORMAL, CameraNum.TWO, this.memorySize); return iPhone; } } // 红色IPhone Builder public static final class RedBuilder { private Model model; private CameraNum cameraNum; private MemorySize memorySize; public RedBuilder setModel(Model model) { this.model = model; return this; } public RedBuilder setCameraNum(CameraNum cameraNum) { this.cameraNum = cameraNum; return this; } // 注意这里入参是RedMemorySize,用于限定内存范围只能是256G和512G public RedBuilder setMemorySize(RedMemorySize memorySize) { this.memorySize = memorySize.getMemorySize(); return this; } public IPhone build() { // 限定的参数直接传入 IPhone iPhone = new IPhone(Color.RED, this.model, this.cameraNum, this.memorySize); return iPhone; } } @Override public String toString() { StringBuilder builder = new StringBuilder(); builder.append("color=").append(color.toString()).append(", "); builder.append("model=").append(model.toString()).append(", "); builder.append("cameraNum=").append(cameraNum.toString()).append(", "); builder.append("memorySize=").append(memorySize.toString()); return builder.toString(); } } 复制代码
public class BuilderDemo { public static void main(String[] args) { // 红色专有Builder,在开发时即可避免创建错误对象 IPhone.RedBuilder redBuilder = new IPhone.RedBuilder(); IPhone redPhone = redBuilder.setCameraNum(CameraNum.THREE) .setMemorySize(RedMemorySize.G512) .setModel(Model.MAX).build(); // 黑色专有Builder,在开发时即可避免创建错误对象 IPhone.BlackBuilder blackBuilder = new IPhone.BlackBuilder(); IPhone blackPhone = blackBuilder.setMemorySize(MemorySize.G128).build(); System.out.println(redPhone); System.out.println(blackPhone); } } 复制代码
输出:
color=RED, model=MAX, cameraNum=THREE, memorySize=G512 color=BLACK, model=NORMAL, cameraNum=TWO, memorySize=G128 复制代码
可以看到,这时创建的黑色IPhone是正确的。
至此,我们可以总结出创建者模式的经典范式: