博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
状态模式、职责链模式、组合模式--三个例子(大话设计模式考)
阅读量:6248 次
发布时间:2019-06-22

本文共 17415 字,大约阅读时间需要 58 分钟。

hot3.png

输出的结果:

状态模式:

当前时间: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()        {                 }        ///         /// 状态模式        ///         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();        }        ///         /// 职责链条模式        ///         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();        }        ///         /// 组合模式        ///         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 操作端 /// /// 具体的工作对象,定义当前工作的属性与值, 利用State做状态对象。利用状态对象的参数传递WORK,针对此WORK做状态的切换。并且在切换中配置新的工作的属性与值,调用工作的状态执行方法。 /// ///
/// 1.关于工作对象中的各种状态和属性以及记录操作等,都可以在Work类中加入,并在状态对象中调用WORK对象实现。 /// 2.利用抽象类解耦,但是传递WORK对象也是一种耦合,这种耦合在面向对象中反而是必须的。就好像参数是object\int一样。 /// 3.状态模式解除的是在WORK中出现非常多的状态判断的情况。 ///
public class Work { private State current;//因为是抽象类,所以解耦,而且抽象类指明是父子关系。接口指规范行为。 public Work() { current = new ForenoonState();//状态子类 } /// /// 时间段 /// private double hour; public double Hour { get { return hour; } set { hour = value; } } /// /// 任务--是否完成(整个工作流程) /// 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; }        }    }    ///     /// 管理者抽象类。。 每个负责不同职责功能 工作流程的的链条。     ///     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);        }    ///     /// 经理类    ///     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);//向下传递参数, 而在客户端已经设置本类的指向。                 }            }        }     }    ///     /// 总监    ///     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{    ///     /// 嵌套组合体现在抽象类中,分支类中叠加 抽象类。  即,实现抽象类、 根节点类、节点类3个类即可,其他的都是他们的组合。    /// 组合的好处是一个方面调用,其子类中的各自的方法也都立即响应。     ///  对我来说,嵌套的东西很少。 但是可以把每个状态做成一个组合,一个组合中组合所有的功能模块,当然功能模块多是平行的。    ///  至于嵌套可以先做出来,以后需要类似功能方便添加。    ///     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();//执行职责    }    ///     /// 具体公司类-- 树枝节点    ///     public class ConcreteCompany : Company    {        private List
children = new List
(); public ConcreteCompany(string name) : base(name) { } public override void Add(Company com) { children.Add(com); } public override void Remove(Company com) { children.Remove(com); } ///
/// 显示层次 /// ///
public override void Display(int depth) { Console.WriteLine(new String('-',depth)+name); foreach(Company component in children) //这里 无法分辨是一个组合层次还是单组件。 { component.Display(depth+2);// 但是利用这种层次+2,将每个组合向下逐渐 加两个字符。 嵌套的含义,非常的明显了。 } } ///
/// 履行职责 /// 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); } }}

转载于:https://my.oschina.net/mahaisong/blog/160786

你可能感兴趣的文章
sublime text ctrl+b
查看>>
时间复杂度几个概念
查看>>
poj 1273 Drainage Ditches(最大流入门)
查看>>
for语句
查看>>
网页总结
查看>>
我用过的那些电脑 -- 致逝去的美好时光
查看>>
SQLiteOpenHelper学习
查看>>
Tomcat路径下目录的介绍
查看>>
TopCoder SRM 628 DIV 2
查看>>
实验吧_简单的sql注入_1、2、3
查看>>
BZOJ3779重组病毒LCT
查看>>
T-SQL (一)
查看>>
词法分析
查看>>
安装laravel框架
查看>>
Linux 目录结构
查看>>
第二次实验
查看>>
R中,求五数,最小值、下四分位数、中位数、上四分位数、最大值
查看>>
【python-Day3】
查看>>
接上一篇——上海有哪些值得加入的互联网公司
查看>>
VFS相关内容
查看>>