一个好的软件系统,除了必须符合使用者的需求之外,应该可以容易地再利用、维护及扩充。要达成这个目标,需要多少的设计思维及创意呢?若是符合这个目标的系统,一定充满软件美学的精神。软件设计其实是一种艺术,它不仅需要灵活的设计思维及技巧,还需要平衡项目的资源及使用者的期望,因此不管从工程面来看,还是从管理面来看,都是一种艺术。而要秉持软件美学精神来开发软件系统,其最深层的根基则必须要以「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 所定义的形式完全相同的。
透彻的很