简述-命令模式

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/ddxxii/article/details/84108317

介绍

行为型设计模式之一。这个模式没有规矩,比较灵活。将一些列的方法调用封装,用户只需要调用一个方法执行,那么所有这些被封装的方法就会被挨个执行调用。如名字一样,命令,比如开机命令,只需要一条命令,内部操作都封装好了自己执行。很多时候封装API其实也可以看作是一个简单的命令

Android中使用多,但不是很典型,比较典型的是Android的事件机制中底层逻辑对事件的转发处理,Android的每一种事件在屏幕上产生后都会经由底层逻辑将其转化为一个NotifyAgs对象,NotifyAgs相当于一个命令者抽象。InputDispatcher则为请求者,接受者角色由硬件驱动承担

UML

  • Receiver:接受者角色,负责具体实施或执行一个请求,执行具体逻辑的角色
  • Command:命令角色,定义所有具体命令类的抽象接口
  • ConcreteCommand: 具体命令角色,相当于一个中间角色,调用接受者的相关方法,在接受者和命令执行的具体行为之间加以弱耦合
  • Invoker: 请求者角色,该类职责就是调用命令对象执行具体的请求,相关方法称为行动方法
  • Client: 客户端角色

使用场景

  • 需要抽象待执行操作,以参数形式提供出来——类似于过程设计中的回调机制,而命令模式正是回调机制的一个面向对象的替代品
  • 在不同的时刻指定、排列和执行请求。一个命令对象可以有与初始化请求无关的生存期
  • 需要支持取消操作
  • 支持修改日志功能,这样当系统崩溃时,这些修改可以被重做一遍
  • 需要支持事务操作

事例

以小明吃饭为例子,采用命令模式的结构来进行操作。

  1. 命令抽象:提供吃和取消吃方法
/**
 * 命令模式命令
 */
public interface ICommand {
    /**
     * 吃
     */
    void eat();

    /**
     * 取消吃
     */
    void cancelEat();
}
  1. 创建处理者:可实现接口,也可不实现,目的还是提供给命令调用
/**
 * 小明命令处理
 */
public class XiaoMingResolver implements ICommand {
    EatThread eatThread;

    public XiaoMingResolver() {
    }

    /**
     * 吃饭中标志
     */
    private boolean eating;

    /**
     * 吃饭操作
     */
    @Override
    public void eat() {
        eating = true;
        //开启线程输出吃饭
        eatThread = new EatThread(this);
        eatThread.start();
    }

    /**
     * 取消吃饭
     */
    @Override
    public void cancelEat() {
        try {
            //终止吃饭
            eating = false;
            eatThread.join();
            eatThread = null;
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    private static class EatThread extends Thread {
        private WeakReference<XiaoMingResolver> xiaoMingResolverWeakReference;

        public EatThread(XiaoMingResolver xiaoMingResolver) {
            xiaoMingResolverWeakReference = new WeakReference<XiaoMingResolver>(xiaoMingResolver);
        }

        @Override
        public void run() {
            super.run();
            /*每隔一秒输出一次吃饭中*/
            XiaoMingResolver xiaoMingResolver = xiaoMingResolverWeakReference.get();
            while (xiaoMingResolver != null && xiaoMingResolver.eating) {
                try {
                    Thread.sleep(1000);
                    System.out.println("小明吃饭中");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

}

  1. 小明实际命令:实现接口
/**
 * 小明命令实现
 */
public class XiaoMingEatCommand implements ICommand {
    private XiaoMingResolver xiaoMingResolver;

    public XiaoMingEatCommand() {
        xiaoMingResolver = new XiaoMingResolver();
    }

    @Override
    public void eat() {
        //调用处理者的吃
        xiaoMingResolver.eat();
    }

    @Override
    public void cancelEat() {
        //调用处理者的取消吃
        xiaoMingResolver.cancelEat();
    }
}
  1. 命令请求者:持有命令,在调用命令方法
/**
 * 命令请求者
 */
public class ComInvoker {
    private ICommand iCommand;

    public ComInvoker(ICommand iCommand) {
        this.iCommand = iCommand;
    }

    /**
     * 执行吃操作
     */
    public void exeEat() {
        iCommand.eat();
    }

    /**
     * 执行取消吃操作
     */
    public void exeCancelEat() {
        iCommand.cancelEat();
    }
}
  1. 测试:
 ICommand xiaoMingEatCommand = new XiaoMingEatCommand();
        ComInvoker comInvoker = new ComInvoker(xiaoMingEatCommand);
        comInvoker.exeEat();
        try {
            Thread.sleep(3000);
            comInvoker.exeCancelEat();

            //再开始吃
            comInvoker.exeEat();
            Thread.sleep(3000);
            comInvoker.exeCancelEat();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
  1. 输出
小明吃饭中
小明吃饭中
小明吃饭中
再开始吃
小明吃饭中
小明吃饭中
小明吃饭中

这里的操作很简单,看似简单的操作,硬生生分了成了几部分:

  1. 请求者持有命令
  2. 由具体的命令者持有最终实现者
  3. 最终实现者实现代码

总结:命令模式的思想就是,调用方一条命令下去,剩下的内部去执行就好,而且内部还做到了低耦合和可替换。它的缺点很明显,类的膨胀,产生类很多衍生类。优点也非常明显,更弱的耦合、更灵活的控制性和扩展性,比如最终实现者或者是具体命令者都是随时可替换的,实际过程要不要用它还是可以多考虑考虑。

猜你喜欢

转载自blog.csdn.net/ddxxii/article/details/84108317