模板方法模式实现探讨
模板方法(Template Method)模式是GOF设计模式中最为常见几个模式之一。现在流行的很多框架中(如Spring,struts等),我们都可以看到模板方法模式的广泛应用。模板方法模式主要应用于框架设计中,在日常的应用设计中也被经常使用。
?? 可是,我们在运用模板方法模式来解决我们的需求而进行设计时,往往忽略了一些非常重要的细节。保证架构逻辑的正常执行,不被子类破坏;怎么让子类扩展模板方法等。
1. 模板方法设计模式的意图
通常我们会遇到这样的一个问题:我们知道一个算法所需的关键步聚,并确定了这些步聚的执行顺序。但是某些步聚的具体实现是未知的,或者是某些步聚的实现与具体的环境相关。
模板方法模式把我们不知道具体实现的步聚封装成抽象方法,提供一些按正确顺序调用它们的具体方法(这些具体方法统称为模板方法),这样构成一个抽象基类。子类通过继承这个抽象基类去实现各个步聚的抽象方法,而工作流程却由父类来控制。
考虑一个简单的订单处理需求:一个客户可以在个订货单中订购多个货物(也称为订货单项目),货物的销售价是根据货物的进货价进行计算的。有些货物可以打折的,有些是不可以打折的。每一个客户都有一个信用额度,每张订单的总价不能超出该客户的信用额度。
根据上面的业务,我们可以知道处理一个订单需要的步聚:
1. 遍历订货单的订货单项目列表,累加所有货物的总价格(根据订货单项目计算出销售价)
2. 根据客户号获得客户的信用额度
3. 把客户号,订单的总价格,及订单项目列表写入到数据库
但是我们并不能确定怎么计算出货物的销售价,怎样根据客户号获得客户的信用额度及把订单信息写入数据库这些方法的具体实现。
所以用一个抽象类AbstractOrder确定订单处理的逻辑,把不能确定的方法定义为抽象方法,由子类去完成具体的实现。
这样Order类不再是一个抽象类,而是一个具体类。Order类委托OrderHelpher接口来完成placeOrder方法所需的基本操作。
像在这种情况下使用策略模式更具有优势,策略模式不需要继承来实现。而是通过一个委托对象来实现。OrderHelper接口无需要去继续任何指定的类。而相对来说,采用策略来实现会更复杂一些。
由此可见,模板方法模式主要应用于框架设计中,以确保基类控制处理流程的逻辑顺序(如框架的初始化)。像上面的测试基类中。框架通常需要控制反转。而在下面一些情况中,优级先考虑使用策略模式:
当需要变化的操作非常多时,采用策略模式把这些操作抽取到一个接口。
当那些基本操作的实现需要与其它类相关时,应该使用策略模式。通过委托接口把行为与实现完全分离出来(比如数据存取)。
比如订单处理的saveOrder方法,是写入数据库的。它的实现与你采用何种持久化模式相关。
当某些基本操作的实现可能需要在运行时改变时,可以通过在运行时改变委托对象来实现,而继承则不能。所以采用策略模式。
注:作者原创文章
参考文献
java与模式/阎宏编著 北京电子工业出版社 2002.10
Expert one-on-one J2EE Design And Development –Rod Johnson 2002
Design Partterns: elements of reusable object-oriented software? 1994