设计模式-命令模式(Command Pattern)

设计模式-命令模式(Command Pattern)



一、定义

将一个请求封装成一个对象,从而让你使用不同的请求把客户端参数化,对请求排队或者记录请求日志,可以提供命令的撤销功能。

二、概念解释

理解命令模式要先理解三个角色

  • 命令角色: 声明待执行的命令
  • 调用者角色:接收命令,执行命令
  • 接收者角色:实际干活的角色,是调用者角色执行的命令中真正处理命令的角色

我们将请求封装成抽象的命令角色,当有不同的请求时,就会有对应的具体命令类,这些具体命令类会被调用者接收和执行,当调用者执行命令时,真正干活的是具体命令类里的接收者
对于命令而言,有执行当然也会有撤销执行,所以定义里会有日志等机制,就是用来做类似回滚的操作

三、场景

我接触过的有职业划分的游戏里,法师具有变化技能,可以将目标变大或者变小,盗贼具有隐形技能,可以将目标隐形或者显性,这里我们可以用命令模式实现玩家(调用者角色)接受命令(命令角色),执行命令,并让法师或者盗贼(接收者)进行具体实现

四、实现

1、类图

在这里插入图片描述

2、代码实现

首先定义一个抽象命令类 该命令类有一个公共执行方法

public abstract class ChangeCommand {

    /**
     * 对目标执行命令
     * @param target 目标
     */
    public abstract void execute(Target target);
}

定义具体的命令类 代表着不同的命令 其中包含接收者角色去做具体的命令实现

// 改变目标的大小命令
public class ChangeSizeCommand extends ChangeCommand{

    private Profession profession;

    public ChangeSizeCommand(Profession profession) {
        this.profession = profession;
    }

    @Override
    public void execute(Target target) {
        profession.changeTargetAttribute(target);
    }
}
// 改变目标的隐身状态
public class ChangeVisibilityCommand extends ChangeCommand{

    private Profession profession;

    public ChangeVisibilityCommand(Profession profession) {
        this.profession = profession;
    }

    @Override
    public void execute(Target target) {
        profession.changeTargetAttribute(target);
    }
}

定义接收者角色的抽象 不同的命令类会有不同的接收者角色去实现

public abstract class Profession {

    /**
     * 改变目标属性
     */
    public abstract void changeTargetAttribute(Target target);
}

具体的接收者角色类 真正干活的角色

// 法师改变目标的大小
public class Mage extends Profession{

    @Override
    public void changeTargetAttribute(Target target) {
        System.out.println("原来的状态" + target.getSize().name());
        target.setSize(target.getSize() == SizeEnum.HUGE ? SizeEnum.SMALL : SizeEnum.NORMAL);
        System.out.println("改变后的状态" + target.getSize().name());
    }
}
// 盗贼改变目标的隐身状态
public class Thieves extends Profession{

    @Override
    public void changeTargetAttribute(Target target) {
        System.out.println("变化前属性" + target.getVisibility().name());
        target.setVisibility(target.getVisibility() == VisibilityEnum.VISIBLE ? VisibilityEnum.INVISIBLE : VisibilityEnum.VISIBLE);
        System.out.println("变化后属性" + target.getVisibility().name());
    }
}

调用者角色 负责接收,执行命令

@Data
public class Player {

    private ChangeCommand command;

    private Target target;

    public void setChangeCommand(ChangeCommand command) {
        this.command = command;
    }

    public void setTarget(Target target) {
        this.target = target;
    }

    /**
     * 执行命令
     */
    public void action() {
        this.command.execute(target);
    }
}

本例是改变目标的属性 这里定义一个抽象目标

@Data
public abstract class Target {

    private SizeEnum size;

    private VisibilityEnum visibility;
}

具体的目标

public class Dragon extends Target{

    public Dragon() {
        setSize(SizeEnum.HUGE);
        setVisibility(VisibilityEnum.VISIBLE);
    }
}

用到的枚举类

public enum SizeEnum {

    /**
     * 小
     */
    SMALL,

    /**
     * 正常
     */
    NORMAL,

    /**
     * 巨大
     */
    HUGE
}
public enum VisibilityEnum {

    /**
     * 可见-显形
     */
    VISIBLE(),

    /**
     * 不可见-隐形
     */
    INVISIBLE()
}

大脑产生命令 玩家点击鼠标对目标执行命令 法师或者盗贼去改变目标属性

@SpringBootTest
public class CommandTest {

    @Test
    public void test() {

        // 玩家作为调用者
        Player novice = new Player();
        // 让法师作为接收者执行具体命令
        Profession mage = new Mage();
        // 缩小命令并指定接收者
        ChangeCommand changeSizeCommand = new ChangeSizeCommand(mage);
        // 执行缩小目标为龙
        novice.setTarget(new Dragon());
        // 调用者接受命令 改变龙的大小
        novice.setChangeCommand(changeSizeCommand);
        // 调用者执行命令
        novice.action();

        // 让盗贼作为接收者执行具体命令
        Profession thieves = new Thieves();
        // 隐身命令并指定接收者
        ChangeCommand changeVisibilityCommand = new ChangeVisibilityCommand(thieves);
        // 调用者接受命令 改变龙的隐身状态
        novice.setCommand(changeVisibilityCommand);
        // 调用者执行命令
        novice.action();

    }
}

五、总结

优点

  • 命令容易扩展,当我要扩展其他的命令时,只需要依次增加具体命令角色、接收者角色即可
  • 解耦,调用者和接收者解耦,调用者只需要接收和执行命令即可,具体这个命令谁来处理我不需要指定

缺点:当有N个命令时,命令模式就会膨胀起来

代码地址: https://github.com/LuckyTeemo/design-pattern

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值