我们从实际开发当地中找出一些例子,例如我接到一项任务,开发一个GPS数据解析器,用于根据GPS数据协议解析GPS发送回来的数据获得我们想要的数据

1.      一开始我接到任务,没有经过设计就开始编码了,首先新建GPSDataResolver类,添加Resolve方法,根据GPS传输回来的XML解析出经纬度字符串。OK,目前没有问题,程序稳定运行。

2.      过了一段时间,公司接到客户需求需要我们安装另外一家厂商的GPS,这时由于各个厂商的GPS数据解析协议都不同,因此我需要从新修改GPSDataResolver,为方法Resolve添加一个GPS类型参数,在方法内判断不同类型的GPS根据不同的协议解析。

3.      然后随着客户的增加,公司需要支持的GPS类型越来越多我就不断的修改GPSDataResolver,Resolve方法里的分支判断也越来越多,代码超过了300行,终于忍受不了将每一个GPS类型的数据解析都封装成一个方法,
终于Resolve方法解放了,代码行数减少到50行,但是每次有新的GPS类型加入,我还是在不断的修改GPSDataResolver类,即使方法的行数是减少到了50行,但是类的代码行数还是不断的在增加,显得类里面非常复杂,我同事说看到你这个类我都不想去维护了。

4.      受到同事的打击,我决心要寻找方法修改GPSDataResolver类,使他具有灵活性,扩展性和可维护性。于是我想到了工厂方法模式,将数据解析器抽象称为一个接口,根据这个接口,不同类型的GPS解析器可以具有不同的实现,客户端只需要依赖于IGPSDataResolver具体由哪个实现来解析数据完全由GPSDataResolverFactory控制。并且实现之间完全分离,就算由其他人来代替我继续开发新的GPS解析器也不用担心我原来的实现会影响到他,从而需要了解我之前的实现。

 5.      最后由于数据解析器代码结构、可扩展性、可维护性良好,合同伙伴公司也请求我们将数据解析器提供让他们使用,这时我想到了一点,为其他人提供服务应当尽量的简化,不要为他人增加复杂度,因此我将工厂合并到策略类当中,这样合作伙伴公司就连工厂类都不需要知道了。离,就算由其他人来代替我继续开发新的GPS解析器也不用担心我原来的实现会影响到他,从而需要了解我之前的实现。

 

 

说了这么多其实只是想表明软件开发编码不断改善的一个过程,就以上例子其实我们在一开始做开发的时候就应该想到哪一些会是相对稳定不会变化的部分(例如Resolve方法的参数)将其抽象出来以便以后对其进行扩展,也应该想到一些极为容易发生变化的地方(例如Rosolve方法根据不同GPS类型进行不同的解析)将其封装起来(封装到工厂里),只要我们遵循这样的设计思想,就可以为软件带来更多的可扩展性,可维护性。
 
 

对扩展开放,对修改封闭。开放封闭原则可以使软件系统面对需求的变动保持相对的稳定,但是无论模块是多么的封闭,都会存在一些无法对之封闭的变化。既然不可能完全封闭,设计人员必须对于他设计的模块应该对哪种变化封闭做出选择,他必须先猜测出最有可能发生变化的种类,然后构造抽象来隔离哪些变化。
在我们最初编写代码是,假设变化不会发生。当变化发生时,我们就创建抽象来隔离以后发生的同类变化。面对需求对程序的改动是通过增加新代码进行的,而不是更改现有的代码。我们希望的是在开发工作展开不久就知道可能发生的变化。查明可能发生的变化所等待的时间越长,要创建正确的抽象就越困难。
开闭原则是面向对象涉及的核心所在。遵循这个原则可以带来面向对象技术所声称的巨大好处,也就是可维护,可扩展,可复用,灵活性好。开发人员应该仅对程序中呈现出频繁变化的那些部分做出抽象,然而对于应用程序中的每个部分都可以地进行抽象同样不是一个好主意。拒绝不成熟的抽象与抽象本身同样重要。

 

 

posted on 2010-03-11 21:41  FengLin  阅读(553)  评论(1编辑  收藏  举报