〔从这篇《模式的演化和改良》系列开始,我会不定期的更新这个系列的文章,皆在于分享自己在日常工作中的一些心得体会,并整理成较系统的文章,以此和大家沟通分享,也请大家指出不足或提出新的见解〕
基于OO中的职责单一原则,我们需要将一个类的自身行为和外部实体作用于它的行为区分开来。例如我们需要将“商品”类自身的行为(如“获取商品价格”),和其他实体作用于“商品”类的行为(如“统计所有商品的价格”或者“将商品持久化”)区分开来。如果用这些本不属于“商品”类的行为去污染“商品”类的话,我们会发现随着系统的维护,原始的“商品”类将会变得异常的复杂和不可理解,并且这些行为也会分散到“商品”类以及它的各个子类中去,使得维护和扩充这些行为变的复杂。基于这些原因,《设计模式》一书中提出了Visitor模式,将类和对类进行的一些操作解耦开来,使得我们可以方便的在不改变原始类的情况下定义对原始类的新操作。(结构图略,请自行参阅《设计模式》一书218页关于Visitor模式的描述)
在我们使用Visitor模式解耦类和对类进行的一些操作的同时,也引入了一些附作用(同样在《设计模式》一书中有详细的描述)。其中我觉得除了潜在的破坏封装的风险外,其最大的问题是不能使原始类和对其操作的Visitor类独立的进行变化,我们可以很容易的通过扩充新的Visitor类来扩充新的操作,但是却让增加新的原始类变的很困难,Visitor模式假设了原始类族群很少发生变化,但不幸的是在实际应用中这些原始类族群经常发生变化。
考虑设计一个对某些类进行持久化的方案,“持久化”方法并不属于某个特定类自身应具有的行为,另外这些“持久化”行为本身可能多种多样,例如我们可以有两种持久化方案:持久化到数据库或者持久化到Xml文档中;我们当然希望对这种持久化方案的选择不会影响到我们需要持久化的对象自身,于是我们按照Visitor模式得到了如下的结构:

点击图片看大图Visitor1


我们分离了Persist行为,使得我们比较容易扩充新的PersistentProvider而不用重新编译PersistentObject及其子类DerivePersistentObject1。然而这个设计假设了PersistentObject及其子类需要持久化的字段不容易发生变化,举个例子,如果PersistentObject还有一个子类DerivePersistentObject2,它需要持久化的字段也只能是Field1,Field2,Field3;如果它还有第四个字段Field4,那么这个字段无法获得持久化的支持。因为PersistentProvider只认识基类PersistentObject的3个字段Field1,Field2,Field3,当PersistentObject及其子类需要发生变化(加入新的可持久化字段)时,我们不得不修改每一个IPersistentProvider的实现类,这个代价显然是比较大的。
解决的办法是让IPersistentProvider不依赖于具体的PersistentObject类,而是依赖于自身所需要的某种抽象,并让PersistentObject 及其子类去实现这种抽象。考虑持久化一个数据所需要的常用信息:数据的名称,数据的值和数据的类型,把这些常用信息作为我们的抽象根本,我们可以得到如下的一个改良Visitor模式:

点击图片看大图Visitor2

我们使用IPersistentDataProvider来表示IPersistentProvider对需要持久化的类所提出的要求。即需要这些可以被持久化的类实现该接口,并通过该接口告诉IPersistentProvider需要持久化的主键和字段,这些主键和字段都是一种在持久化时所需要的一些通常的数据PersistentElement(数据名称,值和类型)。现在IPersistentProvider和PersistentObject可以独立的发生变化,IPersistentProvider依赖于自身所提出的抽象,扩展新的PersistentObject对象族,只用在新的类中实现IPersistentProvider所提出的那个抽象IPersistentDataProvider接口。无论是修改PersistentProvider以便扩充新的持久化方法,还是修改PersistentObject用以扩充需要持久化的类族,这两部分都可以单独的进行变化,并单独的编译。另外,用PersistentObject实现IPersistentDataProvider,降低了破坏PersistentObject封装性的风险。
当然,这个新的模型仍然存在一些缺陷:
1. 某些场景下可能我们没有办法抽象Visitor对象所需要的数据(即很难提取出类似IPersistentDataProvider这样的接口)。
2. Visitor类(IPersistentProvider及其实现类)的行为比较单一,例如只是持久化。如果Visitor类以后需要支持其他的特性,而这些新的特性和已有特性对目标类的要求差别比较大;例如扩充Visitor使其不只是支持持久化,还可以将目标类图形化,显然图形化要求目标类提供的数据不只是PersistentElement的集合这么简单。这时我们需要定义新的数据抽象,例如IGraphicDataProvider,并要求目标类实现IPersistentDataProvider接口的同时也实现IGraphicDataProvider接口。当Visitor的行为扩充可控时,这样做尚可,但如果Visitor的平行行为(功能完全不同的行为)过多时,我们可能会要求目标类实现过多的接口,从而增加目标类的变化复杂度。幸运的是,在大多数场景中Visitor的变化(特别是平行变化)都少于目标类本身的变化,这种改良Visitor模式在大多数场景下都很适用或者说可控。从另一个角度来说,如果Visitor类有过多的平行行为,根据职责单一原则,这些Visitor类本身的组织结构是不是也需要进行仔细的设计和划分呢?

