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. 

相关文章推荐

Spring的template与callback模式

Spring中 Callback模式和Template模式合用 随处可见。下面以常用的HibernateTemplate为例进行简要简述。     由于java的JDBC的开发过程中有许多步骤是...

23种设计模式之模板方法(Template Method)

23种设计模式之模板方法(Template Method) 模板方法模式是一种类的行为型模式,用于定义一个操作中算法的骨架,而将一些步骤延迟到子类中。模板方法模式使得子类可以不改变一个算法的结构即可...

在objective-c中实现模板方法模式(template method)

在ios中实现模板方法(template method)模式
  • kyfxbl
  • kyfxbl
  • 2013年12月02日 12:49
  • 3239

Template Method模板方法设计模式(类行为型)

概述在面向对象开发过程中,通常我们会遇到这样的一个问题:我们知道一个算法所需的关键步骤,并确定了这些步骤的执行顺序。但是某些步骤的具体实现是未知的,或者说某些步骤的实现与具体的环境相关。 例子1:银...

模板方法模式(Template Method Pattern)。

博文中的内容来源《设计模式之禅》这一本书,感激不尽。

3.10 Template Method(模板方法) -- 类行为型模式

临近毕业,很多人都会到人才网发布简历以寻求符合自己要求的岗位。登陆人才网,系统会给我们提供一份统一的模板,我们只需要按照要求填写个人信息、教育背景、工作经历、项目经验等内容就可以了。虽然大家都是使用相...

Java设计模式透析之 —— 模板方法(Template Method)

今天你还是像往常一样来上班,一如既往地开始了你的编程工作。 项目经理告诉你,今天想在服务器端增加一个新功能,希望写一个方法,能对Book对象进行处理,将Book对象的所有字段以XML...

模板方法(template method)模式

模板(template method)方法模式 一、概述   生活中每个人都离不开吃,然而每个人吃的东西都可能不大相同;有的人可能每天只能吃包子馒头,而有的人却每日山珍海味。尽管吃的东西不一样,但...

模板方法模式【Template Method Pattern】

模板方法模式【Template Method Pattern】 周三,9:00,我刚刚坐到位置,打开电脑准备开始干活。 “小三,小三,叫一下其它同事,到会议室,开会”老大跑过来吼,带着淫笑。还不等...

Android设计模式之美---Template Method

先解释一下设计模式之美,美体现在哪里? 任何实现代码的方法都没有美丑之分,之后复杂与简单之分,人们喜欢简单的,害怕、厌烦、排斥复杂的。 设计模式之美就体现在可以把复杂的东西简单化,让人们用起来很简单,...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Template method vs Callback模式
举报原因:
原因补充:

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