本文来自李明子csdn博客(http://blog.csdn.net/free1985),商业转载请联系博主获得授权,非商业转载请注明出处!
模板方法(Template Method)模式将组成一个过程的各子过程与该过程的实现分离。
模板方法的基本形态如类图2-1所示。
图2-1 模板方法类图
结合图2-1,下面介绍各类在模板方法设计模式中扮演的角色。
3.1 AbstractClass
AbstractClass是抽象类,实现了模版方法TemplateMethod,并声明了模版方法中需要调用的抽象方法,如类图中的抽象方法PrimitiveOperation1及抽象方法PrimitiveOperation2。
3.2 ConcreteClass
ConcreteClass是具体类,派生于AbstractClass,实现了AbstractClass中声明的抽象方法PrimitiveOperation1和PrimitiveOperation2。
下面我们用一个业务场景实例来进一步讲解模板方法的使用。
4.1 场景介绍
某库存管理系统包含移库功能,可以将指定数量的商品从一个仓库移至另一个仓库。
以下各节将介绍该场景各类的具体实现及其在模板方法设计模式中所对应的参与者角色。
4.2 AbstractStorageMgmt
AbstractStorageMgmt是库存管理抽象类,实现了模版方法transfer,声明了需要子类实现的子方法add和remove。对应于模板方法模式的参与者,AbstractStorageMgmt是抽象类AbstractClass。下面的代码给出了AbstractStorageMgmt的声明。
package demo.designpattern.templatemethod;
/**
* 库存管理抽象类
* Created by LiMingzi on 2017/12/6.
*/
public abstract class AbstractStorageMgmt {
/**
* 入库
* @param storage 仓库名称
* @param product 产品名称
* @param count 入库数量
* @return 操作是否成功
*/
public abstract boolean add(String storage,String product,int count);
/**
* 出库
* @param storage 仓库名称
* @param product 产品名称
* @param count 出库数量
* @return 操作是否成功
*/
public abstract boolean remove(String storage,String product,int count);
/**
* 移库
* @param srcStorage 源库名
* @param destStorage 目标库名
* @param product 产品名
* @param count 数量
* @return 操作是否成功
*/
public boolean transfer(String srcStorage,String destStorage,String product,int count){
if(remove(srcStorage,product,count)){
return add(destStorage,product,count);
}
return false;
}
}
上述代码中,33行,移库功能,需要将指定数量的某商品从源仓库移至目标仓库。显而易见,这个功能需要从源仓库出库和向目标仓库入库这两个子操作(34-36行)。而它们并没有在AbstraStorageMgmt中实现,而是延迟到子类中实现。这里,仅仅在15行声明了抽象方法add及在23行声明了抽象方法remove。
4.3 StorageMgmt
StorageMgmt是库存管理类,派生于抽象类AbstractStorageMgmt。对应于模板方法模式的参与者,StorageMgmt是具体类ConcreteClass。下面的代码给出了StorageMgmt的声明。
package demo.designpattern.templatemethod;
/**
* 库存管理类
* Created by LiMingzi on 2017/12/6.
*/
public class StorageMgmt extends AbstractStorageMgmt{
/**
* 入库
*
* @param storage 仓库名称
* @param product 产品名称
* @param count 入库数量
* @return 操作是否成功
*/
@Override
public boolean add(String storage, String product, int count) {
// sql语句
String sql = "update t_storage set c_count=c_count+"+count+" where c_product='"+product+"' and c_storage = '"+storage+"'";
System.out.println("更新库存:"+sql);
return true;
}
/**
* 出库
*
* @param storage 仓库名称
* @param product 产品名称
* @param count 出库数量
* @return 操作是否成功
*/
@Override
public boolean remove(String storage, String product, int count) {
if(count>getProductCount(storage,product)){
return false;
}
// sql语句
String sql = "update t_storage set c_count=c_count-"+count+" where c_product='"+product+"' and c_storage = '"+storage+"'";
System.out.println("更新库存:"+sql);
return true;
}
/**
* 获取产品数量
* @param storage
* @param product
* @return
*/
private int getProductCount(String storage,String product){
// sql语句
String sql = "select c_count from t_storage where c_product='"+product+"' and c_storage = '"+storage+"'";
System.out.println("查询库存:"+sql);
return 100;
}
}
上述代码中,17行,入库方法add实现了抽象方法,这里以sql语句输出模拟入库功能;33行出库方法remove实现了抽象方法,34行由库存是否充足决定是否可以出库。同样,这里以sql语句输出模拟出库功能。
4.4 测试代码
为了测试本文中的代码,我们可以编写如下测试代码。测试代码中,分别对学步车和餐椅两种商品做移库操作。
/**
* 模版方法测试
*/
public static void templateMethodTest(){
// 仓库管理类
AbstractStorageMgmt storageMgmt = new StorageMgmt();
// 移库结果1
boolean result4TransferFromA2B = storageMgmt.transfer("仓库A","仓库B","学步车",80);
System.out.println("从仓库A转移80件学步车到仓库B"+(result4TransferFromA2B?"成功":"失败"));
// 移库结果2
boolean result4TransferFromB2A = storageMgmt.transfer("仓库B","仓库A","餐椅",120);
System.out.println("从仓库B转移120件餐椅到仓库A"+(result4TransferFromB2A?"成功":"失败"));
}
编译运行后,得到如下测试结果:
查询库存:select c_count from t_storage where c_product=’学步车’ and c_storage = ‘仓库A’
更新库存:update t_storage set c_count=c_count-80 where c_product=’学步车’ and c_storage = ‘仓库A’
更新库存:update t_storage set c_count=c_count+80 where c_product=’学步车’ and c_storage = ‘仓库B’
从仓库A转移80件学步车到仓库B成功
查询库存:select c_count from t_storage where c_product=’餐椅’ and c_storage = ‘仓库B’
从仓库B转移120件餐椅到仓库A失败