posted @ 2009-04-28 22:15 hkbarton 阅读(1241) 评论(5) 编辑
由于这段时间忙于公司的项目和家里的一些事情,加上也没有什么值得一说的技术观点或者想法,所以上来更新的时间少了。

其实要说没有想法倒也不是,最近在公司所做的一些项目还有所参与的一些和同事的讨论却也让自己冒出了一些想法,不过只是胡思乱想罢了。两年前大家都热衷于Web2.0的时候,自己就曾投入过相当的关注,也认识了少数站在浪潮中心的站长们,两年后发现大部分人过的都不是太好。垮掉的不少,原地踏步没有变化的也不少,没有清晰的盈利模式成了Web2.0的硬伤,成功者屈指可数,用我自己的观点来说“卖掉就是成功。运营?想都别想!”。去年和今年央视举办的几届《赢在中国》节目倒也点燃了不少人的创业雄心,大家互相奔走,找投资,组团队,到处挖掘着金点子,好一片繁荣热闹的景象。于是,除了“坚持不懈,吃苦耐劳”的创业精神外,那个看似简单却又重要的问题再次浮出水面:做什么?

如果说Web2.0,Web3.0会成为泡沫的话,倒也有那么一条踏实一点的,适合IT人走的创业道路:做项目,做咨询。做项目,大家再熟悉不过了,不外乎就是到外面去找项目来做,政府的,学校的,机关的,小企业的,可以做的项目很多。和Web2.0的迅速,高风险,靠一两个点子吃饭的速成道路相比,去找些项目做确实踏实了很多,没有盈利模式的困扰,也没有高高在上的技术门槛,看起来的确很容易。然而,现实却也未必如此,做项目的非技术因素太多。由于技术门槛不高,人人都可以做项目,导致市场竞争激烈,环境恶劣,再加上那么一点点中国特色,要靠做项目生存也是十分艰辛。通俗一点讲,没有关系谁拿项目给你做?而且大部分技术出身的人都喜欢埋头于技术中,身上一股典型的“宅男”味,不注重社交,不注重建立自己的人脉,要让他们靠关系吃饭?难!做咨询,中国这两年刚起步不久,比起做项目来说提升了一个层次,技术门槛也提高了很多。做咨询需要在做项目的基础上,积累和建立起一套针对某个行业的完善成熟的行业知识体系和技术积累,形成针对某个行业的产品体系,做的好的甚至能够在行业内有重要的话语权。如果说做项目缺乏核心竞争力的话,那么丰富的行业经验和技术积累无疑给做咨询注入了强有力的核心竞争力,做咨询产出的是高标准化,高质量,体系化的成熟的解决方案,而不再是滥竽充数的项目。那么做咨询就是出路吗?哪里有这么简单!其实前面的描述太过理想主义,那些光鲜的成功案例给无数想做咨询的创业者们构筑起一个个漂亮的乌托邦,然而现实确是残酷的。不在行业内摔几个跟头,不靠从做项目做起多年在行业内的摸爬滚打,怎么可能积累起成熟的行业经验和技术积累?从另一个方面看,做咨询和做项目一样也存在着很多非技术因素,除了需要良好的社会关系外,还需要有拿的出手的成功案例说服客户。我们需要思考并自我回答这些问题:对于那些具有中国特色的客户来说,他们拿五分之一甚至十分之一的投资就能做到的面子工程,为什么还需要花大本钱来做咨询呢?而对于那些中小企业来说,他们同样可以以很小的代价引入能够带来收益的项目,为什么需要将紧缺的资源浪费在无法立即看到成效的事情上面呢?

说了那么多,才发现原来问题除了“做什么”,还有“怎么做”。创业路上没有速成班,去除浮躁,勤练内功是一种无论是创业者还是打工者都应具有的心态。
posted @ 2009-04-28 22:14 hkbarton 阅读(12) 评论(0) 编辑