状态模式、职责链模式、组合模式--三个例子(大话设计模式考)

输出的结果:

状态模式:

当前时间:9点, 上午工作,精神百倍

当前时间:10点, 上午工作,精神百倍
当前时间:12点 饿了, 午饭,犯困, 午休
当前时间: 13 点下午状态还不错,继续努力
当前时间: 14 点下午状态还不错,继续努力
当前时间17点,加班哦,疲惫之极
当前时间19点,加班哦,疲惫之极
当前时间:22点不行了,睡着了。

当前时间:22,点下班回家了。

职责链模式:


总经理:请详细说明情况!
总经理:病假 数量10 被总经理批准
总监:病假 数量5 被总监批准
经理:病假 数量1被经理批准
总经理:加薪 数量500 被总经理批准
总经理:加薪 数量600 总经理不批准!
总经理:不是请假,加薪申请,工作流程错误,一律不批准!
总经理:病假 数量5 被总经理批准


组合模式:

结构图
-北京总公司
---总公司人力资源部
---总公司财务部
---上海华东分公司
-----上海华东分公司人力资源部
-----上海华东分公司财务部
---南京办事处
-----南京办事处人力资源部
-----南京办事处财务部
---杭州办事处
-----杭州办事处人力资源部
-----杭州办事处财务部

职责
总公司人力资源部 员工招聘培训管理
总公司财务部 公司收支管理
上海华东分公司人力资源部 员工招聘培训管理
上海华东分公司财务部 公司收支管理
南京办事处人力资源部 员工招聘培训管理
南京办事处财务部 公司收支管理
杭州办事处人力资源部 员工招聘培训管理
杭州办事处财务部 公司收支管理



代码:

 主类:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace WinServerTest1
{
    public class IntoMain
    {

        public IntoMain()
        {
         
        }

        /// <summary>
        /// 状态模式
        /// </summary>
        public void StatePattern()
       {
           //执行开始
           Work happyproject = new Work();
           happyproject.Hour = 9;
           happyproject.WriteProgram();
           happyproject.Hour = 10;
           happyproject.WriteProgram();
           happyproject.Hour = 12;
           happyproject.WriteProgram();
           happyproject.Hour = 13;
           happyproject.WriteProgram();
           happyproject.Hour = 14;
           happyproject.WriteProgram();
           happyproject.Hour = 17;
           happyproject.WriteProgram();
           happyproject.TaskFinished = false;
           happyproject.Hour = 19;
           happyproject.WriteProgram();//并没有换状态。
           happyproject.Hour = 22;
           happyproject.WriteProgram();//换状态。
           Console.Read();
        }

        /// <summary>
        /// 职责链条模式
        /// </summary>
        public void ChainPattern()
        {
            //这里这么多请求,还可以做成事件的绑定方式。 当然不需要的话直接用LIST就可以,不要过度设计。


            CommonManager jinli = new CommonManager("经理");
            Majordomo zongjian = new Majordomo("总监");
            GeneralMananger zhongjingli = new GeneralMananger("总经理");

            jinli.SetSuperior(zongjian);
            zongjian.SetSuperior(zhongjingli);

            Request request = new Request();
            request.RequestType = "请假";
            request.RequestContent = "病假";
            request.Number = 100;
            jinli.RequestApplication(request); //所有流程构建后,从最初流程进入,并不知道具体管理负责的类。


            Request request1 = new Request();
            request1.RequestType = "请假";
            request1.RequestContent = "病假";
            request1.Number =10;
            jinli.RequestApplication(request1);


            Request request2 = new Request();
            request2.RequestType = "请假";
            request2.RequestContent = "病假";
            request2.Number = 5;
            jinli.RequestApplication(request2);

            Request request3 = new Request();
            request3.RequestType = "请假";
            request3.RequestContent = "病假";
            request3.Number = 1;
            jinli.RequestApplication(request3);


            Request request4 = new Request();
            request4.RequestType = "加薪";
            request4.RequestContent = "加薪";
            request4.Number = 500;
            jinli.RequestApplication(request4);


            Request request5 = new Request();
            request5.RequestType = "加薪";
            request5.RequestContent = "加薪";
            request5.Number = 600;
            jinli.RequestApplication(request5);

            Request request6 = new Request();
            request6.RequestType = "旅游";
            request6.RequestContent = "旅游";
            request6.Number = 7;
            jinli.RequestApplication(request6);


            //更改当前的工作流程, 请假工作直接走向新的特殊流程,请假5天,直接走总经理流程,跳过总监。

            jinli.SetSuperior(zhongjingli);
            jinli.RequestApplication(request2);//请假5天,本来总监能批准,但是他不批,于是直接找总经理。

            //问题1: 注意总经理的范围, 一开始是 >5 <10. 但是5到总经理那里就成了不能批准了,于是修改,改成0-10

            //问题2: 这种职责链条的维护比较麻烦,比如,我这个需要做单独的处理, 下面还有很多需要做正常的处理, 
            //        还需要再次重新绑定整个序列。 如果很多种形式,则很麻烦。 
            //        维护方式,做接入和去除工作。和链表一样。   
            //例如, 做删除总监操作。 则把总监的后指向赋给经理。 但是需要首先做好基础定义。 
            //     在需要还原的话,就把 做插入方法, 把经理的后指向(总经理)给总监,把经理的指向赋成总监。
            //     抽象类包装好此方法,将会好很多。  

            // 同时,单独需要的最好单独定义。 因为这种改动将会导致 链条混乱,除非有链条控制器。

            Console.Read();

        }

        /// <summary>
        /// 组合模式
        /// </summary>
        public void CombinePattern() 
        {
            ConcreteCompany root = new ConcreteCompany("北京总公司");
            root.Add(new HRDepartment("总公司人力资源部"));
            root.Add(new FinanceDepartment("总公司财务部"));

            ConcreteCompany comp = new ConcreteCompany("上海华东分公司");
            comp.Add(new HRDepartment("上海华东分公司人力资源部"));
            comp.Add(new FinanceDepartment("上海华东分公司财务部"));
            root.Add(comp);


            ConcreteCompany comp1 = new ConcreteCompany("南京办事处");
            comp1.Add(new HRDepartment("南京办事处人力资源部"));
            comp1.Add(new FinanceDepartment("南京办事处财务部"));
            root.Add(comp1);

            ConcreteCompany comp2 = new ConcreteCompany("杭州办事处");
            comp2.Add(new HRDepartment("杭州办事处人力资源部"));
            comp2.Add(new FinanceDepartment("杭州办事处财务部"));
            root.Add(comp2);

            Console.WriteLine("\n结构图");
            root.Display(1);
            Console.WriteLine("\n职责");
            root.LineOfDuty();
            Console.Read();
        }

    }
}

