从GOF的设计模式说起

设计模式对于做软件者来说是必修的内功之一,尤其现在面向对象已经成为主流的开发方法。掌握那些经过证实的面向对象的设计模式是学习和理解面向对象的绝佳途径,每一个模式都是面向对象最经典的应用。以前算法+数据结构=程序的时代已经一去不复返了,软件的复杂度越来越大,硬件水平的不断提到,也使得在一般的应用中性能的已不是主要的问题,算法在普通的应用中显得不像以前那么重要。而如何降低软件的复杂度,如何实现代码甚至组件级的复用,如何构建稳定而开放的系统?这些问题在软件理论的研究中越来越重要,而面向对象方法的提出很大程度的解决了这些问题,特别是使用面向对象的设计模式来降低软件的复杂性,提高重用性,构建开放的系统已经成为现实。掌握设计模式对于个人来说能够很大程度上提高设计和编写软件的水平,同时为学习各种框架打下了良好的基础,并且可以触类旁通。
学习某模式关键是学习这个模式它适用的场景和使用它所带来的效果,这样才能理解为什么要使用这个模式,从而更深层的理解这个模式。多与没有使用模式前的设计相比较,从而在差别中体会模式的妙处。同时横向对比各个模式也是很有益的,许多模式使用的场合差不多,细微的差别往往只用通过对比才能比较出来,特别是创建型模式的,他们都有类似相同的使用场景,但产生的效果不同。
下面从实际中看看使用模式所带来的好处:
  当前主流的web框架他们为什么能够流行,我想与良好的的设计是分不开得,而良好的设计自然离不开设计模式,spring为什么能够让EJB2.X退出j2ee的舞台,无疑是spring使用了恰当的设计模式的结果,spring的核心ioc(依赖注入),是工厂模式的应用,只不过这个工厂很大,大到我们我们需要都可以从中取,并让容器把这些对象的依赖关系注入到对象内部,使用ioc不仅可以减轻我们创建实例的负担,更重要的是避免硬编码的new,通过xml配置依赖关系,并把依赖关系注入到对象中,从而产生松耦合的系统。Spring对jdbc、hibernate和ibatis的集成,使用模板方法(template method)使得我们的写代码大大简化。其实Spring使用最多要算策略模式,策略模式让我们可以轻易的用一种实现方案替换掉已有的方案,Spring在每个层中都对不同框架进行了集成(web层对structs,webwork,jsf,持久层对hibernate,ibatis,JDO,JPA的集成),而每一种框架都是一种策略,使用策略模式很容易构建开放的体系架构,这就是针对接口编程而不是类编程的原因,有了接口就可以随意添加要替换的策略。使用dao模式很容易把对数据库的访问代码分离出来,而不是把对数据库的访问的代码分散的业务层,便于测试,你也很容易与抽象工厂模式结合,使的你的数据库很容易在不同的数据库移植,而不管你的底层是使用jdbc,ibatis,hibernate还是JDO,然后使用facade模式进行封装,提供用户简单的接口的同时也把数据访问层隐藏掉。而EJB使用的是很多理论上很有价值的,但实际上并不那么有价值模式,例如实体bean,这个思想从理论上很好,但是在性能上很差。使用分布式对象来增强系统的可伸缩性,不管我们现在在一台服务器还是多台上运行,我们只要做成分布式的,以后就可以方便移植到多台服务器在多个JVM运行,理论上似乎很很完美的,但实际上为了当我们不需要分布式的时候我们去分布式,我们牺牲的是什么?性能,复杂性,远离oo,为了减少远程调用的往返次序,我们需要把对象粒度做得很粗,这显然远离了oo。并且使得设计显得不自然,EJB设计失败的原因可能也与当时测试驱动的方法没有流行有很大的原因,所以使得ejb完全绑定在ejb容器中,结果是测试非常困难。无侵入的框架对于一个成为事实标准的框架或许并不那么重要,但是如果你使得测试难于进行,没有生产率的框架无疑会被抛弃。现在的Spring无论在思想上还是在实际使用中许多方面都要比ejb先进,虽然EJB3.0的版本对ejb作了很大的改进,但许多方面并没有胜过spring,并且现在Spring已经被广泛的使用,不知道会会像ip协议那样被因为被广泛使用而成为事实的工业的标准。
