命令模式

2018-11-04  本文已影响20人  Whyn

简介

Encapsulate a request as an object,thereby letting you parameterize clients with different requests,queue or log requests,and support undoable operations.
将一个请求封装成一个对象,从而让你使用不同的请求把客户端参数化,对请求排队或者记录请求日志,可以提供命令的撤销和恢复功能。

命令模式(Command Pattern)是对命令的封装,每一个命令都是一个操作:请求的一方发出请求要求执行一个操作;接收的一方收到请求,并执行操作。命令模式 解耦了请求方和接收方,请求方只需请求执行命令,不用关心命令是怎样被接收,怎样被操作以及是否被执行····

软件系统中,行为请求者与行为实现者通常是一种紧耦合关系,因为这样的实现简单明了。但紧耦合关系缺乏扩展性,在某些场合中,当需要为行为进行记录,撤销或重做等处理时,只能修改源码。而 命令模式 通过为请求与实现间引入一个抽象命令接口,解耦了请求与实现,并且中间件是抽象的,它可以有不同的子类实现,因此其具备扩展性。

命令模式 本质:解耦命令请求与处理

主要解决

当系统的某项操作具备命令语义时,且命令实现不稳定(变化),那么可以通过 命令模式 解耦请求与实现,利用抽象命令接口使请求方代码架构稳定,封装接收方具体命令实现细节。接收方与抽象命令接口呈现弱耦合(内部方法无需一致),具备良好的扩展性。

优缺点

优点

缺点

使用场景

模式讲解

首先看下 命令模式 的通用 UML 类图:

命令模式

从 UML 类图中,我们可以看到,命令模式 主要包含四种角色:

:从 命令模式 的 UML 类图中,其实可以很清晰地看出:Command的出现就是作为ReceiverInvoker的中间件,解耦了彼此。而之所以引入Command中间件,我觉得是以下两方面原因:

以下是 命令模式 的通用代码:

class Client {
    public static void main(String[] args) {
        ICommand cmd = new ConcreteCommand();
        Invoker invoker = new Invoker(cmd);
        invoker.action();
    }

    //接收者
    static class Receiver {
        public void action() {
            System.out.println("执行具体操作");
        }
    }

    //抽象命令接口
    interface ICommand {
        void execute();
    }

    //具体命令
    static class ConcreteCommand implements ICommand {
        // 直接创建接收者,不暴露给客户端
        private Receiver mReceiver = new Receiver();

        @Override
        public void execute() {
            this.mReceiver.action();
        }
    }

    //请求者
    static class Invoker {
        private ICommand mCmd;

        private Invoker(ICommand cmd) {
            this.mCmd = cmd;
        }

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

:在一个系统中,不同的命令对应不同的请求,也就是说无法把请求抽象化,因此 命令模式 中的Receiver是具体实现;但是如果在某一个模块中,可以对Receiver进行抽象,其实这就变相使用到了 桥接模式Command类具备两个变化的维度:CommandReceiver),这样子的扩展性会更加优秀。

举个例子

例子:假如现有我们有一个遥控器,可以控制风扇的风力大小,分为大,中,小,关闭四个程度,请使用程序进行实现。

分析:上面的例子涉及两个物体:遥控器和风扇,直接的思路就是遥控器紧耦合风扇,然后遥控器内部暴露控制风扇风力等级接口。但是遥控器后续可能还可以对其他电器设备(如空调等)进行控制,因此有必要解耦遥控器和具体电器设备的紧密联系。对遥控器进行操作,相当于发出一个指令(命令),让对应的电器设备进行工作,那么 命令模式 是非常切合这个场景的。

具体代码如下:

class Client {
    public static void main(String[] args) {
        RemoteController remote = new RemoteController();
        Fan fan = new Fan();

        ICommand cmd = new TurnMinCommand(fan);
        remote.action(cmd);
        
        cmd = new TurnMidCommand(fan);
        remote.action(cmd);

        cmd = new TurnMaxCommand(fan);
        remote.action(cmd);
        
        cmd = new TurnOffCommand(fan);
        remote.action(cmd);
    }

    //Receiver
    static class Fan {
        public void turnMin() {
            System.out.println("Fan in Min degree");
        }

        public void turnMid() {
            System.out.println("Fan in Mid degree");
        }

        public void turnMax() {
            System.out.println("Fan in Max degree");
        }

        public void turnOff() {
            System.out.println("Fan off");
        }
    }

    //Command
    interface ICommand {
        void execute();
    }

    //ComcreteCommand
    static class TurnMinCommand implements ICommand {
        private Fan mFan;

        public TurnMinCommand(Fan fan) {
            this.mFan = fan;
        }

        @Override
        public void execute() {
            this.mFan.turnMin();
        }
    }

    //ComcreteCommand
    static class TurnMidCommand implements ICommand {
        private Fan mFan;

        public TurnMidCommand(Fan fan) {
            this.mFan = fan;
        }

        @Override
        public void execute() {
            this.mFan.turnMid();
        }
    }

    //ComcreteCommand
    static class TurnMaxCommand implements ICommand {
        private Fan mFan;

        public TurnMaxCommand(Fan fan) {
            this.mFan = fan;
        }

        @Override
        public void execute() {
            this.mFan.turnMax();
        }
    }
    //ComcreteCommand
    static class TurnOffCommand implements ICommand {
        private Fan mFan;

        public TurnOffCommand(Fan fan) {
            this.mFan = fan;
        }

        @Override
        public void execute() {
            this.mFan.turnOff();
        }
    }

    //Invoker
    static class RemoteController {
        public void action(ICommand cmd) {
            cmd.execute();
        }
    }
}

由于遥控器已经与具体电器解耦了,以后如果想扩展新命令,只需增加即可,遥控器结构无需改动。

上一篇下一篇

猜你喜欢

热点阅读