比较巧,自己在接触设计模式的时候,也刚开始学习spring,但可惜的是,真的仅仅在学习“用”spring,每天都沉浸在会痛快的完成spring各种配置的快乐之中,但对成长无用。其实当初就清楚,spring框架中有大量设计模式,于是也下了代码来看,设计模式其实没那么简单,当初的学习也很皮毛,所以就没有发现spring中的金矿。现在动手,里面依然还是金矿,但不要偷懒,让它完全腐烂。[这是对自己的告诫]
开头上来就说到了spring跟设计模式,实际上,spring中的核心原则就是基于设计模式来构建的。这个时候继续祭出《敏捷软件开发》这本神书,结合里面比较全面的和具体的设计模式来大体讨论一下各种设计模式。(在此也建议将《敏捷》多看几遍,虽然里面用了c++示例,但极易理解)
在学习和讨论每种设计模式之前,都应该明确这样几个问题:
1)这个模式是什么?
2)这个模式适应的场景是什么,有何限制?
3)《敏捷》里面是如何推出来用这个模式的?针对《敏捷》中的场景,如若不考虑这个模式,会如何出手?这种类似于范伟大师傅的神功,为何降服不了“黑帮”?铁定被打趴在地上的原因,有考虑过么?[范伟是俺的偶像]
Command模式
这个模式表面上看是个比较简单的模式,这个是Bob的看法。他强调Command模式具有“功能分解的味道”。实际上在《design patterns》里面command也是被归类在行为类的。一般的command接口定义:
public interface Command {
public void do();
}
从这个接口的角度讲,我们根本不知道它的主要意图是什么,所以在一个类实现这个接口之后,这个类的动作意图,也同样被这个接口给封装起来了。Bob认为从面向对象角度,这是违犯天条的行为。但从上层抽象来说,这又是很好的屏蔽了上层(caller)对具体实现的依赖。所以说,命令模式是一种面向动作的独立抽象,它可以很好地处理输入和动作调用方之间的隔离关系。
考虑到《敏捷》中的两个例子,例1复印机程序,传感器可以在不需要知道当前的事件具体是什么的前提下,直接调用绑定到事件上的command 接口方法。例2验证雇员信息合法性的实现。在增加每个雇员信息到数据库之前都有对其所有信息的合法性进行验证。雇佣方式不同的雇员,其相关信息也是不一样的。如按小时工作的员工需要有相关的时间信息,而按业绩支付的也需要有相应的时间和数量,按月支付的员工则没有额外的信息。但在做增加一个雇员信息的事务时,能隔离掉对具体信息的依赖,可以减少这个事务代码实现的复杂性。《敏捷》在网上有电子书,各位可以对照着看看具体的架构实现。
针对《敏捷》中雇员事务的实现,来说明一种可能比较常见的方法,首先声明,这里说明的方法,从一定意义上讲,是没有考虑面向对象这些设计的,而是我们经常随手拈来写代码凑出来的习惯,写在这里,是想提醒自己,以后碰到这样的场景,应该考虑一下设计模式。看到这个需求,我们的第一印象,应该是给雇员分类:
public enum EmployeeType {
HOUR(1),
MONTH(2),
COMMISSION(3);
private EmployeeType(int type){
this.type = type;
}
private int type;
public int getValue(){
return this.type;
}
}
然后在实现AddEmployeeTransaction时,判断加入的Employee的type. 跟Bob的实现相比,我们少了什么,又多了什么?我的答案肯定不是唯一的,不仅是对这个需求的实现,还有前面这个问题。我来说一下自己的看法:
1.过程性的思维定势,使得AddEmployeeTransaction需要了解全部的可能情况,在种类繁多的情况下,可能会出现一个极其庞大,充满了if-else的大方法;
2.因为第一点,我们肯定创建了一个极其简单POJO 对象,很多人都会直接命名成VO(ValueObject)。
于是,各种所谓的smell就会出现。那么这个时候,我们可能通过重构来抽取出一些小方法,来格式化一个庞大的方法。如此之多的方法是否在说明一个问题,一些行为是否可以形成抽象。因为我们知道if-else比较多的情况下,要考虑command,strategy之类的设计模式,为什么?因为这些模式都是面向行为的,而我们就是在针对行为进行重构。
想到这里,突然对《重构》这本人人喜爱的书有点惋惜,要是它里面能关联上设计模式方面的内容,可能会更具震撼力,因为行动加上理论依据更有说服力,也可以在总是学重构方法方式的时候能思考一下,什么样的重构推出来什么样的模式。
以上是我的个人见解,是做了7,8年的一个对自己编码方式的总结,后面的一些设计模式,也会带上个人色彩的自我剖析。
那么为什么要讲command模式,当然接这个机会都学一遍,但在《设计模式》中关于Command模式的应用部分,其中的一种方式就是采用callback的方式来提供action perform,从而在时间上和引用上都隔离request和调用者。spring里面在阐述IoC的时候,尤其是关于jdbc的封装,它将具体业务相关的动作放到一个callback对象中,而JdbcTemplate可以在毫不关心具体业务动作的状况下,进行调用。
希望这个关联,有助于加深对spring设计的理解。
在part2,再讨论其他几个相关的设计模式,或许多少都会提一下。《设计模式》,《敏捷》,《Expert》这三本书再次捧在手上还是引人入胜,只是现在不会再像以前那么急躁,那么不顾实际场景的使用。由于spring这个框架本身就是个集大成的模板,这是一个极好的机会能切实看到大师级的架构思路,所以后面看情况,如有必要,就一下子把设计模式都过一遍。