(learn&think)

不浮躁,不自傲,学习,思考,总结

浅谈设计模式十九: 责任链模式(Chain of Responsibility)

| Comments

1 实例

学校里,教师,主管,主任都有不同的职责,现在家长有不同的请求,比如他们小孩的日常表现或付学费等,但家长并不清楚学校内部的职责归属,哪个请求该去找那个人处理,家长一般直接与孩子的老师交流,那么如何满足家长不同的请求呢?

浅谈设计模式十八: 享元模式(Flyweight)

| Comments

1 实例

绘画培训班内,一次绘图课上,每个学员要练习大量不同颜色的圆形,那么如果为每个学员都实例和维护不同颜色圆的实例话,将产生很多重复颜色的圆,占用很多存储开销,那么如何大家共享这些圆的实例呢?

浅谈设计模式十七: 桥接模式(Bridge)

| Comments

1 实例

画圆可以顺时针或逆时针,但只能使用一种方法,不能同时既顺时针又逆时针。比较直观的做法就是定义两种不同的圆,但同时继承于圆的基本特性基类。但如果不采用继承并在运行时选取画圆的方法呢?

浅谈设计模式十六: 原型模式(Prototype)

| Comments

1 实例

有一个系统中有很多系统配置和用户简况:

  1. 初始读取配置或用户简况需要花一些时间(比如用一些系统调用或读取数据库等),但并非实时数据,只需初始化读一编;
  2. 因为众多系统配置和用户简况需要初始化,每次手动初始化比较繁琐,希望能一个类其中管理并快速创建实例

那么如何能不每次手动初始化对象,并能克隆初始化的数据到新的实例呢?

浅谈设计模式十五: 生成器模式(Builder)

| Comments

1 实例

批萨店有不同种类的批萨,每种批萨的制作流程类似,如果每个批萨都创建一个类,并且在各自类中完成各自的制作,那么制作流程的代码就会重复,并且制作过程与对象本身融合在一起,那么如何把所有批萨类似的制作流程分离出来,并消除代码冗余呢?

浅谈设计模式十四: 代理模式(Proxy)

| Comments

1 实例

在酒吧,有不同的酒和喝酒者对象,一开始,喝酒者都能喝酒,没有任何限制。之后,规定年纪小于 16 岁的不应该喝酒。那么如何在不改动众多的酒类的情况下,限制喝酒的年纪呢?

浅谈设计模式十三:状态模式(State)

| Comments

1 实例

实现如上运行的糖果机,基本的做法就是定义好每个状态,然后把每个状态转换的行为定义为一个函数方法来实现状态间的转换。

class GumballMachine {
 public:
  explicit GumballMachine(int cout);
  void insertQuarter();
  void ejectQuarter();
  void turnCrank();
  void dispense();
 private:
  const int SOLD_OUT = 0;
  const int NO_QUARTER = 1;
  const int HAS_QUARTER = 2;
  const int SOLD = 3;
  int state;
  int count;
};

现在糖果机生产商想新添加一个幸运机制,添加一个 winner 状态,有 1/10 的概率成为 Winner,免费获得一个糖果,状态机图如下:

在原有的代码上新添加这个状态,需要在每个转换函数里修改,以致很多处修改,容易产生错误。分析这个设计的缺陷:

  • 状态转换不明显,一堆判断语句在每个转换函数里;
  • 没有封装好变化部分和不变化部分,使得两者纠缠在一起;
  • 进一步添加与修改容易产生 bugs。

浅谈设计模式十二: 组合模式(Composite)

| Comments

1 实例

上节使用迭代器模式可以很方便访问各个菜单目录下的菜单,易易于菜单目录的扩展。但现在菜单目录下新增加了子菜单,比如 DinerMenu 下有 DessertMenu 的子菜单,那么如何更进一步改进我们的设计,新设计至少需要:

  • 一种树状结构来包含菜单目录,子目录和菜单项。
  • 遍历菜单目录里的每个菜单项如何迭代器一样方便。
  • 遍历菜单更灵活。比如,只遍历 Diner 的 desssert 菜单,或遍历整个 Diner 菜单,包括 dessert 菜单。

浅谈设计模式十一: 迭代器模式(Iterator)

| Comments

1 实例

为了提高市场竞争力,早餐店(Pancake House)和午餐店(Diner)合并了。如下整合他们的菜单让服务员使用。

PancakeHouseMenu 类使用 vector 来维护它的菜单,它认为使用 vector 可以很容易的扩展自己的菜单。

class PancakeHouseMenu {
 private:
  vector<MenuItem*> *menu_items_;
};

DinerMenu 类使用数组来维护它的菜单,它认为使用数组能控制菜单数目和更快速的添加菜单。

class DinerMenu {
 public:
  enum { kMaxItems = 6 };
 private:
  int number_of_items_;
  MenuItem *menu_items_[kMaxItems];
};

那么 Waitress 类需要使用两个循环分别访问它们的菜单来打印整个菜单。但问题是:

  • 面向菜单的具体实现来编码而不是接口。
  • 如果增加一个新的餐厅类,就需要另外一个循环,代码冗余,不易扩展。
  • Waitress 需要知道每个餐厅类是如何内部表示它的菜单,破坏了它们的封装。
  • 如果餐厅类改变存储菜单的方式,比如由数组变成 Hashtable,那么 Waitress 需要很大的改动。

如何设计使得避免这些问题呢?