设计模式之命令模式

命令模式

The command pattern encapsulates a request as an object, thereby letting us parameterize other objects with different requests, queue or log requests, and support undoable operations.

定义:命令模式将请求(命令)封装为一个对象,这样可以使用不同的请求参数化其他对象(将不同请求依赖注入到其他对象),并且能够支持请求(命令)的排队执行、记录日志、撤销等(附加控制)功能。

命令模式最核心的实现手段,是将函数封装成对象。C 语言支持函数指针,可以把函数当作变量传递来传递去。但是,在大部分编程语言中,函数不能作为参数传递给其他函数,也不能赋值给变量。借助命令模式,可以将函数封装成对象。具体来说就是,设计一个包含这个函数的类,实例化一个对象传来传去,这样就可以实现把函数像对象一样使用。从实现的角度来说,它类似回调。

令模式的主要作用和应用场景,是用来控制命令的执行,比如,异步、延迟、排队执行命令、撤销重做命令、存储命令、给命令记录日志等等,这才是命令模式能发挥独一无二作用的地方。

代码演示:

服务器在接收到客户端的请求之后,会解析出指令和数据,并且根据指令的不同,执行不同的处理逻辑。对于这样的业务场景,一般有两种架构实现思路。

一种实现思路是利用多线程。一个线程接收请求,接收到请求之后,启动一个新的线程来处理请求。

另一种实现思路是在一个线程内轮询接收请求和处理请求。这种处理方式不太常见。尽管它无法利用多线程多核处理的优势,但是对于 IO 密集型的业务来说,它避免了多线程不停切换对性能的损耗,并且克服了多线程编程 Bug 比较难调试的缺点 。

这里演示第二种实现代码:

public interface Command {
    void execute();
}

public class ArchiveCommand implements Command {

    public ArchiveCommand(byte[] data) {
    }

    @Override
    public void execute() {

    }
}

public class GotStarCommand implements Command {

    public GotStarCommand(byte[] data) {
    }

    @Override
    public void execute() {
        System.out.println("Got start");
    }
}

public class GotDiamondCommand implements Command {

    public GotDiamondCommand(byte[] data) {
    }

    @Override
    public void execute() {
        System.out.println("Got Diamond");
    }
}

public class HitObstacleCommand implements Command {

    public HitObstacleCommand(byte[] data) {
    }

    @Override
    public void execute() {
        System.out.println("Hit Obstacle");
    }
}

public enum Event {
    NONE,
    GOT_DIAMOND,
    GOT_STAR,
    HIT_OBSTACLE,
    ARCHIVE;
}

public class Request {
    public Event getEvent() {
        return Event.NONE;
    }

    public byte[] getData() {
        return new byte[10];
    }
}

public class GameApplication {
    private static final int MAX_HANDLED_REQ_COUNT_PER_LOOP = 100;
    private Queue<Command> queue = new LinkedList<>();

    public void mainloop() {
        while (true) {
            List<Request> requests = new ArrayList<>();
            //省略从epoll或者select中获取数据,并封装成Request的逻辑,
            //注意设置超时时间,如果很长时间没有接收到请求,就继续下面的逻辑处理。
            for (Request request : requests) {
                Event event = request.getEvent();
                Command command = null;
                if (event.equals(Event.GOT_DIAMOND)) {
                    /*数据作为参数*/
                    command = new GotDiamondCommand(request.getData());
                } else if (event.equals(Event.GOT_STAR)) {
                    command = new GotStarCommand(request.getData());
                } else if (event.equals(Event.HIT_OBSTACLE)) {
                    command = new HitObstacleCommand(request.getData());
                } else if (event.equals(Event.ARCHIVE)) {
                    command = new ArchiveCommand(request.getData());
                } // ...一堆else if...
                queue.add(command);
            }

            int handledCount = 0;
            while (handledCount < MAX_HANDLED_REQ_COUNT_PER_LOOP) {
                if (queue.isEmpty()) {
                    break;
                }

                Command command = queue.poll();
                command.execute();
            }
        }
    }
}
命令模式 VS 策略模式

每个设计模式都应该由两部分组成:第一部分是应用场景,即这个模式可以解决哪类问题;第二部分是解决方案,即这个模式的设计思路和具体的代码实现。不过,代码实现并不是模式必须包含的。

在策略模式中,不同的策略具有相同的目的、不同的实现、互相之间可以替换。 而在命令模式中,不同的命令具有不同的目的,对应不同的处理逻辑,并且互相之间不可替换。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值