命令模式

  命令模式(Command Pattern)把请求以命令的形式包裹在对象中,并传给调用对象。调用对象寻找可以处理该命令的合适的对象A,并把该命令传给相应的N个对象,由N个对象去执行命令。

  命令模式主要解决在某些场合中,命令发布者和N多命令执行者的耦合关系。比如在项目实施过程中,客户同时通知SA修改需求,UI修改页面,通知码农修改代码。

  定义每个项目组的抽象方法

/**
 * 每个项目会分成SA组,UI组,码农组
 * 每个组都有新增需求,删除需求,重新排期的实现,因此抽象出一个Group
 * @author test11
 */
public abstract class Group {

    /**
     * 新增需求
     * @param id
     * @param content
     */
    public abstract void addReq(String id,String content);

    /**
     * 删除需求
     * @param id
     */
    public abstract void delReq(String id);

    /**
     * 重新排期
     */
    public abstract void replan();
}

  每个项目组的具体实现

/**
 * 码农组
 * @author test11
 */
public class Coder extends Group{

    @Override
    public void addReq(String id, String content) {
        System.out.println("加代码");
    }

    @Override
    public void delReq(String id) {
        System.out.println("删代码");
    }

    @Override
    public void replan() {
        System.out.println("重新排期");
    }
}
/**
 * 加需求
 * @author test11
 */
public class SA extends Group{

    @Override
    public void addReq(String id, String content) {
        System.out.println("加需求");
    }

    @Override
    public void delReq(String id) {
        System.out.println("删需求");
    }

    @Override
    public void replan() {
        System.out.println("重新排期");
    }
}
/**
 * UI组
 * @author test11
 */
public class UI extends Group{

    @Override
    public void addReq(String id, String content) {
        System.out.println("加页面");
    }

    @Override
    public void delReq(String id) {
        System.out.println("删页面");
    }

    @Override
    public void replan() {
        System.out.println("重新排期");
    }
}

  客户通知所有的组别做命令的下发

/**
 * 客户给不同组别下命令的测试
 * @author test11
 */
public class Demo {

    public static void main(String[] args) {
        /**
         * 客户新增需求,需要分别告知SA,然后再跟UI描述页面需求,再跟码农描述接口需求
         * 因此,需要有个帮忙执行所有命令的角色出现,客户只需告知这个角色,其他的不管
         * 项目经理就是这个角色,由项目经理统一接收命令,然后下发到各个组
         */
        Group sa = new SA();
        sa.addReq("1","接口和UI优化");
        sa.replan();

        Group ui = new UI();
        ui.addReq("1","修改页面");
        ui.replan();

        Group code = new Coder();
        code.addReq("1","优化接口");
        code.replan();
    }
}

  如上的设计中,客户和SA,UI,码农这几个角色耦合在了一起,它必须关心谁是这个角色,并且把命令传达给指定的人。

  而解决这个问题可以通过设置项目经理PM这个角色,统筹管理SA,UI和码农,而客户只需将将命令包裹在对象中,传达给项目经理,由项目经理去分派任务。

  我们定义好命令的抽象,其中包含执行任务的对象,和一个执行任务的抽象方法,方便在不同命令的实现中调用父类的对象去执行任务

  Command命令抽象

/**
 * 把客户的命令抽象,只留一个execute方法
 * 即客户只需把命令做一次下发,后面的执行交由项目经理去安排
 * @author test11
 */
public abstract class Command {

    /**
     * 项目经理为了方便在execute方法中调用三个组的力量,预先实例化好待命
     */
    Coder coder = new Coder();
    UI ui = new UI();
    SA sa = new SA();

    /**
     * 客户跟项目经理沟通需求的方法
     */
    public abstract void execute();
}

  PM:接收命令的对象

/**
 * 项目经理,接收命令的对象
 * @author test11
 */
public class PM {

    Command command;

    PM(Command command){
        this.command = command;
    }

    public void invoke(){
        command.execute();
    }
}

  客户将命令封装成对象

/**
 * 添加需求的命令
 * 假设需求是添加一个页面,新增一个接口,然后SA重排项目周期
 * @author test11
 */
public class AddReqCommand extends Command{

    @Override
    public void execute() {
        super.ui.addReq("1","新增页面");
        super.coder.addReq("1","优化接口");
        super.sa.replan();
    }

}

  客户将命令传达给PM去分派执行

/**
 * 测试命令模式,客户通过项目经理下发各种需求
 * @author test11
 */
public class Demo {

    /**
     * 命令模式很好的避免了下发命令的人需要一一和实际执行命令的人说清楚
     * 很好的解耦了两者的关系
     * 但命令模式也存在着弊端,即命令特别多的时候,Command的子类会无限膨胀
     * @param args
     */
    public static void main(String[] args) {

        //整理好需求
        Command addReq = new AddReqCommand();

        //把PM喊来
        PM pm = new PM(addReq);

        //告知他去执行
        pm.invoke();
    }
}

 命令模式+责任链模式的结合例子见:https://files.cnblogs.com/files/jiyukai/chainaddcommand.rar

原文地址:https://www.cnblogs.com/jiyukai/p/14789665.html