12种行为模式 之1 TEMPLATE METHOD 模板方法模式 《Java与模式》学习笔记
在运用模板方法模式来解决我们的需求而进行设计时,往往忽略了一些非常重要的细节。保证架构逻辑的正常执行,不被子类破坏(模板方法加final关键字);怎么让子类扩展模板方法等。抽象模板中的基本方法尽量设计为protected类型的,符合迪米特法则.
迪米特法则(LoD):又称最少知识原则(LKP),就是说一个对象应当对其他对象尽可能少的了解。如果两个类不必彼此直接通信,那么这两个类就不应当发生直接的相互作用.如果其中一个类需要调用另一个类的方法的话,可以通过第三者转发这个调用.
1.模板方法设计模式的意图
通常我们会遇到这样的一个问题:我们知道一个算法所需的关键步聚,并确定了这些步聚的执行顺序。但是某些步聚的具体实现是未知的,或者是某些步聚的实现与具体的环境相关。模板方法模式把我们不知道具体实现的步聚封装成抽象方法,提供一些按正确顺序调用它们的具体方法(这些具体方法统称为模板方法),这样构成一个抽象基类。子类通过继承这个抽象基类去实现各个步聚的抽象方法,而工作流程却由父类来控制。
2.模板方法模式定义及结构
考虑一个简单的订单处理需求:一个客户可以在个订货单中订购多个货物(也称为订货单项目),货物的销售价是根据货物的进货价进行计算的。有些货物可以打折的,有些是不可以打折的。每一个客户都有一个信用额度,每张订单的总价不能超出该客户的信用额度。
根据上面的业务,我们可以知道处理一个订单需要的步聚:
1.遍历订货单的订货单项目列表,累加所有货物的总价格(根据订货单项目计算出销售价)
2.根据客户号获得客户的信用额度
3.把客户号,订单的总价格,及订单项目列表写入到数据库
但是我们并不能确定怎么计算出货物的销售价,怎样根据客户号获得客户的信用额度及把订单信息写入数据库这些方法的具体实现。
所以用一个抽象类AbstractOrder确定订单处理的逻辑,把不能确定的方法定义为抽象方法,由子类去完成具体的实现。
抽象模板类
public abstract class AbstractOrder { //模板方法 public Order placeOrder(int customerId , List orderItemList){ int total = 0; for(int i = 0; i < orderItemList.size();i++){ OrderItem orderItem = (OrderItem)orderItemList.get(i); Total += getOrderItemPrice(orderItem) * orderItem.getQuantity(); } if(total > getSpendingLimit(customerId)){ throw new BusinessException(“超出信用额度” + getSpendingLimit(customerId)); } int orderId = saveOrder(customerId, total, orderItemList); return new OrderImpl(orderId,total); } //基本方法 public abstract int getOrderItemPrice(OrderItem orderItem); //基本方法 public abstract int getSpendingLimit(int customerId); //基本方法 public abstract int saveOrder(int customerId, int total, List orderItemList); } Public class ConcreteOrder extends AbstractOrder{ public int getOrderItemPrice(OrderItem orderItem){ //计算货物的售价 …… } public int getSpendingLimit(int customerId){ //读取客户的信用额度 ….. } public int saveOrder(int customerId, int total, List orderItemList){ //写入数据库 …… } } Public interface OrderHelper{ public int getOrderItemPrice(OrderItem orderItem); public int getSpendingLimit(int customerId); public int saveOrder(int customerId, int total, List orderItemList); } public class Order { //委托的接口 private OrderHelper orderHelpr; public void setOrderHelper(OrderHelper orderHelper){ this.orderHelper = orderHelper; } //具体逻辑 public Order placeOrder(int customerId , List orderItemList){ int total = 0; for(int i = 0; i < orderItemList.size();i++){ OrderItem orderItem = (OrderItem)orderItemList.get(i); Total += orderHelpr .getOrderItemPrice(orderItem) * orderItem.getQuantity(); } if(total > orderHelpr .getSpendingLimit(customerId)){ throw new BusinessException(“超出信用额度” + orderHelpr .getSpendingLimit(customerId)); } int orderId = orderHelpr .saveOrder(customerId, total, orderItemList); return new OrderImpl(orderId,total); } }