1 实例
有些人喜欢喝茶,有些人喜欢喝咖啡,所以现在有咖啡和茶两个类,基本代码如下:
Coffee
类:
class Coffee { public: virtual ~Coffee(); void prepareRecipe(); protected: void boilWater(); void brewCoffeeGrinds(); void pourInCup(); void addSugarAndMilk(); };
Tea
类:
class Tea { public: virtual ~Tea(); void prepareRecipe(); protected: void boilWater(); void steepTeaBag(); void pourInCup(); void addLemon(); };
我们发现代码有重复: void boilWater()
和 void pourInCup()
。那么如何整合代码消除重复代码呢?
浅谈设计模式九: 外观模式(Facade)
1 实例
在家组建了一个家庭影院,基本配置如下图。每次看电影都要进行如下一系列准备工作:
- 打开爆米花机
- 爆米花机制作爆米花
- 调暗灯光
- 投影幕布降下来
- 打开投影机
。。。等等
至少在 10 项的准备工作,如果每次一一去调用,非常的繁琐,那么如何让用户方便而简洁的准备看电影,并看完电影善后等活动呢?

浅谈设计模式八: 适配器模式(Adapter)
1 实例
如果有一只乌龟走的像一只鸭子,发生声音也类似鸭子,鸭子的接口已经存在了,现在想把乌龟添加到鸭子实例的调用者里,那么调用者能如何继续用鸭子的接口去调用乌龟呢?
浅谈设计模式七: 命令模式(Command)
1 实例
有一个远程控制器,上面有很多按钮,每个按钮分配不同的功能,比如打开客厅灯,关闭客厅灯,调高风扇的风力,关闭风扇等。那么整个家庭会有如下那么多的控制对象,如何很好的维护,易扩展,易独立改变呢?

浅谈设计模式六: 单例模式(Singleton)
1 实例
对于一些类来说只有一个实例是很重要的。如,仅有一个文件系统,一个窗口管理者。一个数字滤波器只有一个模数转换器。
那么我们如何确保一个类只有一个实例,而且这个实例能容易的访问?
- 全局变量。一个全局变量能使对象任意访问,但是它并不能防止你实例化多个对象。
- 单例模式。更好方法是让类自己负责保存它唯一的实例。这个类能保证没有其他实例被创建(通过截断创建新对象的请求),而且它提供获取这个实例的方法。
浅谈设计模式五: 抽象工厂模式(Abstract Factory)
1 实例
继续扩展模式四中的批萨店实例,加入批萨配料对象。不同的地区的批萨店有一组共同的产品(如生面,酱汁,芝士等等),但是根据不同地区的口味有不同的实现。整个系统变得有点复杂了,
- 有不同的批萨原料,同样的批萨原料在不同的地区有不同的作法;
- 每个店有不同种类的批萨(即各种原料搭配不同);
- 整个批萨连锁在不同地区有不同的店。
如何清晰而易维护的设计整个批萨连锁店系统呢?
浅谈设计模式四: 工厂模式(Factory Method)
1 实例
批萨店有各种不同的批萨,根据不同的用户来点批萨,基本实现如下:
Pizza* orderPizza(string type) { Pizza pizza = NULL; if (type == "cheese") { pizza = new CheesePizza(); } else if (type == "pepperoni") { pizza = new PepperoniPizza(); } else if (type == "clam") { pizza = new ClamPizza(); } else if (type == "veggie") { pizza = new VeggiePizza(); } pizza->prepare(); pizza->bake(); pizza->cut(); pizza->box(); return pizza; }
但是如果批萨店新添或下架其它的品种的批萨呢?就需要在这个函数里添加或删除不同的批萨,而这段代码包括变化的批萨品种,和不变的批萨制作过程。不易后期维护。
浅谈设计模式三: 装饰器模式(Decorator)
1 实例
星巴克以咖啡文明,现在为它设计它的咖啡订餐系统。
- 先定义一类饮料的基类
Beverage
,为不同咖啡做好一个接口。 - 每种不同的咖啡继承这个基类,覆盖各自的特性,比如描述,价格等。
每种咖啡都有很多中附加,比如拿铁咖啡就有,加糖拿铁,加奶拿铁,加奶加糖拿铁等等。所以按照上面的设计来设计咖啡订餐系统,那么整个系统类结构如下:

每种咖啡不同的附加组合导致太多类。
浅谈设计模式二: 观察者模式(Observer)
1 实例
有一个气候观测应用,包括三部分:
- 气候站(WeatherStation):物理设备用来采集实际天气数据;
- 气候数据对象(WeatherData)追踪来自气候站的数据和更新显示;
- 给用户现在气候情况的显示(xxDisplay)
现在气候收集这 3 个数据:温度,湿度和气压。有 3 种不同的显示:现在的天气情况,天气统计信息和天气预测信息。
直观的话是在 WeatherData
类里的 measurementsChanged()
里直接调用不同显示器的 update()
来更新数据,如下:
WeatherData::measurementsChanged() { currentConditionsDisplay.update(temp_, humidity_, pressure_); statisticsDisplay.update(temp_, humidity_, pressure_); forecastDisplay.update(temp_, humdity_, pressure_);
1. WeatherData 和 Display 比较紧的耦合。在函数内直接使用实例,每次增加或较少 Display 都要在这个函数内修改。
2. 以具体实例来编码,使得不能动态的添加和减少显示元素,唯有修改这段代码
浅谈设计模式一: 策略模式(Strategy)
1 实例
有一个模拟鸭子的应用完成。这个应用可以仿真鸭子的各种活动,比如游泳,鸣叫,飞等等。能马上想到的模式设计如下:

一个基类 Duck
定义 Duck 的一些特性,子类继承它的特性,并覆盖它的部分特性。至此没什么问题。子类共同拥有父类的特性,消除了代码的重复性。
然后想让 Duck
具有有 fly()
的特性,把它加到父类中,相应的不同
duck(子类)如果不具备 或 fly()
或 quack
的特性,那么就去覆盖父类相应的特性。



每增加一个不同的子类 duck,如果没有父类相应的特性都要去覆盖它,很冗余。
那么如果把不变的特性继续放在基类 Duck
里,而把变化的特性拿出来做成独立的接口呢?

1. 增加代码的冗余性,每个子类 duck 都要去实现部分相同的特性;2. 想更改一个相同的 fly() 特性,要在相应的所有子类都修改