代码改变世界

责任链模式在网站参数传递、存取的应用

2012-11-26 16:05  soothing  阅读(499)  评论(0编辑  收藏  举报

     当前门户存在很多参数传递的情况,如浏览器客户端参数中的dn、fr、jb,还有一些公共参数如sid、channelcode等,这些参数从源头获取后,都会保存在cookie、session或者mc。这样一来,业务获取这些参数时就存在多种来源,这次获取都要对这些来源做一次轮询。比如dn参数,就存在着一下轮询操作:
1 从session获取,有值返回,无值进行下一步
2 从cookie获取,有值返回,无值进行下一步
3 从uc_param_str获取,有值返回,无值进行下一步
4 从uccPara获取,返回值(可能仍然为null)
我们将伪代码转换成java代码.

 

    public static String getDn(){
        String dn = "";
        
        if(Http.Request.current().cookies.containsKey("dn")){
            dn = Http.Request.current().cookies.get("dn").value;
        }else if(Scope.Session.current().contains("dn")){
            dn = Scope.Session.current().get("dn");            
        }else if(Http.Request.current().params._contains("dn")){
            dn = Http.Request.current().params.get("dn");
        }else if(Http.Request.current().headers.containsKey("dn")){
            dn = Http.Request.current().headers.get("dn").value();
        }
        
        return dn;
    }

 

      上述只是一个简化的逻辑,实际情况比这更为复杂,可以看出,代码存在很多if...else...的判断,如果这套逻辑应用于客户端二十多个参数和其他公共参数,整个代码看起来就显得相当臃肿。那有什么办法可以简化这些逻辑呢?何不尝试一下“责任链模式”...

      我们先看一下阎宏博士在《JAVA与模式》一书中对责任链模式的描述:

      责任链模式是一种对象的行为模式。在责任链模式里,很多对象由每一个对象对其下家的引用而连接起来形成一条链。请求在这个链上传递,直到链上的某一个对象决定处理此请求。发出这个请求的客户端并不知道链上的哪一个对象最终处理这个请求,这使得系统可以在不影响客户端的情况下动态地重新组织和分配责任。

     如果我们把cookie、session、uc_param_str、uccpara看做是一个个存储节点,并将这些节点组成一条有向无回路的责任链:

                                        图 1

   这个责任链实现之后,作为业务方,完全可以把这个模式看做一个黑盒子,只需传递一个"name"参数,就可以轻松取得“value”。

   我们观察一下这个链条,发现每个节点都有两个任务:

   1 指定下一个节点

   2 处理客户端请求

   自然而然,我们可以把这些节点抽象一个接口:StoreChain:

 

public interface StoreChain {
    public abstract void setNext(StoreChain nextInChain);
    public abstract String getValue(String name);
}

 

    责任链上各节点都继承了StoreChain接口。

    CookieChain:

public class CookieChain implements StoreChain{
    private StoreChain nextInChain;
    @Override
    public void setNext(StoreChain nextInChain) {
        this.nextInChain = nextInChain;
    }

    @Override
    public String getValue(String name) {
        String value = null;
        if(Http.Request.current().cookies.containsKey(name)){
            value = Http.Request.current().cookies.get(name).value;
        }
        if(value == null&&nextInChain!=null){
            nextInChain.getValue(name);
        }
        return value;
    }
}

       在处理客户单请求的时候,判断下一个节点:nextInChain 是否为空是很有必要的。因为我们设计的链条不是回路的,也就是你不知道当前的节点是否是最后一个,如果是,当nextInChain为空,再引用其他方法,就会引发空引用的错误。

SessionChain:

public class SessionChain implements StoreChain {
    private StoreChain nextInChian;
    @Override
    public void setNext(StoreChain nextInChain) {
        this.nextInChian = nextInChain;
    }

    @Override
    public String getValue(String name) {
        String value = Scope.Session.current().get(name);
        if(value == null&&nextInChian!=null){
            nextInChian.getValue(name);
        }
        return value;
    }
}

由于客户端访问带uc_param_str的链接后,会将uc_param_str后的参数机型解析,并以参数的形式请求服务器,如客户端访问

http://{host}/index.html?uc_param_str=dnfrjb,经过解析之后,实际请求服务器的链接是:

http://{host}/index.html?uc_param_str=dnfrjb&dn=1234565_1234&fr=android&jb=0,因此我们可以后台轻松地以request方法获得参数值。

UcParamStrChain:

public class UcParamChain implements StoreChain{
    private StoreChain nextInChain;
    @Override
    public void setNext(StoreChain nextInChain) {
        this.nextInChain = nextInChain;
    }

    @Override
    public String getValue(String name) {
        String value = Http.Request.current().params.get(name);
        if(value == null&&nextInChain!=null){
            nextInChain.getValue(name);
        }
        return value;
    }
}

UccParaChain:

public class UccParaChain implements StoreChain{
    private StoreChain nextInChain;
    @Override
    public void setNext(StoreChain nextInChain) {
        this.nextInChain = nextInChain;
    }

    @Override
    public String getValue(String name) {
        Map<String, String> uccPara = UcUtil.setUccPara();
        String value = null;
        if(uccPara.containsKey(name)){
            value = uccPara.get(name);
        }
        if(value == null&&nextInChain!=null){
            nextInChain.getValue(name);
        }
        return value;
    }
}

       到此,各个责任链的节点就出来了,那业务该如何调用呢?我们实现的只是责任链一个个孤立的节点,还没形成“链”。我们就按图 1 的设计方式组织成链:

    private static StoreChain cookieChain = new CookieChain();
    private static StoreChain sessionChain = new SessionChain();
    private  static StoreChain ucgcParamStrChain= new UcgcParamStrChain();
    private static StoreChain uccParaChain = new UccParaChain();
    static {
        cookieChain.setNext(sessionChain);
        sessionChain.setNext(ucgcParamStrChain);
        ucgcParamStrChain.setNext(uccParaChain);
    }

现在我们可以对比一下,获取参数的方式前后有什么变化:

    public static String getDn(){
        return cookieChain.getValue("dn");
    }

获取fr值:

public static String getFr(){
     return cookieChain.getValue("fr");  
}

  3行代码,简洁明了。依此类推,客户端二十来个参数都可以通过这种方式轻松获取,不用什么if...else...的判断。