状态模式:StatePattern.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace WinServerTest1
{
    ///<!--状态模式实例-->

    #region 操作端
    /// <summary>
    /// 具体的工作对象,定义当前工作的属性与值, 利用State做状态对象。利用状态对象的参数传递WORK,针对此WORK做状态的切换。并且在切换中配置新的工作的属性与值,调用工作的状态执行方法。
    /// </summary>
    /// <remarks>
    /// 1.关于工作对象中的各种状态和属性以及记录操作等,都可以在Work类中加入,并在状态对象中调用WORK对象实现。
    /// 2.利用抽象类解耦,但是传递WORK对象也是一种耦合,这种耦合在面向对象中反而是必须的。就好像参数是object\int一样。
    /// 3.状态模式解除的是在WORK中出现非常多的状态判断的情况。
    /// </remarks>
    public class Work
    {

        private State current;//因为是抽象类,所以解耦,而且抽象类指明是父子关系。接口指规范行为。

        public Work() {

            current = new ForenoonState();//状态子类
        }

        /// <summary>
        /// 时间段
        /// </summary>
        private double hour;
        public double Hour {
            get { return hour; }
            set { hour = value; }
        }

       /// <summary>
       /// 任务--是否完成(整个工作流程)
       /// </summary>
        private bool finish = false;
        public bool TaskFinished 
        {
            get { return finish; }
            set { finish = value; }
        }


        public void SetState(State s)//声明,方便以后使用,其实利用WriteProgram就可以做好状态传递。但是如果要扩展职责链条,有必要做扩展。
        {
            current = s;//状态切换
        }


        public void WriteProgram() 
        {
            current.WriteProgram(this);//调用具体状态的State状态子类的方法。 传递WORK。
        }


    }

    public abstract class State
    {
        public abstract void WriteProgram(Work k);
    }


    public class ForenoonState : State 
    {

        public override void WriteProgram(Work w) 
        {
            if (w.Hour < 12)
            {
                Console.WriteLine("当前时间:{0}点, 上午工作,精神百倍",w.Hour);
            }
            else
            {
                w.SetState(new NoonState()); //按照指定顺序流程 调用WORK对象中的方法 更改下一个状态。
                 //也可以,在执行某个操作,通过操作判断是否进入下一个状态,还是结束。
                       //操作可以是多种 方法模块的不同组合,可以使用组合模式。
                //还可以针对每个状态做各自的职责链条。 这个等职责模式搞出来之后再合并。
                
                w.WriteProgram();
            }
        }
    }

    public class NoonState : State 
    {

        public override void WriteProgram(Work w)
        {

            if (w.Hour < 13) {
                Console.WriteLine("当前时间:{0}点 饿了, 午饭,犯困, 午休",w.Hour);
            }
            else
            {
                w.SetState(new AfternoonState());
                w.WriteProgram();
            }
        }
    }

    public class AfternoonState : State 
    {
        public override void WriteProgram(Work w)
        {
            if (w.Hour < 17)
            {
                Console.WriteLine("当前时间: {0} 点下午状态还不错,继续努力", w.Hour);
            }
            else 
            {
                w.SetState(new EventingState());
                w.WriteProgram();
            }
        }
    }

    public class EventingState : State 
    {//17-21

        public override void WriteProgram(Work w) 
        {
            //正常下班--客户端类中使用WORK对象,进行WORK对象的属性的更新。
            if (w.TaskFinished) {

                w.SetState(new RestState());
                w.WriteProgram();
            } else
            {//加班
                if (w.Hour < 21)
                {
                    Console.WriteLine("当前时间{0}点,加班哦,疲惫之极",w.Hour);
                }
                else
                {
                    w.SetState(new SleepingState());
                    w.WriteProgram();
                
                }
            
            }
        
        }
    }

    public class SleepingState : State 
    {
        public override void WriteProgram(Work w) 
        {
            Console.WriteLine("当前时间:{0}点不行了,睡着了。",w.Hour);//加班睡着
            w.TaskFinished = true;
            w.SetState(new EventingState()); //状态之间可以转向,但是主要不要做成环了就行了。 
            //通过改变WORK的属性,做操作。 如果WORK 的属性和标记更多,则可以在每个状态中做更多的控制。
            //不过:状态模式本身就是为了解除过多的状态判断,如果里面再次嵌套,是否再次进行状态模式,这个要仔细考虑。
            w.WriteProgram();
        }

    }

    public class RestState : State 
    {

        public override void WriteProgram(Work w) 
        {
            Console.WriteLine("当前时间:{0},点下班回家了。",w.Hour);
        }
    }

#endregion



#region 客户端

   //IntoMain
   // Execute()

#endregion

}

