模板模式讲解二
一、何为模板
在阎宏博士的《JAVA与模式》一书中开头是这样描述模板方法(Template Method)模式的:
模板方法模式是类的行为模式。准备一个抽象类,将部分逻辑以具体方法以及具体构造函数的形式实现,然后声明一些抽象方法来迫使子类实现剩余的逻辑。不同的子类可以以不同的方式实现这些抽象方法,从而对剩余的逻辑有不同的实现。这就是模板方法模式的用意。
二、模式结构设计
父类定义成一个抽象类,有一个具体实现方法,在这个具体实现方法会去调用此抽象类定义的抽象方法,这些抽象方法由子类继承实现,因为不同的业务逻辑是需要由不同的子类完成的。父类的具体实现方法,只是把这些子类的抽象方法执行的共同点抽取出来。有点不好理解,直接看图吧
三、操作数据库的模板模式设计
场景 : 大型的电商网站,如淘宝、京东、苏宁等。仔细分析下,领域模型大同小异。无非就是围绕商品、规格、订单等模型来展开。一个商品,它的模型是怎么样的呢?商品名字、价格等。但我们很难把商品的所有属性定义出来,并不是所有的商品属性都是一样的。所以,这时商品就有了另一个极其灵活的属性-->扩展属性。扩展属性,顾名思义,可扩展,视需求定义。比如,我们定义商品的购买限制规则,每个ID只能购买一件等等。商品的扩展属性很多,在保存商品属性信息,同时也需要保存扩展属性。保存扩展属性信息,操作可以细分为如下三种 :
①、创建商品信息,插入扩展属性
②、更新商品信息,更新扩展属性(假设属性表,A商品有三条扩展属性信息,origin_id=[123,456,789] , 现在需要更新扩展属性信息,new_id = [456,520] )
a、插入新的扩展属性 : id = 520
b、更新扩展属性 : id = 456
c、删除不需要的扩展属性 : id = 123,789
③、删除商品信息,删除扩展属性
我们的重点是讲第②点,update商品信息,其更新规则如下:
a、属性表没有的,参数有的,则插入
b、属性表有的,参数有的,则更新
c、属性有的,参数没有的,则删除
更新商品扩展属性伪代码如下:
1 public Result<GoodsDTO> save(List<GoodsDTO> newInfo) { 2 // 获取商品的老扩展属性信息 3 List<GoodsDTO> oldInfo = getGoodsAttrByGoodsId(Long goodsId); 4 5 for(GoodsDTO newGoods : newInfo) { 6 boolean isNeedInsert = true; 7 for(GoodsDTO oldGoods :oldInfo) { 8 if(newGoods.getId() = oldGoods.getId()) {// 属性表有的,参数有的,则为更新 9 isNeedInsert = false; 10 updateAttr(newGoods); 11 break; 12 } 13 } 14 if(isNeedInsert) {// 属性表没有的,参数有的,则为插入 15 insertAttr(newGoods); 16 } 17 } 18 for(GoodsDTO oldGoods : newInfo) { 19 boolean isNeedDelete = true; 20 for(GoodsDTO newGoods :oldInfo) { 21 if(newGoods.getId() = oldGoods.getId()) {// 属性表有的,参数没有的,则为删除 22 isNeedDelete = false; 23 break; 24 } 25 } 26 if(isNeedDelete) { 27 deleteAttr(oldGoods); 28 } 29 } 30 }
代码逻辑不复杂,但这种逻辑写法,严格来说,是非业务性代码,浸入了我们的业务系统。我们再想想,同样,规格、订单等也有扩展属性。它们的操作规则大同小异。试想,让
你每次更新扩展属性时,写这种恶心逻辑,你能坚持写下去么?如果,后续我们更新扩展属性的规则变了呢?比如,不再根据扩展属性的Id来判断是否add、update、delete?那这时问题来了,你是不是把所有有此逻辑的代码找出来,改改?显然,谁也不愿意这样干。这时,模板设计就派上场了。可以把改动点抽取粗来,集中在一个父类的具体实现方法。
insert 、 update 、delete这些不同的DAO对应不同的表操作,由具体的子类去继承父类,并强迫子类去实现这些抽象方法。
父类(模板)
1 public abstract class DoTemp<T extends BaseDO> { 2 3 public abstract void insert(T t); 4 5 public abstract void update(T target, T orign); 6 7 public abstract void delete(T t); 8 9 protected void execute(List<T> target, List<T> orign) { 10 if(target != null) { 11 for(T t : target) { 12 boolean isNeedInsert = true; 13 for(T o : orign) { 14 if(t.getId() == o.getId()) { 15 this.update(t, o); 16 isNeedInsert = false; 17 } 18 } 19 if(isNeedInsert) { 20 this.insert(t); 21 } 22 } 23 } 24 25 if(orign != null) { 26 for(T o : orign) { 27 boolean isNeedDel = true; 28 for(T t : target) { 29 if(t.getId() == o.getId()) { 30 isNeedDel = false; 31 } 32 } 33 if(isNeedDel) { 34 this.delete(o); 35 } 36 } 37 } 38 } 39 }
实体类:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 public class GoodsDO extends BaseDO { 2 3 private int id; 4 5 private String name; 6 7 @Override 8 public String toString() { 9 return ToStringBuilder.reflectionToString(this); 10 } 11 12 public GoodsDO() { 13 14 } 15 16 public GoodsDO(int id, String name) { 17 this.id = id; 18 this.name = name; 19 super.id = id; 20 } 21 22 public int getId() { 23 return id; 24 } 25 26 public void setId(int id) { 27 this.id = id; 28 } 29 30 public String getName() { 31 return name; 32 } 33 34 public void setName(String name) { 35 this.name = name; 36 } 37 } 38 39 40 41 public class BaseDO { 42 43 public int id; 44 45 public int getId() { 46 return -1; 47 } 48 49 public void setId(int id) { 50 51 } 52 }
子类:
public class GoodsDoTempImpl extends DoTemp<GoodsDO> { @Override public void insert(GoodsDO t) { // TODO Auto-generated method stub System.out.println("-------- insert ---------" + JSON.toJSONString(t)); } @Override public void update(GoodsDO target, GoodsDO orign) { // TODO Auto-generated method stub System.out.println("-------- update ---------" + JSON.toJSONString(target) + "---- 更新后值为 ----" + JSON.toJSONString( orign)); } @Override public void delete(GoodsDO t) { // TODO Auto-generated method stub System.out.println("-------- delete ---------" + JSON.toJSONString(t)); } }
测试类 :
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 public class Client { 2 3 public static void main(String[] args) { 4 5 6 test_dotemp(); 7 } 8 9 public static void test_dotemp() { 10 11 List<GoodsDO> target = new ArrayList<GoodsDO>(); 12 List<GoodsDO> orign = new ArrayList<GoodsDO>(); 13 for(int i = 1; i<3; i++) { 14 GoodsDO p = new GoodsDO(); 15 p.setId(i); 16 p.setName("ym" + i); 17 target.add(p); 18 19 p = new GoodsDO(); 20 p.setId(i - 1); 21 p.setName("ym" + (i - 1)); 22 orign.add(p); 23 } 24 25 new GoodsTempImpl().execute(target, orign); 26 }