从面向对象到设计模式

面向对象(OO),所有熟悉计算机的朋友都听说过,一些设计,开发人员在自己开发过程中或多或少使用到面向对象.但若要其解释一下,什么是对象,什么又是面向对象.又恐怕很少有人能说的很清楚.最近正好在学习设计模式,正好把一些学习感受拿出来和大家分享,交流.

让我们从现实生活开始,假如给你安排一个任务(每个人,每一天都会有很多任务).最让你头痛的是什么.也许你会说:"刚刚准备这么去做的,现在情况又变了,哎,又得重新去做".让你不安是一种不确定感,你不知道你这样去做,事情本身还会不会变化.哦!,找了下原因,不安的是变化.不巧的变化是绝对的.是不可阻止的.

同样的,软件设计,开发过程中也会同样出现这样的问题.时常听人抱怨说:"我们不是昨天谈好了的么,怎么又要改,你们这样改过来,改过去,还让不让人活了."这种抱怨并不是没有道理,老是改动计划并不一件好事,因为这会迫使你不得不放弃你先前很多的劳动.很明显解决这种事的方法就只有两种:1,不让用户变更他们的需求.(说实话,现在有些用户也有些变态,不能总是一味满足他们的要求,适当的时候要学会拒绝).2,使自己的系统更有弹性,以适当不断的变化.

别人的事,交给别人自己去处理(请注意,待会还要提到).我们今天想谈的是怎么样让自己做的更好.以适应不断变化的需求.假如现在有一个任务:将数据库的三角形信息抓出来,并显示在自己的屏幕上,思考一下,没多少我脑中就有了一个解决方法(方案):

  1. 先将存于数据库中三角形的信息抓出来(假设边长为20,30,40);
  2. 在我们电脑屏幕上画出一个边长为(20,30,40)的三角形;

你也许会觉得这没有什么难的,的确,这是很简单.你很高兴你自己这么快就完成了任务.正准备打开网页冲冲浪,或是来杯Coffee休息一下.但这时你电话响了,你得先接一个电话."哦,我的天,你怎么不早说,还有正方形",刚写好的程式又要改.叹了一口气,改吧,你把你的解决方法改为如下:

  1. 先将存于数据库中的信息抓出来;
  2. 判断你抓出来的形状是三角形还是正方形;
  3. 第三步若是三角形,在屏幕上画出一个(20,30,40)的三角形
  4. 第三步若是正方形,在屏幕上画一(40,40,40,40)的四边形;

也还好,你的改动并不大,只需要两个小时,你改好了.这下了可以休息了吧.你想去休息一下,因为你有些累了.这时电话又响了(怎么又响了),电话那头告诉你:"不好意思,刚才忘记说了,数据库里还有可能有五角星"[email protected]#$%*#&@....

这下子你并没有一接到任务就做去改程序,你心里在琢磨着:小样,不会我刚刚加上个五角星,你又会让我画出个六边形吧.显然你的担心是有必要的,不能总改来改去,你得有更好的办法去适应他的更改.一番苦思冥想后,你找到了一个较为完美的解决方案:

  1. 先设计一个类Shape,这个类有一个方法Display();
  2. 新增一从Shape类派生一个三角形类(这个三角形类由于是Shape生出来的,他也有一个Dispay方法来显示自己--一个三角形),派生一个四边形类,一个五角星类
  3. 将数据库中形状信息抓出来,判断一下,放至三角形类,四边形类中.
  4. 让这个形状类显示自己Display();

好了,你的设计完成了.乍一看,你并没有多大改动.我们来看看吧.这时电话又响了,六边形又来了.不过你已不再害怕,只是一个小小改动而已,你只要做以下修改:

  1. 先设计一个类Shape,这个类有一个方法Display();
  2. 新增一从Shape类派生一个三角形类(这个三角形类由于是Shape生出来的,他也有一个Dispay方法来显示自己),派生一个四边形类,一个五角星类,一个六边形类;
  3. 将数据库中形状信息抓出来,判断一下,放至三角形类,四边边类,或是六边形类中.
  4. 让这个形状类显示自己Display();

好吧,他来什么,我们只要做相应的新增就可以了.

这个故事听完了,让我们回头去想一下,是什么让我们可以适应不断的变化的(解决了变化的问题).想着想着一个对象的概念也就出来了.

什么是对象?一个有着责任,对自己负责的实体就是一个对象.