职责链模式:ChainPattern.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace WinServerTest1
{
    //请求信息, 也是向下传递的。
    public class Request 
    {
        //申请类型
        private string requestType;
        public string RequestType 
        {
            get { return requestType; }
            set { requestType = value; }
        }

       //申请内容
        private string requestContent;
        public string RequestContent 
        {
            get { return requestContent; }
            set { requestContent = value; }
        }

        //数量
        private int number;
        public int Number 
        {
            get { return number; }
            set { number = value; }
        }

    }


    /// <summary>
    /// 管理者抽象类。。 每个负责不同职责功能 工作流程的的链条。 
    /// </summary>
    public abstract class Manager 
    {
        protected string name;
        protected Manager superior;//向下的链条指向。  在部门中就是向上的领导。

        public Manager(string name) 
        {
            this.name = name;
        }

        public void SetSuperior(Manager superior) //更改向下链条。 与状态模式的WORK 不同的是, 本类做的是其他工作流的抽象父类定义。而WORK中状态改变非常频繁。
        {
            this.superior = superior;// 而这里基本是每个只定义一次。 利用Request的对象方法指向向下传递。
            //即,状态模式传递一个WORK。职责模式通过指向下一个链条做连状。 与WORK中不断变化的指向向下类似。

            //而,WORK中的状态改变是在具体的状态中指向下一条。 
            //链条模式是通过设置下一条直接做链接的改变。  可以在客户端控制。

            //从程序设计中,我的程序确实需要很多状态变化。 但是每一个判断之后有可能就是组合成一种新的链条顺序。
            //即,上一次需要某个环节, 本次不需要了。同是一个状态。 
            //这种情况, 我建议是 整体看做状态设计, 每个状态独立设计其不同判断下的链条组合。 链条走完了。可以走下一个状态。 

            //同样,因为状态的下次指向也无法确定,有可能从停电直接到结束。中间状态没有, 则状态也无法完全指定其下一个状态。
            //则可以对于状态抽象类做类似。
            //但是,状态模式主要是状态的分解。 职责模式主要是链条。  链条中的每个功能也有独立的,只是其切换是由链条控制的。 
            //请求信息也是向下传递的。不过不针对请求信息做 链条。 请求信息之做单独的封装数据传递。
            //而状态模式做状态改变。 其中是 包状态封装到其内部。 职责是把 此请求做为参数不停的通过链条传递。
            //只是侧重点不同, 其实request中如果封装做链条转换的方法,也可以使用。 当然这种使用是要切入 Manager 也就是
            //链条中的抽象父类,中的属性之间做碰撞,然后 利用 职责链对象 做下一个链条的转换。 
            //又因为,我的状态之间是可以替换的。所以做个结合。   状态中加入职责链条。 WORK继续传递,保持其状态转换的功能,
            //增加其状态指向的功能,具体状态中的数据打包成一个请求,然后进入此状态指定的请求链条, 做每一个操作。
            //这里状态指向,在状态模式中靠状态类做, 现在改成WORK做,则WORK就类似与一种链条。
            //链条其实可以改成状态模式, 比较是按照流程去做。这个思路确定,在具体实现中去构造把。
            //链条的好处就是可以客户端指定其上级。

            //批准,停止
            //状态也好, 职责链条也好,总是有停止,而且停止的位置也有可能不同,停止后则链条不再继续。
            //关于这个停止也要好好考虑考虑,其在状态中的停止代表不符合下一个状态进入的可能。
            //其在职责链条的停止,代表链条执行完成或者出现特殊故障。 一般来说,链条如果是按照模块来划分的功能,不是特别的契合
            //传递和职责覆盖结构, 拿来用就成了状态模式差不多的样子,要按流程走完。

            //鉴于上面的分析, 在状态的部分,做成状态模式和职责链模式的结合, 在具体状态下工作要执行的模块,利用组合模式。
              
            //为什么用组合模式, 因为在某个状态可以不去检测某种功能,而其他功能依然都是用,则各个状态都应该是小模块的组合。
            //这里的组合与真正的组合模式不同, 真正的组合模式是嵌套,不断嵌套,但是最初也是这种简单的叠加。其实算是基本的活字印刷术。
            //这样某个功能修改,改某一个类即可。
            //    某个功能删除添加,在指定状态下的组合中修改即可。
            
            //其状态改变也可以非常方面的修改指向。
        }

        abstract public void RequestApplication(Request request);
    
    }

    /// <summary>
    /// 经理类
    /// </summary>
    public class CommonManager : Manager 
    {
        public CommonManager(string name) :base(name)
        { 
        
        }

        public override void RequestApplication(Request request)//请求对象作为参数,传递
        {
            if (request.RequestType == "请假" && request.Number <= 2)//加入天数判断
            {
                Console.WriteLine("{0}:{1} 数量{2}被经理批准", name, request.RequestContent, request.Number);
            }
            else 
            { 
            
                 if(superior!=null)
                 {
                     superior.RequestApplication(request);//向下传递参数, 而在客户端已经设置本类的指向。
                 }
            }
        } 

    }

    /// <summary>
    /// 总监
    /// </summary>
    class Majordomo : Manager 
    {

        public Majordomo(string name) :base(name)
        { }

        public override void RequestApplication(Request request)
        {
            if (request.RequestType == "请假" && request.Number <= 5)//加入天数判断
            {
                Console.WriteLine("{0}:{1} 数量{2} 被总监批准", name, request.RequestContent, request.Number);
            }
            else 
            {

                if (superior != null) { superior.RequestApplication(request); }
            }
        }
    
    }

    //总经理
    class GeneralMananger : Manager 
    {
        public GeneralMananger(string name) : base(name) { }

        public override void RequestApplication(Request request)
        {

            switch (request.RequestType) 
            { 
                case "请假":
                    if (request.Number > 0 && request.Number<=10)
                        Console.WriteLine("{0}:{1} 数量{2} 被总经理批准", name, request.RequestContent, request.Number);
                    else
                        Console.WriteLine("总经理:请详细说明情况!", name, request.RequestContent, request.Number);
                        //if病孕特殊情况,批准,不批准。
                        //传递回个人,个人结束流程。。
                    break;

                case "加薪":
                    if ( request.Number <= 500)
                    {
                        Console.WriteLine("{0}:{1} 数量{2} 被总经理批准", name, request.RequestContent, request.Number);
                    }
                    else 
                    {
                        Console.WriteLine("{0}:{1} 数量{2} 总经理不批准!", name, request.RequestContent, request.Number);
                    }
                    break;
                default:
                    Console.WriteLine("总经理:不是请假,加薪申请,工作流程错误,一律不批准!", name, request.RequestContent, request.Number);
                    break;
            }
        }
    
    }







}