像web层核心模式大多是命令模式(command),这是因为command模式对于request驱动pull方式是天然的恰当选择。Webwork2.x设计的为什么那么优雅,是因为恰当模式的应用并且进行了更高层的抽象,webwork2.x和structs一样都使用command模式,但Webwork2.x是Action普通的java类,完全不依赖servlet,看起来完全不象是web程序,带来的好处不仅可以是脱离了servlet容器而被复用,更重要的是更容易测试,其核心是使用一个valuestack,把所有的参数值放在这个stack里,而不是使用request获取参数值,爽吧。同时webwork强大的拦截器功能,可以轻松增强bean的功能,其实无论是Filter还是AOP在动态给对象增加功能这点其实基本的思想还是来自装饰模式。AOP可以说是对oo的很好的一个补充,将各个方面分离出来,然后动态的注入切入点,使用AOP似乎是那么的自然,而装饰模式更多的是一种技巧,使用起来并不显得那么自然,像java的IO使用的装饰模式,给我们提供动态组合各种功能,让java的io功能非常强大,而使用起来对于初学者来说并不那么容易,因为这些组合需要用户自己去做,而不理解这个模式,会觉得这么做很不自然,甚至觉得有点怪异。模式能够产生优雅的框架,我们只有能够深刻理解设计模式,才能象作家有了对语言的超强驾驭能力一样,产生优雅的作品,才能让我们的工作真正成为艺术而不是技术。
而现在真正懂得设计模式的人并不是很多(当然我也是只知皮毛),记得我在做编译原理课程设计时,从实验室主页下载了一个用java写的SNL编译器源码,估计也是研究生写吧,
不知道作者为什么选择java语言,整个代码感觉是使用自动化工具从c语言中自动翻译而来,
庞大的switch,if随处可见,由于java不支持联合,使用大量大粒度的对象,并且许多成员许多时候根本没有用到。本来已经写完了词法分析,后来决定用java重写,要不可真枉瞎了java了这纯面向对象的语言了。下面说说我使用了设计模式后,所产生的效果。所有的语法成分都定义了一个结点类,这样的对象是细粒度,避免了空间的浪费,并且可以单独对接点进行语法、语义检查以及翻译成中间代码,并且使用访问者模式,把对结点的操作从结点类中分类出来成一个visitor,可以很容易增加对结点的操作,你可以通过生成一个visitor子类增加打印语法树的功能,你可以再写一个visitor子类来增加检查语法错误的功能,增加中间代码的翻译,你可以随意扩充,而这一切不需要动已经写好的代码,这就是模式的效果,如果你在各个结点类写这些功能,那么你增加一个功能你就需要更改所有结点类的实现,你想想,近百个类还不累得你头都大了。
  各个结点类使用组合模式来组成语法树的树形结构,与visitor模式结合和容易进遍历,并且统一对各个结点处理,而不需要区分是组合结点还是叶子结点。使用Builder模式来创建结点类,并最终形成语法树,把语法树复杂的创建过程隐藏,只需要调用一个创建方法,一切就ok了,这就是Builder模式的效果,并且你可以很容易通过替换掉已有的Builder来改变创建的过程。
下面是使用简单工厂(Simple Factory)模式和命令模式(command)所产生的效果:
public ActionFactory{
Action []actionCache = new Action[]{
new Action1(),new Action2(),
//…
new Action106()
}

public Action create ActionInstance(int i){
return actionCache[i];
}
}
actionCache 是Action的缓存,每个Action 都是一个采用Command的模式的一个动作,由于这些Action都是无状态的(没有数据成员),性能不会受到影响,并且由于缓存作用而使
这些实例能够预先创建并且得到共享,当然这只是附带的性能上好处。我在使用这个模式的主要目的是:提供一个数字与一个动作的映射。如果从SNLCompiler的背景中来说,就是从LL(1)文法的动作表中(一个非终极符和输入token流的匹配表,表中填写使用的匹配的文法的序号),找到对应的文法序号,并且每条文法对应一个处理动作(Action)。从而根据找到的文法序号来产生对应的Action,然后使用多态来处理不同的文法:
Action action = factory.createActionInstance(num);
predict(action);
从而避免在predict中使用庞大的 switch…case的判断。
使用Facade模式对编译器的各个子功能进行封装,留给用户的所能看到的只有几个子功能接口,将背后复杂的实现全部隐藏,产生的效果是简洁而清晰的界面。
就像一个软件无论如何强调oo都不为过,而模式是表现oo的最佳途径,以上仅仅是关于设计模式的概要。没有具体讨论各个模式。以后有空把Gof的各个模式分别总结一下。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值