我在《软件设计精要与模式》第19章中介绍了职责链模式在实际项目中的应用,由于引入了该模式,使得对象在职责划分上有了更清晰的结构,然而由于项目场景的诸多限制,总有几分“为模式而模式”的生涩感觉。最近在开发WCF的相关项目时,又一次应用了职责链模式,一方面加深了自己对设计模式的进一步理解,也积累了一些心得,可以与各位分享。
 
在该项目中,我希望实现对Endpoint的合法性检验,其中对于绑定而言,则包含了许多约束,例如绑定与URI样式的约束,例如绑定与服务契约设计的约束。绑定不同,则向对应的约束也不相同。为了更好地体现Endpoint,我在项目中定义了属于自己的Endpoint类:

    public class ServiceEndpoint
    {
        public Uri Address
        {
            get;
            set;
        }

        public Binding Binding
        {
            get;
            set;
        }

        public Type ContractType
        {
            get;
            set;
        }
    }

如果考虑最简单的实现方式,我们完全可以通过分支语句,判断不同的绑定类型,然后执行对绑定约束的检查,例如:

public class BindingConstraint

{

public bool Constraint(ServiceEndpoint endpoint)

{

bool flag = false;

switch (endpoint.Binding.Name)

{

case "BasicHttpBinding":

//check the BasicHttpBinding;

flag = true;

break;

case "NetTcpBinding":

//check the NetTcpBinding;

break;

case "NetPeerTcpBinding":

//check the NetPeerTcpBinding;

break;

//...Other bindings' constraint;

}

return flag;

}

}

这是一个合适的设计,无可厚非。然而,我们所面临的关于绑定的约束性检查,远非几行代码就可以实现。例如,对于WSDualHttpBinding绑定而言,我们就需要判断传递进来的契约类型是否具有回调契约。当然,我们可以分别将这些约束性检查放入到专门的方法,甚至是专门的类中,但不可避免的是,我们会让Constraint方法的switch语句变得越来越长。
 
这还不是关键的,最主要的是我们需要检查的绑定存在扩展的可能,因为除了WCF自身提供的绑定类型之外,我们还可以提供CustomBinding或其它自定义绑定,一旦可能增加绑定,就需要修改这里的Constraint()方法。这样的设计就难免捉襟见肘了。事实上,在.NET Framework 3.5中,微软就为WCF新增加了几个绑定,例如WebHttpBinding。
 
此时,我们就可以考虑采用职责链模式,由于我们是针对绑定类型进行约束性检查,我们可以为每个绑定类型定义一个约束对象,然后对其进行抽象,设计类图如下所示:

首先,我们需要定义一个基类BindingConstraint,如下所示:

    public abstract class BindingConstraint//:IEndpointConstraint
    {
        protected fields#region protected fields

        protected BindingConstraint m_bindingConstraint;
        protected bool m_hasNextConstraint = false;        

        #endregion

        public methods#region public methods

        public void AddConstraint(BindingConstraint constraint)
        {
            m_bindingConstraint = constraint;
            m_hasNextConstraint = true;
        }

        #endregion        

        public abstract methods#region public abstract methods

        public abstract bool Constraint(ServiceEndpoint endpoint);

        #endregion

    }

这是一个抽象类,包含了两个protected字段,其中m_bindingConstraint即形成职责链的关键,通过AddConstraint()方法可以将BindingConstraint对象加入到职责链中,而字段m_hasNextConstraint则用来标识当前对象之下是否还存在BindingConstraint对象。抽象方法Constraint()则实现约束性检查的业务逻辑,同时还包括对职责链是否存在下一个职责对象的判断。例如BasicHttpBindingConstraint的定义如下:

    public class BasicHttpBindingConstraint:BindingConstraint
    {
        public override bool Constraint(ServiceEndpoint endpoint)
        {
            if (endpoint.Binding.Name == "BasicHttpBinding")
            {
                //check BasicHttpBinding Constraint;
                BasicHttpBinding binding = endpoint.Binding as BasicHttpBinding;
                //...

                //check binding and address's scheme                if (endpoint.Address.Scheme.ToLower() != "http" && endpoint.Address.Scheme.ToLower() != "https")
                {
                    throw new BindingConstraintException("the binding is mismatch with address schema.");
                }                

                return true;
            }
            else
            {
                if (m_hasNextConstraint)
                {
                    return m_bindingConstraint.Constraint(endpoint);
                }
                else
                {
                    return false;
                }
            }
        }
    }

