一个好的软件系统,除了必须符合使用者的需求之外,应该可以容易地再利用、维护及扩充。要达成这个目标,需要多少的设计思维及创意呢?若是符合这个目标的系统,一定充满软件美学的精神。软件设计其实是一种艺术,它不仅需要灵活的设计思维及技巧,还需要平衡项目的资源及使用者的期望,因此不管从工程面来看,还是从管理面来看,都是一种艺术。而要秉持软件美学精神来开发软件系统,其最深层的根基则必须要以「Pattern」来支撑。
相信有许多软件开发人员会觉得:Pattern和自己开发的程序代码好像是两回事一样,不知如何理解及使用,更不会了解它和软件架构、开发流程,乃至于整个开发项目的关系。美丽,应该从头开始,开发一个好的软件系统也是一样,就让我们从敷Pattern面膜开始。
我们先想象一个情境,假设你是一家比萨餐厅的大厨,现在有两位客人向你点餐,第一个人说:「我要一份虾仁搭配菠萝、洋葱的比萨,虾仁要多一点,再加上一份洒上墨西哥辣椒、洋葱、美式腊肠、意大利肉肠的比萨,不要太辣,外加一份法国香蒜面包及2瓶350毫升的百事可乐」。第二个人则说:「鲜虾菠萝及哈辣墨西哥比萨各一份,外加一份香蒜面包及2瓶小瓶的百事」。
如果你是大厨,你会比较希望听到哪一种点餐方式?除此,这两个人的点餐方式有什么差别呢?其中最大的差别就在于第二个人使用了大家都了解的餐点名称,大大地简化了点餐所使用的语句,而且所表达的意思和第一个人所要的差不多。如此身为大厨的你不仅容易理解顾客所点的餐点,也容易记忆他要的东西,并且节省了彼此沟通的时间。相较之下,你听到第一种点餐方式是不是很想把他轰出餐厅呢?
Pattern的沟通力量
我们再来看看对象导向的程序设计。一个设计老手一定熟悉许多对象导向的基本原理及设计原则,当他在解决一些设计问题时,会很自然地运用这些技巧及经验,设计出解决各式难题的蓝图。
假设你就是这位设计老手,而你刚好要跟伙伴说明这个绝妙的设计。你可能会说:「我先建立一个super abstract class及两个继承于它的sub-class,并在其中一个sub-class中建立一个往super abstract class方向的association以便形成container功能,这样就可以先完成一个递归的类别结构,然后在那container class实作一个final的method,用来固定的呼叫super abstract class所定义的抽象方法,这样在未来继承于此container class的类别阶层的所有对象,都可以动态地被加入到执行时期对象模型的递归结构,透过分别修饰原有功能来增加新功能」,不知道说到这里,有几个人听得懂的呢?
或许你可以用更简洁的方式来表达,你可以说:「在这个部份的设计,我要建立一个Decorator Pattern」。一句再简单不过的话,就足以表达上述那段又臭又长的演讲,甚至所传达的意思还更为清楚。这就是「共享词汇」的力量,也是「沟通」的力量。
在前一篇「感受美丽的元素,设计思维」中有提到,大部分的软件开发都是团队合作,要让大家了解自己伟大的设计,光用言语及UML来表达可能不够,还必须注意传达设计思维的问题。由于每一个Pattern的设计都是基于对象导向精神及原则,在应用上来看,它们保证了软件某个程度的弹性及稳定,除此之外,「沟通」则是另一项非常重要但却比较少人体认到的功用。从Pattern的定义来看:「一种在某个特定情境下,为了解决某种问题的解决方案。」因此,还要再加上某个特定「名称」,才能算是个Pattern,才能和别人沟通。
3类常见的Pattern
Pattern有很多种类,只要符合定义的都可以称做Pattern,但我们先把Pattern简单的分为三种常见的种类,分别是「Architectural Pattern」、「Platform Pattern」及「Design Pattern」,代表三种不同层次的应用,因为每个层次都有各自不同的问题。
Architectural Pattern针对的是软件架构,如Pipes、Broker、MVC等等。
Platform Pattern针对的是某个特定的发展平台,例如J2EE Pattern。
而Design Pattern就是大家比较耳熟能详的,例如四人帮(Gang of Four,简称GoF,这四个人分别是Gamma、Johnson、Helm、Vlissides)的圣经级著作《Design Patterns: Elements of Reusable Object-Oriented Software》一书中,所探讨的是针对一般化的问题,而不是特定领域的问题。每个领域的Pattern几乎都可以看到Design Pattern的影子,因为它提供了最基础而稳固的设计元素。
看到这里也许有人会说,有那么多开放原始码软件可用,为何还要用Pattern呢?这其实也是个事实,我们常常寻找好用的开放原始码 Framework作为开发系统的骨干,例如,Struts、Spring、Hibernate等等,通常我们只要加上一些客户需求的程序代码,拼凑一番,就可以上线了,似乎用不上Pattern。但是,除了要注意开放原始码的授权种类之外,还要注意那些Framework,是否有助于我们让自己的程序代码容易地维护、再利用及扩充?是否有助于我们去「沟通」?再者,这些著名的Framework都是使用Pattern来设计的最佳范例,因此理解 Pattern对于了解Framework的精髓,及如何整合入自己的系统,有很大的帮助,才不会误解Framework的整合方法而张冠李戴,这就是使用Pattern的最好时机及理由。
必学23个Design Pattern
初学Pattern的人一定会觉得Design Pattern很难放到自己的设计上,这个因扰大部分来自于所学的Design Pattern太少,只学习了几个Pattern就急于使用,就很容易会为了使用Pattern而强用Pattern,反而是化简为繁。因此,首先要尽量让自己对于Pattern有多一点的理解。我认为GoF所归纳出来的23个Pattern,是你该理解的最基本数量,这么说并不代表在设计软件中就应该全数用上,重点是当你理解那23个Pattern后,对对象导向会更有感觉,所累积的原力会让你较容易地「感觉」出,应该使用哪些Pattern。其实在做程序代码的Refactorying时,是最好的练习时机,因为你可以从现有程序代码,慢慢修改到某个Pattern的形式,要记住的是,Pattern只是心法,如何变化出招式是靠你的美感,实际的设计是没有必要和Pattern所定义的形式完全相同的。
透彻的很