设计模式-命令模式

命令模式,这个模式从名字上看就很简单,命令嘛,老大发布命令,小兵执行就行咯。
以项目组为例子来讲命令模式
项目组的成员分工也是采用了常规的分工方式,分为需求组、美工组、代码组。现在有客户要我们做一个项目,客户和需求组讨论需求,和美工组讨论页面,和代码组讨论实现,告诉他们修改这里,删除这里,增加这些等等。
我们把这个模式用类图表示一下:
这里写图片描述
这个类图很简单,客户和三个组都有交流,这也合情合理,那我们看看这个的实现,首先看抽象类,我们是面向接口或抽象类编程的嘛:

package com.example.xpeng.myapplication;

/**
 * Created by xpeng on 2018/6/2.
 * 项目组分成了三个组,每个组还是要接受增删的命令
 */

public abstract class Group {
    //甲乙双方分开办公,你要和那个组讨论,你首先要找到这个组
    public abstract void find();

    //被要求增加功能
    public abstract void add();

    //被要求删除功能
    public abstract void delete();

    //被要求修改功能
    public abstract void change();

    //被要求给出所有的变更计划
    public abstract void plan();

    //撤销计划
    public abstract void undo();
}

大家看抽象类中的两个方法,是不是每个都是一个命令?找到它,增加,删除,给我计划!是不是命令,这也就是命令模式中的命令接受角色,等会细讲,我们再看三个实现类,需求组最重要,没有需求组你还设计个屁啊。看RequirmentGroup类的实现:

package com.example.xpeng.myapplication;

import android.util.Log;

/**
 * Created by xpeng on 2018/6/2.
 * 需求组的职责是客户谈定需求,这个组的人应该都是业务领域专家
 */

public class RequirementGroup extends Group {

    //客户要求需求组过去和他们谈
    @Override
    public void find() {
        Log.e("xyz","找到需求组...");
    }

    @Override
    public void add() {
        Log.e("xyz","客户要求添加一项需求...");
    }

    @Override
    public void delete() {
        Log.e("xyz","客户要求删除一项需求...");
    }

    @Override
    public void change() {
        Log.e("xyz","客户要求修改一项需求...");
    }

    @Override
    public void plan() {
        Log.e("xyz","客户要求变更计划...");
    }

    @Override
    public void undo() {
        Log.e("xyz","客户要求撤销计划...");
    }
}

需求组有了,我们再看美工组

package com.example.xpeng.myapplication;

import android.util.Log;

/**
 * Created by xpeng on 2018/6/2.
 * 美工组
 */

public class PageGroup extends Group {

    //客户要求需求组过去和他们谈
    @Override
    public void find() {
        Log.e("xyz","找到美工组...");
    }

    @Override
    public void add() {
        Log.e("xyz","客户要求添加一个页面...");
    }

    @Override
    public void delete() {
        Log.e("xyz","客户要求删除一个页面...");
    }

    @Override
    public void change() {
        Log.e("xyz","客户要求修改一个页面...");
    }

    @Override
    public void plan() {
        Log.e("xyz","客户要求页面变更计划...");
    }

    @Override
    public void undo() {
        Log.e("xyz","客户要求页面撤销计划...");
    }
}

最后再看代码组:

package com.example.xpeng.myapplication;

import android.util.Log;

/**
 * Created by xpeng on 2018/6/2.
 * 代码组
 */

public class CodeGroup extends Group {

    //客户要求需求组过去和他们谈
    @Override
    public void find() {
        Log.e("xyz","找到代码组...");
    }

    @Override
    public void add() {
        Log.e("xyz","客户要求添加一个功能...");
    }

    @Override
    public void delete() {
        Log.e("xyz","客户要求删除一个功能...");
    }

    @Override
    public void change() {
        Log.e("xyz","客户要求修改一个功能...");
    }

    @Override
    public void plan() {
        Log.e("xyz","客户要求代码变更计划...");
    }

    @Override
    public void undo() {
        Log.e("xyz","客户要求代码撤销计划...");
    }
}

整个项目组的三个支柱都已经产生了,那看客户怎么和我们谈。客户刚开始給了一份他们自己写的需求,还是比较完整的,需求组根据这份需求写了一份分析说明书,客户一看,不对,要增加点需求,看程序:

        private void client() {
        //首先客户找到需求组说,过来谈需求,并修改
        Log.e("xyz","客户要求增加一个需求");

        Group rg = new RequirementGroup();
        rg.find();
        rg.add();
        rg.plan();
        }

好的,客户的需求达到了,需求刚开始没考虑周全,增加需求在所难免,理解理解。然后过了一段时间,客户说“界面多画了一个,过来谈谈”,于是L:

 private void client() {
        //首先客户找到美工组说,要修改


        Goup rg = new PageGroup();
        rg.find();
        rg.add();
        rg.plan();
        }

这个页面改了之后,后面又有各种需要修改的地方每次都找页面组,需求组,美工组等等,烦了,后来一想,应该找一个接头人啊,客户有什么更改找接头人就行,先看类图:
这里写图片描述

