设计模式流行之初,我曾在某新闻组里看到一条评论,说有人号称他们试图倾尽23个GoF设计模式去编写一个奇葩程序。不过他们说最终没有成,极其所能也只用到其中20个。他们希望客户叫他们返工,没准能加塞另外3个。
试图用遍所有模式是行不通的,终将以生拼硬凑的设计告终——投机取巧的设计充满百无一用的灵活性。这年头软件太过复杂了。我们不能猜测还要什么,而应该关注于本该要什么。
gamma1
大家刚开始学习设计模式时,很少考虑模式的适用场景,想方设法到处套用,觉得模式用得越多,设计越好。结果产生大量不必要复杂的代码。2
与其说是“运用模式”,不如说是“滥用模式”。有人试图在Hello World程序中套用模式,不可避免地导致滥用。
让我们考察一个示例。这是一个经典问题: 编写一个程序,打印字符串Hello World
至标准输出。
编程新手会写出如下代码(Java语言):
1
| System.out.println("hello world");
|
这段代码看起来超乎简单。能否加点设计模式?接下来…
首先,定义两个接口Subject
和Observer
,加入观察者模式。
1
2
3
4
5
6
7
8
9
| public interface Subject {
public void attach(Observer observer);
public void detach(Observer observer);
public void notifyObservers();
}
public interface Observer {
public void update(Subject subject);
}
|
然后,定义两个类HelloWorldSubject
和HelloWorldObserver
实现以上两个接口。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
| public class HelloWorldSubject implements Subject {
private ArrayList<Observer> observers;
private String str;
public HelloWorldSubject() {
super();
observers = new ArrayList<Observer>();
}
public void attach(Observer observer) {
observers.add(observer);
}
public void detach(Observer observer) {
observers.remove(observer);
}
public void notifyObservers() {
Iterator<Observer> iter = observers.iterator();
while (iter.hasNext()) {
Observer observer = iter.next();
observer.update(this);
}
}
public String getStr() {
return str;
}
public void setStr(String str) {
this.str = str;
notifyObservers();
}
}
public class HelloWorldObserver implements Observer {
public void update(Subject subject) {
HelloWorldSubject sub = (HelloWorldSubject)subject;
System.out.println(sub.getStr());
}
}
|
接着,再添加一个命令模式。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
| public interface Command {
void execute();
}
public class HelloWorldCommand implements Command {
private HelloWorldSubject subject;
public HelloWorldCommand(Subject subject) {
super();
this.subject = (HelloWorldSubject)subject;
}
public void execute() {
subject.setStr("hello world");
}
}
|
然后添加一个抽象工厂模式。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
| public interface AbstractFactory {
public Subject createSubject();
public Observer createObserver();
public Command createCommand(Subject subject);
}
public class HelloWorldFactory implements AbstractFactory {
public Subject createSubject() {
return new HelloWorldSubject();
}
public Observer createObserver() {
return new HelloWorldObserver();
}
public Command createCommand(Subject subject) {
return new HelloWorldCommand(subject);
}
}
|
再添加一个单例模式即大功告成。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
| public class FactoryMakerSingleton {
private static FactoryMakerSingleton instance = null;
private AbstractFactory factory;
private FactoryMakerSingleton() {
factory = new HelloWorldFactory();
}
public static synchronized FactoryMakerSingleton getInstance() {
if (instance == null) {
instance = new FactoryMakerSingleton();
}
return instance;
}
public AbstractFactory getFactory() {
return factory;
}
}
|
最后编写一个主类(用作测试)。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| public class AbuseDesignPatterns {
public static void main(String[] args) {
AbstractFactory factory = FactoryMakerSingleton.getInstance().getFactory();
Subject subject = factory.createSubject();
subject.attach(factory.createObserver());
Command command = factory.createCommand(subject);
command.execute();
}
}
|
程序运行输出: Hello World
哇,我们已经在Hello World程序中成功地运用四种模式。(嗯,其实还能添加一个迭代器模式,不过已经引用了内置的迭代器,Java中经常如此)。这必须是一个拿得出手的设计呀。那么问题出在哪儿呢?
- 对于一个Hello World程序而言代码过于复杂。
- 包含多余的灵活性。
- 设计和实现的时间成本是彻彻底底的浪费。
- 引发了类膨胀。
- 违反了KISS原则。3
- 没满足问题的要求。问题目的本在于学习打印标准输出,以上代码却缪以千里。
总结
设计模式应具体场景具体运用,不要为运用而运用。设计模式是构建大型软件的强大工具。应恰到好处,切忌滥用。
从这儿下载文中的代码。欢迎来函反馈。如果谁有办法在Hello World程序中堆砌更多设计模式,再好不过了。
参考文章