根据传入的endpoint对象,判断绑定的名称是否为"BasicHttpBinding",如果是,则执行该约束对象的约束性检查,如果不是,则去寻找职责链中的其它对象(根据m_hasNextConstraint判断)。正是通过这样的实现方式,当客户端调用BindingConstraint的Constraint()方法时,就可以根据传入的ServiceEndpoint对象,智能地找到符合自己条件的BindingConstraint对象,并执行Constraint()方法进行约束性检查。
 
在我的《软件设计精要与模式》一书中,在应用职责链模式时,我的建议是最好提供专门创建职责链的工厂类,在本例中自然也不例外:

    public class BindingConstraintFactory
    {
        public static BindingConstraint CreateConstraint()
        {
            BindingConstraint basicHttp = new BasicHttpBindingConstraint();
            BindingConstraint netTcp = new NetTcpBindingConstraint();
            BindingConstraint netPeerTcp = new NetPeerTcpBindingConstraint();
            BindingConstraint netNamedPipe = new NetNamedPipeBindingConstraint();
            BindingConstraint wsHttp = new WSHttpBindingConstraint();
            BindingConstraint wsFederationHttp = new WSFederationHttpBindingConstraint();
            BindingConstraint wsDualHttp = new WSDualHttpBindingConstraint();
            BindingConstraint netMsmq = new NetMsmqBindingConstraint();
            BindingConstraint msmqIntegration = new MsmqIntegrationBindingConstraint();

            netMsmq.AddConstraint(msmqIntegration);
            wsDualHttp.AddConstraint(netMsmq);
            wsFederationHttp.AddConstraint(wsDualHttp);
            wsHttp.AddConstraint(wsFederationHttp);
            netNamedPipe.AddConstraint(wsHttp);
            netPeerTcp.AddConstraint(netNamedPipe);
            netTcp.AddConstraint(netPeerTcp);
            basicHttp.AddConstraint(netTcp);

            return basicHttp;
        }
    }

通过CreateConstraint()方法,就可以像穿珠子一般,形成一条隐藏的职责链(在创建这样的职责链时,需要注意职责对象的先后次序),然后在客户端代码中,可以非常优雅的实现对绑定的约束性检查:

private static BindingConstraint m_bindingConstraint = BindingConstraintFactory.CreateConstraint();

public void AddServiceEndpoint(ServiceEndpoint endpoint)

{

if (m_bindingConstraint.Constraint(endpoint))

{

m_endpointsList.Add(endpoint);

}

}

不管传入的endpoint是何种类型的绑定,只要在职责链中创建了相对应的绑定约束对象,都可以进行约束性检查,且逻辑清楚,职责明确。如果对绑定进行了扩展,我们只需要新增对应的绑定约束对象,然后修改BindingConstraintFactory工厂类的工厂方法即可。
 
使用职责链模式必须恰到好处,否则会成为模式滥用的反面教材。根据我对职责链模式的理解,可以认定只要同时符合下列三个条件,就可以引入职责链模式:
1、当一个方法的传入参数将成为分支语句的判断条件时;
2、当每一个分支的职责相对独立,且逻辑较为复杂时;
3、当分支条件存在扩展的可能时。
 
至于职责链模式的最佳实践,则包含以下内容:
1、应尽量将职责链模式的抽象定义为抽象类,而不要定义为接口。这样有利于一些公共逻辑的重用。
2、应在实现职责链模式的同时,提供创建职责链的工厂类。

转载于:https://www.cnblogs.com/zhuawang/archive/2011/09/25/2190413.html

