Template method vs Callback模式

原创 2007年10月03日 00:09:00

Template method vs Callback
以前曾在《也谈谈Spring中的Template和Callback模式》中谈过这两个模式的实用场合,那时候没有给出代码。
最近遇到一个问题,可以很好的说明这两种模式的使用场合。
需求:我暑假实习公司做的一个产品,我们Server组主要事情是:一、把页面的信息组装成DTO,使用JAXB技术
将定义的消息格式(xml schema)自动生成对应的Object,把DTO装配对应的Object,然后marsh成xml(JAXB是什么
东东可以参见以前我写的《尝试了一下JAXB2.0》),最后把消息发送给Client端。二、从Client端接收到xml,然
后unmarch成Object,然后把Object装配成DTO,最后传到页面,来设置页面。
我们可以看到整个过程非常的固定,无非是Send还是Get信息的问题。所以我们很容易想到使用摸版来解决,事实上我们最常用的Servlet也是这两种过程Post和Get,它同样使用了摸版方法。
举一个例子,一个Site里有许多Rules,我们要操作Rules(例如增删改之类的操作),不同的操作过程可能不同,
例如新增一个Rule,我们只需要做上面说的第一件事情,而如果要修改Rule则两件事情都要做。我们现在就用模版
方法来实现:

public interface CAIBaseService{
       
public String send(long agentId, String fullPath, int typeId,Object dto);
       
public Object get(long agentId,String fullPath,int typeId);
}

public class CABaseServiceTemplate implements CAIBaseService{
    
public String send(long agentId, String fullPath, int typeId,Object dto){
            RequestBean reqBean 
= doPrepareToSend(agentId,fullPath,typeId,dto);//把dto装配成Object[requestBean]
            Response response = doProcessRequest(reqBean);//真正把xml发送给Client端,这个过都是一样的,可以抽象出NetworkService来处理
            return doProcessSendResponse(response);//处理返回的response,例如根据response判断是否发送成功,以及失败的原因
    }
    
public Object get(long agentId,String fullPath,int typeId){
           RequestBean reqBean 
= doPrepareToGet(agentId,fullPath,typeId);//装配成Object[requestBean]的根,这样Client就知道消息是什么类型的,从而设置信息返回
           Response response = doProcessRequest(reqBean);//真正把xml发送给Client端,这个过都是一样的,可以抽象出NetworkService来处理
           return doProcessGetResponse(response);//处理返回的response,例如把response装配成Dto,判断是请求否发送成功,以及失败的原因
    }
    
protected RequestBean doPrepareToSend(long agentId, String fullPath, int typeId,Object dto);
    
protected String doProcessSendResponse(Response response);
    
protected RequestBean doPrepareToGet(agentId,fullPath,typeId);
    
protected Object doProcessGetResponse(Response response);
}
//    对于Rule
class AddRuleServiceImpl extends CABaseServiceCallbackTemplate {
     
protected RequestBean doPrepareToSend(long agentId, String fullPath, int typeId,Object dto){
      
//...
     }
     
protected String doProcessSendResponse(Response response){
      
//...
     }
           
protected RequestBean doPrepareToGet(agentId,fullPath,typeId){
     
//因为我们不需要这个操作所以,空实现
     }
     
protected Object doProcessGetResponse(Response response){
     
//因为我们不需要这个操作所以,空实现
     }
    }

class EditRuleServiceImpl extends CABaseServiceCallbackTemplate {
    
protected RequestBean doPrepareToSend(long agentId, String fullPath, int typeId,Object dto){
      
//...
    }
    
protected String doProcessSendResponse(Response response){
      
//...
    }
    
protected RequestBean doPrepareToGet(agentId,fullPath,typeId){
     
//...
    }
    
protected Object doProcessGetResponse(Response response){
     
//...
    }
}

 

我们发现对于一个Rule就需要三到四个Service,Service的粒度显得有点太细,因为我们我们继承了CABaseServiceCallbackTemplate,我们Service的粒度已经由CABaseServiceCallbackTemplate

控制了,
这就是继承的不灵活性,同时我们看到我们在AddRuleServiceImpl中还需要空实现两个方法,当然我们
可以继续对CABaseServiceCallbackTemplate封装出一个新的Template,将他们都默认空实现了CABaseServiceCallbackTemplate未实现的方法,这样我们在AddRuleServiceImpl就不需要空实现了,