什么是类?有着同样的责任(显示自己),的一个群体.物以类聚.

所有对象都有一个责任:显示自己,具体要怎么显示,谁管它呢?这些事让它自己负责,它要是三角形就显示出三角形,它要是五角星就显示出五角星.它要是大的三角就显示大的三角形,它要是小的三角形就显示小的三角形你只要发一个命令给它:显示自己.

有了上面的这些理解,面向对象的的一些特性也会变的理所当然了.

  1. 封装性:简单的讲,对象要做什么,这是它的事.我只要它能显示自己就可以了.
  2. 多态性:三角形的类,会在屏幕上显示一个三角形,正方形的类会显示一个正方形.我只要说:显示自己.同样的一句话,有可能显示出三角形,有可能是正方形.(一种方法,两种结果)
  3. 抽象类:我让你画一个形状出来,你会问什么形状.我说:"不管反正是一个形状,形状总是可以画出来的".

好了,这就是我们的抽象类.形状是什么,我们不知道,我们只知道他能显示自己.所以的形状都有这个特性.

在继续介绍设计模式前,先来放松一下,说一些生活中的哲学。现在你准备在家里举办一个Party,你首先会想到什么?“这个Party要有节目,有歌曲,有说唱的”,“这个Party要有人来组织,小王去买酒,小李去买菜”,“先在大厅放一张桌子”。

其实这些说法都是对的,只不过从不同角度看事物而已。佛曰:"一花一世界,一叶一菩堤",或许这就是最高境界。不过我们是人,人看事物大致可以分为三个层面:

  1. 实现层面:看事物,看细节,了解来龙去脉;
  2. 规格层面:看事物,看类别,了解其方向;
  3. 概念层面:看事物,看框架,了解其本质;

这个和程序对应起来:

  1. 实现层面:Source code;
  2. 规格层面:Public function&interface;
  3. 概念层面:Design pattern;

设计模式所讲的内容应该是概念层面的内容。模式,模式,模式,自己默念三遍会发现,好抽像。抽像也就对了。抽像在这里可以代表两个含义:

  1. 抽像不可以直接拿来应用,他需要实现;
  2. 模式具有很高的通用性。抽像可以指导实现,为实现提供了通用的方式,方法;

先来介绍一下简单的模式Facade模式,之所以先这个例子是因为它在我们无知觉的情况下,时常被我们应用,也可以用它来理解模式的定义。先前在培训时,一个老师这样说过,想让对方理解一个事物的话“文不如表,表不如图”,今天我们采取"一图,二表,三文字"的方式来说明Facade模式,希望让智者能看图便可知其意,节约保贵的时间.

从图上可以简洁的看出Facade提供了一个抽像,使我们的Client可以在不知道有DB的情况下很好的工作.我们的Client只需要Facade提供的接口就OK,具体的接口实现部分不必关心.

有这样的一个感觉(至少我现在是这么认为),一个模式的感觉,那么我们就可以拿来应用,得出的Facade模式常见的一些应用:

  1. 隐藏实现的细节: 如果我们不想让别人知道我们后台的具体细节,那么我们可以提供一个Facade给使用者,让他可以很好的使用,但不知道具体的实现细节,保证了安全性
  2. 屏蔽操作(client端)的复杂: client只想查一下数据,或是打印一表格,没有必要进行一大堆无关目的性的而又必须的操作.例如:连接数据库,对数据进行处理等等.那我们只需要给我一个简单的函数GetTable(),那么就OK了.
  3. 包容变化: 这是Facade模式的一个重点应用,或者说最贴近OO思想的应用.也许哪天数据库变了,那么只需更新一个Facade,哪天表格格式变了,可以更新一下Facade.哈哈,说到这里知道Facade模式的好处了吧.

所以我们遇到同一种概念的时候,我们就可以拿Facade这个模式来指导我们的思想,指导我们的实现.具体应用各位见仁见智了.

设计模式中还有许多模式类型,像Adapter模式,Factory模式.这些模式都能给我们的程序设计提供很好的指导,以包容变化,实现需求.具体这些内容可以看一本很经典的书《设计模式》,也许会有一天,你会发现设计软件和设计楼房一样,会给你带来快乐,当你在欣赏自己的软件时,犹如在欣赏艺术品一样.

@ 2007-03-27 08:00

Comments:

Sharing your thoughts: