`
foo
  • 浏览: 25242 次
  • 来自: 北京
最近访客 更多访客>>
文章分类
社区版块
存档分类
最新评论

设计模式系列-命令模式

阅读更多

新的一年的春天到啦,又是一轮跳槽离职的高峰期,面对新的一年的开始大家都希望各个方面都在更上一层楼,难免会出现跳槽、离职创业等等现象,最近项目组有人离职啦,当然人走了活还是要有人干的嘛,如何合理的利用有限的人力资源把多余的活分配出去呢?这就是项目经理们考虑的事情啦!不过一般还是会出现一个开发人员同时兼有几个项目的现象啦~!OK,这个就是今天的场景,我们来用代码模拟一下吧!

        1.场景模拟

        首先我们考虑,当项目多,人手不够时,我们需要一个人去同时兼有好几个项目的工作,可能有开发也可能有运维!

        那么第一步我们先设计一个项目类,分别代表需要参与的项目,代码如下:

    /// <summary>
    
/// Web项目类
    
/// </summary>
    public class WebProject
    {
        /// <summary>
        
/// 项目名称
        
/// </summary>
        public string ProjectName { getset; }
    }

         接下来第二步,我们设计一个开发者类表示具体的开发人员,并且开发人员具有开发项目和运维项目的操作,代码如下:

    /// <summary>
    
/// 开发者
    
/// </summary>
    public class Developer
    {
        /// <summary>
        
/// 开发项目
        
/// </summary>
        
/// <param name="project">项目</param>
        public void Coding(WebProject project)
        {
            Console.WriteLine("开发{0}项目",project.ProjectName);
        }

        /// <summary>
        
/// 运维项目
        
/// </summary>
        
/// <param name="project">项目</param>
        public void UpdateRoutine(WebProject project)
        {
            Console.WriteLine("维护{0}项目", project.ProjectName);
        }
    }

        主函数调用方法如下:

    static void Main(string[] args)
    {
            //表示一个具体的项目名字叫:项目A
            WebProject wpA = new WebProject() { ProjectName = "项目A" };
            //表示一个具体的项目名字叫:项目B
            WebProject wpB = new WebProject() { ProjectName = "项目B" };

            //实例化一个开发者,程序员
            Developer dp = new Developer();

            //命令他开发项目A
            dp.Coding(wpA);
            //命令他开发项目B
            dp.UpdateRoutine(wpB);
    }

        这么简单的程序运行结果我就不贴出来啦,我们来看看上边的代码,我们把主函数的调用当做客户,我们发现如果客户直接和开发者形成这种紧耦合的状态是非常不好的,比如说,客户会提出很多业务上的要求,而开发者并不能很准确的估算出开发成本与时间,所以我们需要一个项目经理来与客户沟通,并且将客户提出的不合理需求过滤掉,在给开发人员发出一个命令将项目交给开发人员!也就是说需要将“命令发起者”与“命令实现者”分离!

        2.命令模式

         那么我们来看看实现“命令发起者”与“命令实现者”分离的设计模式,命令模式:

         命令模式:将一个请求封装为一个对象,从而可用不同的的请求对客户进行参数化,队请求排队或者记录请求日志,以及支持可撤销的操作。

         命令模式结构图如下:

      

       ①接口ICommand:用来声明抽象一个命令操作的接口。

       ②ConcreteCommand:具体的命令实现,用来表示命令的类型例如上边场景中的开发项目和维护项目可分别实现为:开发项目命令,维护项目命令等。

       ③Receiver:具体命令的实现者,也就是说命令的执行者,相对于上边场景中的开发者。

       ④Invoker:命令的指挥者,用来设置命令,并且通知执行命令,相对于上边场景中的项目经理。

       了解完命令模式的概念后,我们用命令模式来实现上边的场景:

        首先是命令接口ICommand的实现,代码如下:

    public interface ICommand
    {
        void Excute(WebProject project);
    }

        接下来就是我们接受命令并且执行的实现者啦,也就是我们场景中的开发者,代码如下:

    /// <summary>
    
/// 开发者
    
/// </summary>
    public class Developer
    {
        /// <summary>
        
/// 开发项目
        
/// </summary>
        
/// <param name="project">项目</param>
        public void Coding(WebProject project)
        {
            Console.WriteLine("开发{0}项目", project.ProjectName);
        }

        /// <summary>
        
/// 运维项目
        
/// </summary>
        
/// <param name="project">项目</param>
        public void UpdateRoutine(WebProject project)
        {
            Console.WriteLine("维护{0}项目", project.ProjectName);
        }
    }

       现在有了命令的实现者,就应该有具体的命令啦,上边那场景中的命令分别有,开发命令与维护命令,具体代码如下:

  /// <summary>
    
/// 开发项目命令
    
/// </summary>
    public class CodingCommand : ICommand
    {
        Developer dp { getset; }
        public WebProject project { getset; }//所对应的项目

        public void Excute()
        {
            dp.Coding(project);
        }
    }

    /// <summary>
    
/// 维护项目命令
    
/// </summary>
    public class UpdateRoutineCommand : ICommand
    {
        Developer dp { getset; }
        public WebProject project { getset; }//所对应的项目

        public void Excute()
        {
            dp.UpdateRoutine(project);
        }
    }

       命令与实现者都就绪了,指挥调度者就该出现了,也就是项目经理,项目经理用来负责设置命令调度命令执行,代码如下:

    /// <summary>
    
/// 项目经理类
    
/// </summary>
    public class ProjectManager
    {
        List<ICommand> cmdList = new List<ICommand>();

        /// <summary>
        
/// 设置命令
        
/// </summary>
        
/// <param name="cmd"></param>
        public void SetCommand(ICommand cmd)
        {
            cmdList.Add(cmd);
        }

        /// <summary>
        
/// 发起命令
        
/// </summary>
        public void ExcuteCommand()
        {
            cmdList.ForEach(p => p.Excute());
        }
    }

       代码写好后,我们来模拟一下调用吧,现在项目经理需要分配给开发者两个任务,一个是开发项目A,另一个是维护项目B!主函数调用如下:

            //表示一个具体的项目名字叫:项目A
            WebProject wpA = new WebProject() { ProjectName = "项目A" };
            //表示一个具体的项目名字叫:项目B
            WebProject wpB = new WebProject() { ProjectName = "项目B" };
            //开发者
            Developer developer= new Developer();

            //开发者所需要接收的命令
            ICommand codeCmd = new CodingCommand() { project = wpA, dp = developer };
            ICommand UpdateCmd = new UpdateRoutineCommand() { project = wpB, dp = developer };

            //项目经理
            ProjectManager pm = new ProjectManager();
            //设置命令
            pm.SetCommand(codeCmd);
            pm.SetCommand(UpdateCmd);
            //发起命令让开发者去完成
            pm.ExcuteCommand();
}

       那么一个简单的命令模式就完成了。

      3.更加灵活的分配任务

       接下来我们在增加一些要求:

       ①项目经理每次发起的命令都需要记录下来,年底好根据开发者的工作量评估奖金。

       ②项目经理可以撤销发起的命令,例如:撤销维护项目B的命令,让开发者专心做项目A的开发工作。

       回顾下命令模式的定义,上边两条需求就等同于定义中的“队请求排队或者记录请求日志,以及支持可撤销的操作

       那么我们给需求中加入一个方法用来撤销命令,因为项目经理类中已经有一个集合来记录命令的总数了,所以已经实现了请求记录的功能啦,我们只需加入撤销功能就好了。

       首先,给ICommand接口加入一个Cancel方法,用来表示撤销操作,因为命令撤销了需要通知实现者做一些撤销的工作,代码如下:

    public interface ICommand
    {
        void Excute();
        void Cancel();
    }

      接下来既然有取消了,那么开发者受到取消命令后要执行一些关于取消的代码,所以开发者类加入一个方法StopCoding,表示停止项目的工作,代码如下:

  /// <summary>
    
/// 开发者
    
/// </summary>
    public class Developer
    {
        /// <summary>
        
/// 开发项目
        
/// </summary>
        
/// <param name="project">项目</param>
        public void Coding(WebProject project)
        {
            Console.WriteLine("开发{0}项目", project.ProjectName);
        }

        /// <summary>
        
/// 运维项目
        
/// </summary>
        
/// <param name="project">项目</param>
        public void UpdateRoutine(WebProject project)
        {
            Console.WriteLine("维护{0}项目", project.ProjectName);
        }

        /// <summary>
        
/// 停止项目的工作
        
/// </summary>
        
/// <param name="project"></param>
        public void StopCoding(WebProject project)
        {
            Console.WriteLine("停止{0}项目",project.ProjectName);
        }
    }

      修改实际的命令类实现撤销命令的方法,并调用开发者类的StopCoding方法做撤销命令的工作,代码如下:

/// <summary>
    
/// 开发项目命令
    
/// </summary>
    public class CodingCommand : ICommand
    {
        public Developer dp { getset; }
        public WebProject project { getset; }//所对应的项目

        public void Excute()
        {
            dp.Coding(project);
        }

        /// <summary>
        
/// 撤销操作
        
/// </summary>
        public void Cancel()
        {
            dp.StopCoding(project);
        }
    }

    /// <summary>
    
/// 维护项目命令
    
/// </summary>
    public class UpdateRoutineCommand : ICommand
    {
        public Developer dp { getset; }
        public WebProject project { getset; }//所对应的项目

        public void Excute()
        {
            dp.UpdateRoutine(project);
        }

        /// <summary>
        
/// 撤销操作
        
/// </summary>
        public void Cancel()
        {
            dp.StopCoding(project);
        }
    }

       接下来就是命令的指挥者啦,项目经理首先设置一个撤销命令,并且将执撤销命令,在执行撤销命令的时候首先要将命令从集合中移除,因为该开发者已经不参与该撤销项目的工作了,所以不记录考核依据中,在调用命令中的撤销方法让开发者做具体的撤销工作。代码如下:

/// <summary>
    
/// 项目经理类
    
/// </summary>
    public class ProjectManager
    {
        List<ICommand> cmdList = new List<ICommand>();

        /// <summary>
        
/// 设置命令
        
/// </summary>
        
/// <param name="cmd"></param>
        public void SetCommand(ICommand cmd)
        {
            cmdList.Add(cmd);
        }

        /// <summary>
        
/// 发起命令
        
/// </summary>
        public void ExcuteCommand()
        {
            cmdList.ForEach(p => p.Excute());
        }

        /// <summary>
        
/// 返回记录行数
        
/// </summary>
        
/// <returns></returns>
        public int GetCommandCount()
        {
            return cmdList.Count;
        }

        /// <summary>
        
/// 撤销命令
        
/// </summary>
        
/// <param name="cmd"></param>
        public void CancelExectueCommand(ICommand cmd)
        {
            cmd.Cancel();
            cmdList.Remove(cmd);
        }
    }

     可见对功能的封装和“请求与实现分离”,可以让我们很容易的进行撤销与记录的工作,可以再命令执行前作一些必须要的操作。主函数调用如下:

        static void Main(string[] args)
        {
            //表示一个具体的项目名字叫:项目A
            WebProject wpA = new WebProject() { ProjectName = "项目A" };
            //表示一个具体的项目名字叫:项目B
            WebProject wpB = new WebProject() { ProjectName = "项目B" };
            //开发者
            Developer developer= new Developer();

            //开发者所需要接收的命令
            ICommand codeCmd = new CodingCommand() { project = wpA, dp = developer };
            ICommand UpdateCmd = new UpdateRoutineCommand() { project = wpB, dp = developer };

            //项目经理
            ProjectManager pm = new ProjectManager();
            //设置命令
            pm.SetCommand(codeCmd);
            pm.SetCommand(UpdateCmd);
            //发起命令让开发者去完成
            pm.ExcuteCommand();

            pm.CancelExectueCommand(UpdateCmd);//撤销UpdateCmd命令
         }

       命令模式总结:

       ①它能很容易的维护所有命令的集合。

       ②它可以很方便的实现撤销和恢复命令。

       ③可以很方便的将每个执行记录日志。

       ④最重要的就是将发起者与实现者分离。

分享到:
评论

相关推荐

    C# 设计模式系列教程-命令模式

     在软件系统中,行为请求者与行为实现者通常是一种紧耦合的关系,但某些场合,比如需要对行为进行记录、撤销或重做、事务等处理时,这种无法抵御变化的紧耦合的设计就不太合适。 3. 模式中角色  3.1 抽象命令...

    设计模式系列之命令模式

    在软件系统中,“行为请求者”与“行为实现者”通常呈现一种“紧耦合”。但在某些场合,比如要对行为进行“记录、撤销/重做、事务”等处理,这种无法抵御变化的紧耦合是不合适的...这就是命令模式(Command Pattern)。

    Java设计模式-23种设计模式详解

    Java设计模式是前辈们对代码开发经验的总结,是解决特定问题的一系列套路。它不是语法规定,而是一套用来提高代码可复用性、可维护性、可读性、稳健性以及安全性的解决方案。 设计模式的六大原则 1. 开闭原则...

    JavaScript设计模式.pdf

    JavaScript设计模式.pdf JavaScript设计模式是指在软件开发中使用JavaScript语言编写的设计模式。这些设计模式旨在提高代码的重用性、可读性、维护性和扩展性。以下是JavaScript设计模式的知识点总结: 1. 单体...

    C++设计模式基础教程.pdf

    14. 命令模式(Command Pattern):将一个请求封装为一个对象,从而使你可用不同的请求对客户端进行参数化。 15. 责任链模式(Chain of Responsibility Pattern):在该模式里,很多对象由每一个对象对其下家的引用...

    DesignPattern:23种设计模式,Android原始设计模式分析-android

    设计模式系列23种设计模式设计模式是一套被反复使用,多数人知道的,经过分类编目的,代码设计经验的总结。使用设计模式是为了可重用代码,让代码更容易被他人理解,保证代码可靠性。本文将介绍23种设计模式。创建型...

    java 23种设计模式及具体例子

    java 设计模式 java 设计模式是软件工程的基石,它们被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。使用设计模式可以让代码更容易被他人理解、保证代码可靠性、提高代码的重用性。 一、设计模式...

    C#23种设计模式_示例源代码及PDF

    命令模式把发出命令的责任 命令模式 和执行命令的责任分割开,委派给不同的对象。命令模式允许请求的一方和发送的一方 独 立开来,使得请求的一方不必知道接收请求的一方的接口,更不必知道请求是怎么被接收, 以及...

    Java 23种设计模式通解

    "Java 23种设计模式通解" 本文档总结了Java 23种设计模式的基本概念、分类、六大原则和详细实现。设计模式是软件工程的基石,它们被广泛应用于软件开发中,以提高代码的可重用性、可读性和可维护性。 设计模式的...

    软件设计模式知识点

    10. 命令模式(Command):将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及对请求进行撤销操作。 七大设计原则 软件设计模式还遵循七大设计原则: 1. 开放...

    设计模式系列之组合模式

    组合模式,将对象组合成树形结构以表示“部分-整体”的层次结构,组合模式使得用户对单个对象和组合对象的使用具有一致性。掌握组合模式的重点是要理解清楚 “部分/整体” 还有 ”单个对象“ 与 "组合对象" 的含义。...

    JAVA23种设计模式及快捷记忆

    设计模式(Design Pattern)是前辈们对代码开发经验的总结,是解决特定问题的一系列套路。它不是语法规定,而是一套用来提高代码可复用性、可维护性、可读性、稳健性以及安全性的解决方案。工厂模式、抽象工厂模式、...

    软件设计模式作业 行为型设计模式

    使用组合命令模式实现多功能开关,让用户进行设置,要么控制教室的所有灯的开和关,要么控制教室所有风扇的开和关,要么控制教室所有空调的开和关,要么控制教室里教学多媒体设备的开和关。 2、中介者模式 2.1 作业...

    23种设计模式入门到精通详解.txt

    命令模式:将命令请求封装为一个对象,使得可以用不同的请求来进行参数化。 访问者模式:在不改变数据结构的前提下,增加作用于一组对象元素的新功能。 责任链模式:将请求的发送者和接收者解耦,使的多个对象都有...

    浅析java常用的设计模式(doc-23页).doc

    浅析java常用的设计模式(doc 23页) 1、工厂模式:客户类和工厂类分开。消费者任何时候需要某种产品,只需向工厂请求即 可。消费者无须修改就可以接纳新产品。缺点是当产品修改时,工厂类也要做相应的修 改。如:如何...

    Android编程设计模式之命令模式详解

    本文实例讲述了Android编程设计模式之命令模式。分享给大家供大家参考,具体如下: 一、介绍 命令模式(Command Pattern),是行为型设计模式之一。命令模式相对于其他的设计模式来说并没有那么多的条条框框,其实它...

    GoF 的 23 种设计模式

    GoF 的 23 种设计模式的分类,现在对各个模式的功能进行介绍。 单例(Singleton)模式:某个类只能生成一个实例,该类提供了一个全局访问点供外部获取该实例,其拓展是有限多例模式。 原型(Prototype)模式:将一...

    软件设计模式行为型模式实验代码

    包含4个实验,组合命令模式(使用组合命令模式实现多功能开关,让用户进行设置,要么控制教室的所有灯的开和关,要么控制教室所有风扇的开和关),中介者模式(ATC代表空中交通管制。空管调解员不过是机场可用的空中...

    软件设计模式实验3行为型模式源码

    1.使用组合命令模式实现多功能开关,让用户进行设置,要么控制教室的所有灯的开和关,要么控制教室所有风扇的开和关,要么控制教室所有空调的开和关,要么控制教室里教学多媒体设备的开和关。2.ATC代表空中交通管制。...

Global site tag (gtag.js) - Google Analytics