目录
简介
关于设计模式可以理解为,那些经常会遇到的问题以及如何解决所洗练出来的总结。所以我们在考虑进行设计时,首先要做的就是查询当前所面临的问题,是否已经有很好的解决方案,而不是闭门造车。身边有些同事喜欢需求来了,直接上来就撸代码,认为为了迎合设计模式而设计的工作,会有过度设计的嫌疑。什么时候是导入新工具,新技术的最佳时机?当一个事物让人难以忍受的时候,这时改变所带来的团队收益远大于痛苦程度,就可以很平缓地推进。反之,强推工具反而引来的不是技术上的问题,而是人为的抵制。是不是很奇妙!
本文主要通过问题配合设计模式,来说明设计模式所带来的前后效果,加深大家各种模式的印象。
如何让构造器的用途更容易理解
- 改造前
public class FooClient {
private final String url;
private final String proxyHost;
private final int proxyPort;
public FooClient(String url) {
this.url = url;
this.proxyHost = null;
this.proxyPort = -1;
}
public FooClient(String url, String proxyHost, int proxyPort) {
this.url = url;
this.proxyHost = proxyHost;
this.proxyPort = proxyPort;
}
}
new FooClient(url);
new FooClient(url, proxyHost, proxyPort);
通过参数个数来控制生成的实例是否具备代理功能
- 改造后
Factory Method
public class FooClient {
private final String url;
private final String proxyHost;
private final int proxyPort;
private FooClient(String url, String proxyHost, int proxyPort) {
this.url = url;
this.proxyHost = proxyHost;
this.proxyPort = proxyPort;
}
public static FooClient withoutProxy(String url) {
return new FooClient(url, null, -1);
}
public static FooClient withProxy(String url, String proxyHost, int proxyPort) {
return new FooClient(url, proxyHost, proxyPort);
}
}
FooClient.withoutProxy(url);
FooClient.withProxy(url, proxyHost, proxyPort);
通过Factory Method
封装让外部调用更友好
根据条件参数创建子类实例时,如何隐藏底层细节
- 改造前
public class FooDateFilter extends FooFilter {}
public class FooNumberFilter extends FooFilter {}
public class FooStringFilter extends FooFilter {}
FooFilter filter = new FooStringFilter("foo");
当条件参数为字符串时,调用方需要知道要用FooStringFilter
子类
当条件参数为数字时,调用方需要知道要用FooNumberFilter
子类
- 改造后
Factory Method
public class FooDateFilter extends FooFilter {}
public class FooNumberFilter extends FooFilter {}
public class FooStringFilter extends FooFilter {}
public class FooFilterFactory {
private FooFilterFactory() {}
public static FooFilter create(Date date) {
return new FooDateFilter(date);
}
public static FooFilter create(Number number) {
return new FooNumberFilter(number);
}
public static FooFilter create(String string) {
return new FooStringFilter(string);
}
}
FooFilter filter = FooFilterFactory.create("foo");
通过Factory Method
将子类生成实例细节隐藏,调用方不用再关心需要调用哪个子类。还有,将来如果要将某个子类(如:FooStringFilter)废弃,升级到FooStringFilter V2版本,也只需要更改FooFilterFactory文件即可。对调用方来说还是调用FooFilterFactory.create
来生成实例,从而避免因为修改某个子类,造成调用方的代码改动。
想通过1个接1个字段来配置生成实例
- 改造前
public class FooWindow {
private final int width;
private final int height;
private final FooColor color;
private final FooColor backgroundColor;
public FooWindow() {
this.width = 0;
this.height = 0;
this.color = null;
this.backgroundColor = null;
}
public FooWindow(int width, int height, FooColor color, FooColor backgroundColor) {
this.width = width;
this.height = height;
this.color = color;
this.backgroundColor = backgroundColor;
}
public FooWindow withWidth(int width) {
return new FooWindow(width, this.height, this.color, this.backgroundColor);
}
public FooWindow withHeight(int height) {
return new FooWindow(this.width, height, this.color, this.backgroundColor);
}
//color, backgroundColor同上
}
new FooWindow()
.withWidth(100)
.withHeight(200)
.withColor(color)
.withBackgroundColor(backgroundColor);
每调用一个链式方法都会生成一个新实例替代老的实例,开销较大。
- 改造后
Builder
public class FooWindow {
private final int width;
private final int height;
private final FooColor color;
private final FooColor backgroundColor;
public FooWindow(int width, int height, FooColor color, FooColor backgroundColor) {
this.width = width;
this.height = height;
this.color = color;
this.backgroundColor = backgroundColor;
}
public static class FooWindowBuilder {
private int width;
private int height;
private FooColor color;
private FooColor backgroundColor;
public FooWindowBuilder withWidth(int width) {
this.width = width;
return this;
}
public FooWindowBuilder withHeight(int height) {
this.height = height;
return this;
}
//color, backgroundColor同上
public FooWindow build() {
return new FooWindow(this.width, this.height, this.color, this.backgroundColor);
}
}
}
new FooWindowBuilder()
.withWidth(100)
.withHeight(200)
.withColor(color)
.withBackgroundColor(backgroundColor)
.build();
在给实例配置成员值时,并不像改造前
每回都生成一个新的实例。通过Builder
模式,改变builder实例的值来控制最终生成FooWindow
实例。
在本例中,FooWindow
只有4个参数,当对象的参数变得更多时,改造前
每个属于设置方法都需要修改且考虑各参数的排序问题。而改造后
只关注单一的属性,很容易扩展。