职责链模式在开发中的应用相关推荐

  1. 策略模式和职责链模式在CMS中的应用

    最近在做一个轻量级CMS供客户站点使用. 根据客户的需求,需要以静态页方式提供用户浏览的页面,同时还要保留一个本份,支持"双远程"发布,即在一台远程发布服务器上保留存根,最终页面保 ...

  2. 餐馆的故事-浅析职责链模式

    我们在餐馆吃饭的时候,一般都是在拿到菜单后,选择喜欢的菜,然后通知服务员.服务员会将我们的定单交给大厨,大厨可能会亲自去做这道菜,也可能安排给小厨来做,总之,我们不用担心他们没有人做菜,即使有时候等的 ...

  3. java 职责链模式_Java中的责任链模式

    java 职责链模式 当应有几个处理器来执行某项操作并为这些处理器定义特定顺序时,就需要采用责任链设计模式. 在运行时处理器顺序的可变性也很重要.模式的UML表示如下: 处理程序定义处理器对象的一般结 ...

  4. 职责链模式里面必须要知道的事情

    为什么80%的码农都做不了架构师?>>>    职责链模式里面必须要知道的事情 用java web开发的很多同学很容易沉迷于各种框架的使用技巧,而忽略servlet的一些细节.对很多 ...

  5. 漫画设计模式:什么是 “职责链模式” ?

    作者 | 小灰 来源 | 程序员小灰(ID:chengxuyuanxiaohui) -----  第二天  ----- ------------ 在一家公司里,有三个程序员,他们的名字分别是小A.小B ...

  6. 使用职责链模式来重构你的代码

    在这里我们先想象一个场景,假设我们是一个售卖手机的网站,前期出过500到200的定金活动,现在已经进入正式购买阶段.已经支付过 500 元定金的用户会收到 100 元的商城优惠券,200 元定金的用户 ...

  7. 趣谈设计模式 | 职责链模式(ChainOfResposibility):请求的转发处理

    文章目录 案例:企业信息处理 职责链模式 总结 完整代码与文档 案例:企业信息处理 对于一个企业来说,每天难免的要收到大量的信息,有求职者发送过来的简历.其他公司的商务合作信息.又或者是和一些企业或客 ...

  8. 请求的链式处理——职责链模式

    本文转载自 :http://blog.csdn.net/lovelion/article/details/7420891 "一对二","过","过&q ...

  9. JS设计模式五:职责链模式

    职责链模式简述 职责连是由多个不同的对象组成的,有发送者跟接收者,分别负责信息的发送跟接收,其中,链中第一个对象是 职责连是由多个不同的对象组成的,发送者是发送请求的对象,接收者接收请求并且对其进行处 ...

最新文章

  1. Vmware虚拟机的复制后无法使用的问题和解决
  2. Raman Kazhamiakin
  3. setsockopt
  4. C++拷贝构造函数的调用时机
  5. JAVA入门级教学之(方法-题-3)
  6. 礼物gift(DP)
  7. pom.xml中出现错误提示Failure to transfer org.jboss.weld.jar ...  maven2 was cached in the local repository.
  8. OPEN SQL中通配符的使用
  9. vue中的watch监听
  10. linux下罗技摄像头采集图片,linux下寻找罗技摄像头快看酷讯版驱动
  11. 翁凯C语言程序设计期末考试
  12. 全国计算机能力挑战赛含金量高吗,大学里,有哪些含金量高,又容易得奖的国家级比赛?...
  13. mqtt协议 阿里云物联网平台
  14. “十三五”电力科技重大发展方向及关键技术
  15. 移动端隐藏scroll滚动条::-webkit-scrollbar
  16. Linux之文件/目录搜索
  17. 魔兽世界,你不是一个人
  18. Linux软件集成开发环境
  19. nginx空白图片 访问打点
  20. C语言用数组实现十个国家名字按字典排序

热门文章

  1. python爬虫怎么挣钱_买不到口罩怎么办?Python爬虫帮你时刻盯着自动下单!| 原力计划...
  2. vue 获取数组索引_获取某个数组元素 在 数组中的索引
  3. dategurd oracle_Oracle之11g DataGuard
  4. 怎么看电脑系统是win几_做设计,用win系统 还是苹果MAC电脑更好 (PS举例)
  5. Linux 环境下NFS服务安装及配置
  6. Java中junit单元测试
  7. scrapy自定义Request的缓存策略(减少内存占用)
  8. dropout为什么有效
  9. 吴恩达深度学习5.2笔记_Sequence Models_自然语言处理与词嵌入
  10. FTP服务器管理和配置