设计模式系列8---发号施令的命令模式

好了,我们还是开一个故事吧。
我们看到过这样的一个表情,我们的程序员接收到来自四面八方的需求,要和不同的人打交道,应对各种所谓需求背后还加多句:“领导提出来的,很重要“之类的结束语,最终过载,导致崩溃跳楼的情况。哈哈
enter image description here

而且我们的美工同学也有这样的经历吧!
enter image description here

这种混乱的需求来源,导致了下面这种情况。

enter image description here

所以,与其让整体暴漏在问题前,不如推我们的PM出去面对所有
正所谓集体阵亡,不如死一个好。

enter image description here

代码实现

对于这些问题,我们把我们的产品经理推到了风头浪尖,由他去面对风雨,接收各种提出来的命令,然后团队人员再接收他的调度,这很有IOC的味道,不适吗?把原本紧密耦合的几个类,拆开来,让我们的pm独自面对。
现在我们先写出我们的Pm。

    public class PmInvoker {

    private Command command;

    public void setCommand(Command command){
        this.command = command;
    }

    public void action(){
        this.command.execute();
    }
}

他做的事情很简单,就是接受上门发的命令Command(),然后去执行action()
接着我们抽象下我们的命令,我们的命令里面包含着我们的美工和码农们。

 public abstract class Command {
    protected PageEmployee mArtistEmployee = new PageEmployee(); //美工
    protected CodeEmployee mCoder = new CodeEmployee(); //码农

    //只要一个方法,你要我做什么事情
    public abstract void execute();
}

我们的命令类还是挺简单的,那就是被执行,哈哈。

接着我们来写下几个具体的命令

public class DeletePageCommand extends Command {
    //执行删除一个页面的命令
    public void execute() {
        mCoder.delete(); 
    }
}

首先是最苦逼的删除也没的质量,辛辛苦苦做出来的页面,老板说不要,不要就得不要删除啊,那么删咯。

接着我们来看下一个增加需求的命令

public class AddRequirementCommand extends Command {

    public void execute() {
        mArtistEmployee.add();
        mArtistEmployee.plan();

        mCoder.add();
        mCoder.plan();
    }
}

没看错,这个就是这样,我们需要我们的美工去出界面稿,然后说下这个需要多少天的时间,给个计划,接着通知下我们的码农同学,叫他过来,通知他需要加代码啦,然后也给个进度计划吧。
其余的命令类似,这里就不重复累赘了。

接着我们来充当下老板,来看下我们是怎么发号施令的

public static void main(String[] args) {

    Command command=new AddRequirementCommand();
    PmInvoker pmInvoker=new PmInvoker();
    pmInvoker.setCommand(command);
    pmInvoker.action();

}

首先我们先头脑发热了一下,突然有了灵光,然后就了新的需求,接着我们找来了PM,同他说这个需求,接着叫她去干活。

很一气呵成的过程,是吧!
如果我们脑子一热,也可以要求他删掉这个页面。哈哈

public static void main(String[] args) {

    Command command=new DeletePageCommand();
    PmInvoker pmInvoker=new PmInvoker();
    pmInvoker.setCommand(command);
    pmInvoker.action();

}

这样基本就演示完了,我们每次脑热的时候都之需要求改下我们的具体命令就好了,如果有新的命令,也是继承然后写多一个就好了。是不是很好?而且我们每次不需要关心背后到底做了什么,但却有很多类在背后默默工作着。我们的幕后工作人员啊,辛苦你们了。
很高內聚的,是不是?

最后给出我们的员工类代码

public class CodeEmployee extends Employee {

    public void add() {
        System.out.println("客户要求增加一项功能...");
    }

    public void change() {
        System.out.println("客户要求修改一项功能...");
    }

    public void delete() {
        System.out.println("客户要求删除一项功能...");
    }

    public void plan() {
        System.out.println("客户要求代码变更计划...");
    }
}

public class PageEmployee extends Employee {

    @Override
    public void add() {
        System.out.println("客户要求增加一个页面...");
    }

    @Override
    public void change() {
        System.out.println("客户要求修改一个页面...");
    }

    @Override
    public void delete() {
        System.out.println("客户要求删除一个页面...");
    }

    @Override
    public void plan() {
        System.out.println("客户要求页面变更计划...");
    }
}


public abstract class Employee {

    public abstract void add();

    public abstract void delete();

    public abstract void change();

    public abstract void plan();
}

好了,我们的代码演示就到之类结束了。

定义

我们来看下uml

enter image description here

这里的invoker,就是我们的PM去执行我们的Command,然后我们的背后实际干活的ConcrateCommand就去找对应的负责人Receiver去做事,就是我们的个个employee,美术,码农啊。

可能小伙伴觉得那个桥街和策略的不像,但感觉这次我们命令模式就像了,为何像呢,因为它们都是分在行为模式组里面。

后记

我们的命令模式提供了很好的封装,把Invoker和具体的Receiver分开,高内聚,扩展性很好。
而且我们的所有成员都在我们的命令里面有一个实例,因为这可以给我们的具体命令们调用,不要让每个命令都去生成一次。

但使用我们的命令是需要慎重的,因为如果当命令很多的时候,这些类的膨胀速度还是挺快的。
另外一个是Do&Undo,我们不可避免的是需要撤销上一次的操作。
这需要我们做对应的配套支持,当然对于一些特点的类型,我们可以加多一个undo的命令,但对于一些需要案例,需要配套一些状态的变量,纪录一些参数信息等。

写的过程一直在提示强调他们很像,一方面是为了温故旧的知识,同事也是为了清楚各个模式之间的不一样。从而加强我们对每个类的了解。

热评文章