组合模式:CombinePattern.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace WinServerTest1
{
    /// <summary>
    /// 嵌套组合体现在抽象类中,分支类中叠加 抽象类。  即,实现抽象类、 根节点类、节点类3个类即可,其他的都是他们的组合。
    /// 组合的好处是一个方面调用,其子类中的各自的方法也都立即响应。 
    ///  对我来说,嵌套的东西很少。 但是可以把每个状态做成一个组合,一个组合中组合所有的功能模块,当然功能模块多是平行的。
    ///  至于嵌套可以先做出来,以后需要类似功能方便添加。
    /// </summary>
    public abstract class Company 
    {
        protected string name;
        public Company(string name) { this.name = name; }

        //不同的子类都实现不同

        public abstract void Add(Company com);//引用其子类,做组合嵌套使用
        public abstract void Remove(Company com);

        public abstract void Display(int depth);//显示
        public abstract void LineOfDuty();//执行职责

    }

    /// <summary>
    /// 具体公司类-- 树枝节点
    /// </summary>
    public class ConcreteCompany : Company
    {

        private List<Company> children = new List<Company>();
        public ConcreteCompany(string name) : base(name) { }

        public override void Add(Company com)
        {
          children.Add(com);
        
        }
        public override void Remove(Company com)
        {
          children.Remove(com);
        
        }

        /// <summary>
        /// 显示层次
        /// </summary>
        /// <param name="depth"></param>
        public override void Display(int depth) 
        {
            Console.WriteLine(new String('-',depth)+name);

            foreach(Company component in children) //这里 无法分辨是一个组合层次还是单组件。
            {
                component.Display(depth+2);// 但是利用这种层次+2,将每个组合向下逐渐  加两个字符。 嵌套的含义,非常的明显了。
            
            }
        
        }
        /// <summary>
        /// 履行职责
        /// </summary>
        public override void LineOfDuty()
        {
          foreach(Company component in children)
          {
              component.LineOfDuty();
          }

        }

    }


    class HRDepartment : Company
    {

        public HRDepartment(string name) : base(name) { }//继承抽象类的构造,否则可以自己写不同的构造函数。
        public override void Add(Company com)
        {
           
        }

        public override void Remove(Company com)
        {

        }

        public override void Display(int depth)
        {
            Console.WriteLine(new String('-',depth)+name);// 树叶与上面的树枝
        }

        public override void LineOfDuty()
        {
            Console.WriteLine("{0} 员工招聘培训管理",name);
        }
    
    }


    class FinanceDepartment : Company
    {

        public FinanceDepartment(string name) : base(name) { }
        public override void Add(Company com)
        {

        }

        public override void Remove(Company com)
        {

        }

        public override void Display(int depth)
        {
            Console.WriteLine(new String('-', depth) + name);// 树叶与上面的树枝
        }

        public override void LineOfDuty()
        {
            Console.WriteLine("{0} 公司收支管理", name);
        }

    }

}















你可能感兴趣的:(状态模式、职责链模式、组合模式--三个例子(大话设计模式考))