另外,
doPrepareToSend,doProcessSendResponse到底是干什么的(由于Send方法在CABaseServiceCallbackTemplate
定义的),别人头一次看说不定发甍。综上,在这里使用Template method模式,产生了过于琐碎的类,并且
显得不够直观。
下面我们考虑使用Callback模式来实现,来避免上面的问题:

 

public interface CAIBaseService{
       
public String send(long agentId, String fullPath, int typeId,Object dto);
       
public Object get(long agentId,String fullPath,int typeId);
}

public interface CAProcessSendResponseCallback{ 
        RequestBean doPrepareToSend(
long agentId,String fullPath,int typeId,Object dto);
}

pubilc 
interface CAProcessSendResponseCallback{
    String  doProcessSendResponse(Response response);
}

public interface CAPrepareToGetCallback{
    RequestBean doPrepareToGet(
long agentId,String fullPath,int typeId);
}

public interface CAProcessGetResponseCallback{
    
public Object doProcessGetResponse(Response response);
}
    
public class CABaseServiceCallbackTemplate implements CAIBaseCallbackService{
      
public String send(long agentId, String fullPath, int typeId,Object dto,
               CAPrepareToSendCallback prepareToSendCallback,CAProcessSendResponseCallback processSendResponseCallback){
      
          RequestBean reqBean 
= prepareToSendCallback.doPrepareToSend(agentId,fullPath,typeId,dto);// 把dto装配成Object[requestBean]
          Response response = doProcessRequest(reqBean);// 真正把xml发送给Client端,这个过都是一样的,可以抽象出NetworkService来处理
          return processSendResponseCallback.doProcessSendResponse(response);// 处理返回的response,例如根据response判断是否发送成功,以及失败的原因
      }
     
public Object get(long agentId,String fullPath,int typeId,CAPrepareToGetCallback prepareToGetCallback,
             CAProcessGetResponseCallback processGetResponseCallback){
                RequestBean reqBean 
= processSendResponseCallback.doPrepareToGet(agentId,fullPath,typeId);// 装配成Object[requestBean]的根,这样Client就知道消息是什么类型的,从而设置信息返回
             Response response = doProcessRequest(reqBean);// 真正把xml发送给Client端,这个过都是一样的,可以抽象出NetworkService来处理
             return processSendResponseCallback.doProcessGetResponse(response);// 处理返回的response,例如把response装配成Dto,判断是请求否发送成功,以及失败的原因
     }
    }

    
public class CASiteRuleManageServiceImpl {  
         
private CABaseServiceCallbackTemplate caBaseServiceCallBackTemplate;
      
         
public CASiteNewRuleDto getEditRuleInfo(long agentId, String fullPath, int typeId) { 
               
return (CASiteNewRuleDto)caBaseServiceCallBackTemplate.get(agentId, fullPath, typeId,new CAPrepareToGetCallback (){
                     
public RequestBean doPrepareToGet(long agentId, String fullPath, int typeId){
                              
// ...
                     }
                }
               ,
new CAProcessGetResponseCallback (){
                     
protected Object doProcessGetResponse(Response response){
                        
// ...
                     }
               }
          );
     }

     
public String sendEditRuleInfo(long agentId, String fullPath, int typeId, CASiteNewRuleDto dto) {
      
return caBaseServiceCallBackTemplate.send(agentId, fullPath, typeId, dto, new dto,CAPrepareToSendCallback() {
              
public RequestBean doPrepareToSend(long agentId, String fullPath, int typeId,Object object){
                  
// ...
              }
             },
               
new CAProcessSendResponseCallback(){
                     
public  String doProcessSendResponse(Response response){
                          
// ...
                     }
               }
             ); 
     }

     
public String sendAddRuleInfo(long agentId, String fullPath, int typeId, CASiteNewRuleDto dto) {
           
return caBaseServiceCallBackTemplate.send(agentId, fullPath, typeId, dto, new dto,CAPrepareToSendCallback() {
                   
public RequestBean doPrepareToSend(long agentId, String fullPath, int typeId,Object object){
                       
// ...
                   }
                },
                
new CAProcessSendResponseCallback(){
                   
public  String doProcessSendResponse(Response response){
                         
// ...
                   }
                }
            ); 
// ...other operation
    }
}

 

