代码改变世界

职责链模式

2012-08-24 11:42  Mike.Jiang  阅读(599)  评论(0编辑  收藏  举报

1概述
    当一个请求,有多个处理对象时,如果硬编码指定某个由某个对象来处理,需要采用ifelse的结构,从而产生了代码的耦合,如果要添加新的请求处理对象或调整请求处理的次序,必然会修改同一个方法,违背开闭原则。

2 GOF中的定义
意图:  
使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。
结构图:

适用性:

1>有多个的对象可以处理一个请求,哪个对象处理该请求运行时刻自动确定。
2>你想在不明确指定接收者的情况下,向多个对象中的一个提交一个请求。
3>解耦ifelse,将处理对象组织一个链并希望处理的次序由客户端来定义;

3项目中的例子
在简单的审批处理中,经理与总经理有着不同的处理级别。比如,在请假审批中,经理可以批准3天的,而当要请假5天时需要总经理审批。在这里,我们定义请假3天的级别为3,请假5天的级别为5。
4紧耦合的实现
代码:

View Code
    public class Manager
    {
        public void HandelRequest(int levelDays)
        {
            if (levelDays <= 3) 
            {
                Console.WriteLine("经理处理请假");
            }
            else 
            {
                Console.WriteLine("总经理处理请假");
            }
        }
    }
        static void Main(string[] args)
        {
            Manager manager = new Manager();
            manager.HandelRequest(4);
            Console.Read();
        }

说明:在这里,不同的请求处理对象耦合在ifelse分支中,当新修改、添加新的请求处理对象,或要调整请求处理次序时,都要修改Manager的HandelRequest方法,很明显违背了开闭、单一职责原则。

5松耦合的实现
代码:

View Code
    /// <summary>
    /// 处理请求对象的基类
    /// </summary>
    public abstract class Manager
    {
        /// <summary>
        /// 维护一个指向下一个请求处理对象的引用
        /// </summary>
        protected Manager nextHander;

        public void SetNextHander(Manager manager) 
        {
            this.nextHander = manager;
        }

        /// <summary>
        /// 请求处理方法,由子类实现
        /// </summary>
        /// <param name="reqLevel"></param>
        public abstract void HandelRequest(int reqLevel);
    }

    /// <summary>
    /// 经理
    /// </summary>
    public class NomalManager:Manager
    {
        public override void HandelRequest(int reqLevel)
        {
            if (reqLevel <= 3) 
            {
                Console.WriteLine("{0}:同意请假", this.GetType().Name);
            }
            else if (nextHander != null)
            {
                nextHander.HandelRequest(reqLevel);
            }
        }
    }

    /// <summary>
    /// 总经理
    /// </summary>
    public class GeneralManager:Manager
    {
        public override void HandelRequest(int reqLevel)
        {
            if (reqLevel > 3)
            {
                Console.WriteLine("{0}:同意请假", this.GetType().Name);
            }
            else if (nextHander != null)
            {
                nextHander.HandelRequest(reqLevel);
            }
        }
    }

        static void Main(string[] args)
        {
            Manager normalManager = new NomalManager();
            Manager generalManager = new GeneralManager();
            normalManager.SetNextHander(generalManager);
            normalManager.HandelRequest(3);
            normalManager.HandelRequest(4);
            Console.Read();
        }

说明:在这里,将不同的请求处理行为抽象成类,然后将这些类构成一个链式结构(此时链的前后关系由客户端定义,提高了灵活性)。当有请求时,只需要调用处理链中的第一个就可以完成各种请求,不需要将某个请求与具体的处理对象关联了。

6总结
职责链模式解决的是将ifelse解耦,但它与策略模式不同,它将行为对象组织成一个链式结构来处理请求,一步步向后处理。很明显这样做会浪费一些性能,如加载了一些不会用的到类(因为只有一个对对象才会处理某个请求),另外如果请求只有最后一个才能处理,要经过之前的层层判断才会至最后一个。但是在一些业务系统中,这样的做会更加容易理解与维护。