欢迎来到星巴兹咖啡
星巴兹(Starbuzz) 是以扩张速度最快而闻名的咖啡连锁店。如果你在街角看到它的店, 在对面街上肯定还会看到另一家。因为扩张速度实在太快了, 他们准备更新订单系统, 以合乎他们的饮料供应要求。
他们原先的类设计是这样的……
![]() |
购买咖啡时, 也可以要求在其中加入各种调料, 例如: 蒸奶(Steamed Milk) 、豆浆(Soy) 、摩卡(Mocha, 也就是巧克力风味) 或覆盖奶泡。星巴兹会根据所加入的调料收取不同的费用。所以订单系统必须考虑到这些调料部分。
这是他们的第一个尝试……
请为下面类的cost()方法书写代码( 用伪Java 代码即可) 。
public class Beverage { public class DarkRoast extends Beverage { public double cost() { |
当哪些需求或因素改变时会影响这个设计?
调料价钱的改变会使我们更改现有代码。
一旦出现新的调料,我们就需要加上新的方法,并改变超类中的cost()方法。
以后可能会开发出新饮料。对这些饮料而言(例如:冰茶),某些调料可能并不适合,但是在这个设计方式中,Tea(茶)子类仍将继承那些不适合的方法,例如:hasWhip()(加奶泡)。
这是很糟糕的!我们在第1章就得到了这个教训。
万一顾客想要双倍摩卡咖啡,怎么办?
轮到你了:
大师与门徒……
大师: 我说蚱蜢呀! 距离我们上次见面已经有些时日, 你对于继承的冥想, 可有精进?
门徒: 是的, 大师。尽管继承威力强大, 但是我体会到它并不总是能够实现最有弹性和最好维护的设计。
大师: 啊! 是的, 看来你已经有所长进。那么, 告诉我, 我的门徒, 不通过继承又能如何达到复用呢?
门徒: 大师, 我已经了解到利用组合(composition) 和委托(delegation) 可以在运行时具有继承行为的效果。
大师: 好, 好, 继续……
门徒: 利用继承设计子类的行为, 是在编译时静态决定的, 而且所有的子类都会继承到相同的行为。然而, 如果能够利用组合的做法扩展对象的行为, 就可以在运行时动态地进行扩展。
大师: 很好, 蚱蜢, 你已经开始看到组合的威力了。
门徒: 是的, 我可以利用此技巧把多个新职责, 甚至是设计超类时还没有想到的职责加在对象上。而且, 可以不用修改原来的代码。
大师: 利用组合维护代码, 你认为效果如何?
门徒: 这正是我要说的。通过动态地组合对象, 可以写新的代码添加新功能, 而无须修改现有代码。既然没有改变现有代码, 那么引进bug 或产生意外副作用的机会将大幅度减少。
大师: 非常好。蚱蜢, 今天的谈话就到这里。希望你能在这个主题上更深入……
牢记, 代码应该如同晚霞中的莲花一样地关闭( 免于改变), 如同晨曦中的莲花一样地开放( 能够扩展) 。
| 回书目 上一节 下一节 |