我们发现使用Callback模式,我们可以把对Rule的操作组织成一个Service,避免产生大量的Service,同时我们可以随意使用Get和Send操作,而不象Template method受缚于上层定义步骤,以及要实现的方法,同时我们可以给Service的方法很好的命名(例如sendAddRuleInfo),从而使得程序更加清晰。唯一的不完美的地方是使用了内部匿名类,给程序的阅读带来点困难,当然可以用内部类来代替匿名的,但大家似乎更习惯使用匿名内部类,如果Java象Ruby那样能够支持block就好了(Java 7据说要支持closure,但由于Java历史的包袱太重,实现是何等的丑陋,非泛型所能比--Java为了向前兼容,泛型的实现实在难以和c++和c#相比)。
从上面分析可以看到如果不是真正的"is-a"关系的话,组合优于继承绝对是至理名言,继承就会对子类有所限制,而组合则没有什么限制,显得更加灵活。一般情况下如果一个操作的子步骤比较少(三个以下),特别是如果你不想生成太细粒度的对象时,用Callback来代替template method能够获得更好的灵活性,子步骤多则使用template method. 

Strategy模式和Template Method模式的异同浅析

一、Strategy模式 1. 特点说明: 定义一系列的算法,把它们一个个封装起来,并且使它们可相互替换。适用场景: 许多相关的类仅仅是行为有异。“策略”提供了一种用多个行为中的一个行为...
  • aheroofeast
  • aheroofeast
  • 2011年08月19日 20:16
  • 3097

C++主题——Template Method(模板方法)模式

 C++主题——Template Method(模板方法)模式        现在正在做一个差分系统,大概意思就是把服务器上的代码作为备份,程序员从服务器上下来修改了这些代码,然后在提交的时候,判断哪...
  • Xscarlet
  • Xscarlet
  • 2007年04月13日 10:36
  • 1158

Template Method模式和Strategy模式

Template Method模式和Strategy模式都可以分离通用的算法和具体的上下文,所解决的问题是类似的,但是实现的方法不同,一个是用的继承,一个是用的委托。 我们先来看一下Template...
  • nabila
  • nabila
  • 2012年08月24日 13:41
  • 1261

23种设计模式之python实现--Template模式

#理解 #就是普通通过继承实现多态的方法,对于通用操作在父类中实现,不同操作的细节在子类中实现,父类只声明接口 #注意的是要遵循DIP原则 #例子 #灯泡发光,不同的灯泡发不同的光 #Abstrac...
  • apple_boys
  • apple_boys
  • 2014年04月18日 10:46
  • 412

设计模式总结之Factory Method Pattern(工厂方法模式)

定义一个用于创建对象的接口,让子类决定实例化哪一个类。Factory Method 使一个类的实例化延迟到其子类。...
  • cooldragon
  • cooldragon
  • 2016年08月11日 00:44
  • 1250

模板方法模式(Template Method) - 最易懂的设计模式解析

前言今天我来全面总结一下Android开发中最常用的设计模式 - 模板方法模式。 其他设计模式介绍 1分钟全面了解“设计模式” 单例模式(Singleton) - 最易懂的设计模式解析...
  • carson_ho
  • carson_ho
  • 2017年02月07日 15:37
  • 5106

URI Template Patterns

URI templates can be used for convenient access to selected parts of a URL in a@RequestMapping metho...
  • u013571243
  • u013571243
  • 2015年03月15日 16:42
  • 2640

模版方法(Template Method)模式

无处不在的Template Method,如果你只想掌握一种设计模式,那么它就是Template Method。变与不变变化……是软件设计的永恒主题,如何管理变化带来的复杂性?设计模式的艺术性和复杂度...
  • bendan999999999
  • bendan999999999
  • 2007年05月24日 19:56
  • 293

Template Method模式

1.定义:一个操作中算法的框架,而将一些步骤延迟到子类中,使得子类可以不改变算法的结构即可重定义该算法中的某些特定步骤。 类型:行为类模式 类图: 2.模板模式与继承     模板方法估计恰当...
  • wangjian223344
  • wangjian223344
  • 2013年10月11日 11:16
  • 787

Template Method 模式

    回想一下你编写过的所有程序。其中许多可能具有如下的基本循环结构。Initialize();while(!Done()){ Idle();}CleanUp();     首先进行初始化应用...
  • robertcarlos
  • robertcarlos
  • 2010年05月24日 23:00
  • 336
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Template method vs Callback模式
举报原因:
原因补充:

(最多只允许输入30个字)