类图中增加了不少,看着也比较清晰,比较简单的(Command抽象类与Group抽象类是没有关联关系的,与Group的三个实现类是由关联关系,为了线条不交叉就直接画上父类有关系),增加了几个类说明如下:
Command抽象类:客户发给我们的命令,定义三个工作组的成员变量,供子类使用:定义一个抽象方法execute,由子类来实现:
Invoke实现类:项目接头人,setComand接受客户发给我们的命令,action方法是执行客户命令
我们先看Command抽象类代码:

package com.example.xpeng.myapplication;

/**
 * Created by xpeng on 2018/6/2.
 * 命令的抽象类,我们把客户发出的命令定义成一个一个的对象
 */

public abstract class Command {

    //把三个组都定义好,子类可以直接使用
    protected RequirementGroup rg = new RequirementGroup();//需求组
    protected PageGroup pg = new PageGroup();//美工组
    protected CodeGroup cg = new CodeGroup();//需求组

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

}

这个简单,看两个具体实现类,先看AddRequirementCommand类,这个类的作用就是增加一项需求。

package com.example.xpeng.myapplication;

/**
 * Created by xpeng on 2018/6/2.
 * 添加一项需求
 */

public class AddRequirementCommand extends Command {
    //执行增加一项需求的命令
    @Override
    public void execute() {
        //找到需求组
        super.rg.find();

        //增加一份需求
        super.rg.add();

        //页面也要增加
        super.pg.add();

        //功能也要增加
        super.cg.add();

        //给出计划
        super.rg.plan();

    }
}

看删除一个页面的命令,DeletePageCommand类

package com.example.xpeng.myapplication;

/**
 * Created by xpeng on 2018/6/2.
 * 添加一项需求
 */

public class DeletePageCommand extends Command {
    //执行删除一个页面的的命令
    @Override
    public void execute() {
        //找到页面组
        super.pg.find();

        //删除一个页面
        super.pg.delete();

        //给出计划
        super.pg.plan();
    }
}

Command抽象类还可以有很多的子类,比如增加一个功能命令(AddCodeCommand),删除一份需求命令(DeleteRequirementCommand)等等,这里就不用描述了,都很简单。
我们再来看看我们的接头人,就是Invoker类的实现:

package com.example.xpeng.myapplication;

/**
 * Created by xpeng on 2018/6/2.
 * 接头人的职责就是接受命令,并执行
 */

public class Invoker {
    //什么命令
    private Command command;

    //客户发出命令
    public void setCommand(Command command){
        this.command = command;
    }

    //执行客户的命令
    public void action(){
        this.command.execute();
    }

}

最后再来看实现:

  private void client() {
        //首先客户找到需求组说,过来谈需求,并修改
        Log.e("xyz","客户要求增加一个需求");
//
//        Group rg = new RequirementGroup();
//        rg.find();
//        rg.add();
//        rg.plan();


        //定义我们的接头人
        Invoker invoker = new Invoker();
        //客户要求增加一项命令
//        Command command = new AddRequirementCommand();
        //客户给我们下命令来
        Command command = new DeletePageCommand();
        invoker.setCommand(command);
        invoker.action();

    }

接下来看看命令模式的通用类图如下:
这里写图片描述
在这个类图中,我们看到三个角色:
Receiver角色:这个就是干活的角色,命令传递到这里是应该被执行的,具体到上面我们的例子中就是Group的三个实现类:
Command角色:就是命令,需要我执行的所有命令都在这里声明
Invoker角色:调用者,接收命令,并执行命令,例子中我这个项目经理就是这个角色
命令模式比较简单,但是在项目使用是非常频繁的,封装性非常好,因为他把请求方和执行方分开了,扩展性也有很好的保障。但是,命令模式也是有缺点的,你看Command的子类没有,那个如果我要写下去的可不是几个,而是几十个,这个类的膨胀的非常多,这个就需要大家在项目中自己考虑使用了。
上面的例子还没有说完。我们想想,客户要求增加一项需求,是不是页面也要增加,同时功能呢个也要增加呢呗?如果不使用命令模式,客户就需要先找到需求组,然后找美工组,然后找代码组,这个客户会崩溃的,使用命令模式之后,客户只管发布命令模式,你增加一个需求,没问题,我内部调用三个组通力合作,然后反馈结果,这也是客户所需要的,那这个怎么去修改呢?想想,很简单,在AddRirementCommand类的execute方法中增加对PageGroup和CodePage的调用就成了,修改后的代码如下:

package com.example.xpeng.myapplication;

/**
 * Created by xpeng on 2018/6/2.
 * 添加一项需求
 */

public class AddRequirementCommand extends Command {
    //执行增加一项需求的命令
    @Override
    public void execute() {
        //找到需求组
        super.rg.find();

        //增加一份需求
        super.rg.add();

        //页面也要增加
        super.pg.add();

        //功能也要增加
        super.cg.add();

        //给出计划
        super.rg.plan();

    }
}

看看是不是解决问题了?命令模式做了一层非常好的封装。那还有一个需求大家考虑:客户发出命令,那要是撤回怎么办呢?怎么实现呢,可以自己想想,很简单。

命令模式DEMO下载地址:
命令模式demo下载

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值