设计模式是什么?
Shubho:通过我们关于面向对象设计原则(OODP,即SOLID原则)的对话,我想你已经对面向对象设计原则(OODP)有了基本的认识。希望你不要介意我把对话分享到博客上。你可以在这找到它:<如何向妻子解释OOD>.
设计模式是这些原则在某些特定公共场景下标准化的应用,接下来让我们通过一些例子学习什么是设计模式。
Farhana: 当然,我喜欢例子。
Shubho: 让我们以汽车为例讨论一下。汽车是一个很复杂的对象,由成千上万的其它对象组成,如发动机,车轮,方向盘,车座,车体等等其他不同的部分或部件。
汽车部件
当装配汽车时,制造商需要集中并装配这些更小的自成汽车子系统的不同部件。而这些不同的小部件同样也是复杂的对象,其它制造商同样要生产并组装它们。在生产汽车时,汽车公司并不会为怎么生产组装这些部件操心(前提是他们要确保这些对象/设备的质量)。当然,汽车制造商更加关心怎么装配这些不同部件以便能生产不同型号的汽车。
通过遵循不同的设计,组装不同的部件,生产不同型号的汽车
Farhana: 汽车制造公司必须有如何生产不同型号汽车的设计图或蓝图,对吗?
Shubho: 当然,并且这些设计都是良好的,他们花费大量的时间和精力来做这些设计。一旦设计完成,生产汽车就仅仅是照葫芦画瓢了。
Farhana: 嗯。如果事先有一些好的设计,就能在短时间内遵照这些设计生产不同产品,并且制造商在每次生产某一个型号产品时就不需要重新设计或重新发明车轮,他们只需要按照已有的设计办事就行了。
生产不同型号产品(汽车)的不同设计图
Shubho: 你抓到重点了。现在假设我们是软件生产商,我们使用基于需求而来的不同组件或功能构建各种不同的软件程序。当生产这些不同软件系统时,我们常常需要为一些不同软件系统中存在的相同情况开发代码,对吗?
Farhana: 是的,在开发不同软件程序时经常遇到相同的设计问题。
Shubho: 我们尝试使用面向对象的方式开发软件,并尝试应用OOPD来让代码能易于维护,可复用,可扩展。无论什么时候,当我们遇到这些设计问题时,如果我们有一组经过谨慎开发,良好测试的对象以供使用会不会更好呢?
Farhana: 是的,这样能够节省时间,生产出更好的软件,且利于以后维护。
Shubho: 很好!从设计上来说,它的好处是你不需要开发那些对象。经过多年发展,人们已经遇到过一些类似的设计问题,并已经形成有一些公认的,良好的已标准化的设计方案。我们称之为设计模式。
我们一定好感谢四人组,他们在《设计模式:可复用面向对象软件设计》中总结出了23种基本的设计模式。四人组由Erich Gamma, Richard Helm, Ralph Johnson, 和John Vlissides组成。实际中有很多面向对象设计模式,但这23种模式被公认为是所有其他设计模式的基础。
Farhana: 我能发明一个新的模式吗?这可能吗?
Shubho: 当然,亲爱的,为什么不能呢?!设计模式不是由科学家发明创造的。它们是被发现找到的。这意味着任何通用问题场景中都有一些好的设计方案在那。如果我们能够指出一个能够解决一个新的设计相关问题的面向对象设计,那么这将会是一个由我们定义的新的设计模式。谁知道呢?!如果我们发现找到一些设计模式,或许将来有一天人们会称我们为二人组,哈哈。
Fahana: :)
我们将如何学习设计模式?
Shubho: 我一直认为例子是学习的最好途径。在我们的学习方法中,我们不会先讨论理论后讨论实现。我认为这是很糟糕的方式。设计模式不是基于理论的发明。事实上,问题场景首先出现,其次是基于这些问题的来龙去脉和需求,然后是一些设计方案的演化,最后其中的一些被标准化为模式。所以对每一个我们讨论的设计模式,我们将尝试理解并分析一些现实生活中的例子,然后一步步尝试归纳一个设计,并最后总结一些与某些模式匹配设计。设计模式就是在这些相似过程中发现的。你认为呢?
Farhana:我想这种方式对我更有用。如果我能通过分析问题和归纳方案得出设计模式,我就不用死记那些设计模式和定义了。请按照你的方式继续。
一个常见的设计问题和它的解决方案
Shubho: 让我们考虑下面的场景:
我们房间里有些电器(电灯,风扇等)。这些设备按照某些方式布局,并由开关控制。任何时候你都能替换或排查一个电器而不用碰到其他东西。例如,你可以换一个电灯而不需要换开关。同样,你可以换一个开关或排查它而不需要碰到或替换相应的电灯或风扇;甚至你可以用把电灯连接到风扇的开关上,把风扇连到电灯的开关上,而不需要碰到开关。
电器:风扇和电灯
风扇和电灯的两种不同开关,一个普通点,另一个别致点
Farhana: 是的,但就是这样子,对吗?
Shubho: 是的,确实如此,就该如此布局。当不同东西联系在一起时,它们应该按照一定方式联系:修改或替换一个系统时不会影响到另一个,或者说即便有,也应该最小化。这能够让你的系统易于管理,且成本低。想想一下,如果改一下房间里的灯同时需要改开关,你会乐意在你房子上花钱并安装这个系统吗?
Farhana: 当然不会。
Shubho: 现在,让我们思考一下电灯或风扇如何连接到开关上才能达到改变一个不会影响到另一个。你认为该如何?
Farhana: 用电线!
Shubho: 很好。把电灯/风扇和开关联系到一起的是电线和电器布局。我们可以它们看做不同系统间相互联系的桥梁。其基本的思想是,一个事物不能和另一外一个事物直接联系。当然啦,它们应当通过某些桥梁或接口联系在一起。用软件术语来说,这叫“松耦合”。
Farhana: 我知道了。
Shubho: 现在,让我们尝试推断在电灯/风扇和开关例子中的几个关键问题,并尝试推断它们是如何设计并联系起来的。
Farhana: 好,我们试一下。
例子中我们有开关,可能有几种开关,如普通的开关,漂亮的开关,但通常来说它们还是开关,并且每种开关都能够打开和关闭。