设计模式之命令模式(Command)

设计模式之命令模式(Command)

本篇为 https://github.com/iluwatar/java-design-patterns/tree/master/command 阅读笔记
典型用例

保持请求的历史
实现回调功能
实现撤消功能


目的

将请求封装为对象,从而允许使用不同的请求,队列或日志请求参数化客户端,并支持可撤销操作

场景

精灵有两种属性(大小,可见不可见),巫师可以操作这两种属性,并且可以撤销,重做(Ctrl+z,Ctrl+y),如果再加几个属性或再加几个其他物种呢?要保证可扩展性需要采用命令模式。
封装目标对象(精灵,野兽),把对目标对象属性的操作设置成命令(excute,undo,redo),巫师调用命令操作对象,这样避免了巫师直接调用目标对象,简化了操作,新的命令可以很容易添加到系统中,降低了类之间的耦合度。

目标属性枚举类型

public enum Size {

    SMAL("smal"),NORMAL("normal");

    private String title;

    Size(String title){
        this.title = title;
    }
}

public enum Visibility {

    VISIBLE("visible"), INVISIBLE("invisible");

    private String title;

    Visibility(String title) {
        this.title = title;
    }

    @Override
    public String toString() {
        return title;
    }
}

目标抽象类

public abstract class Target {
    private Size size;
    private Visibility visibility;

    public Size getSize() {
        return size;
    }

    public void setSize(Size size) {
        this.size = size;
    }

    public Visibility getVisibility() {
        return visibility;
    }

    public void setVisibility(Visibility visibility) {
        this.visibility = visibility;
    }

    @Override
    public abstract String toString();

    public void printStatus() {
        System.out.println(String.format("%s [size = %s] [visibility = %s]", this, size, visibility));
    }
}

精灵

public class Goblin extends Target {

    public Goblin(){
        setSize(Size.NORMAL);
        setVisibility(Visibility.VISIBLE);
    }

    @Override
    public String toString() {
        return "Goblin";
    }
}

命令抽象类

public abstract class Command {

    public abstract void excute(Target target);

    public abstract void undo();

    public abstract void redo();

    @Override
    public abstract String toString();
}

大小操作命令

public class ShrinkSpell extends Command {

    private Size oldSize;
    private Target target;

    @Override
    public void excute(Target target) {
        oldSize = target.getSize();
        target.setSize(Size.SMAL);
        this.target = target;
    }

    @Override
    public void undo() {
        if (oldSize != null && target != null){
            Size temp = target.getSize();
            target.setSize(oldSize);
            oldSize = temp;
        }
    }

    @Override
    public void redo() {
        undo();
    }

    @Override
    public String toString() {
        return "ShrinkSpell";
    }
}

可见性操作命令

public class InvisibilitySpell extends Command {

    private Target target;

    @Override
    public void excute(Target target) {
        target.setVisibility(Visibility.INVISIBLE);
        this.target = target;
    }

    @Override
    public void undo() {
        if (target != null){
            target.setVisibility(Visibility.VISIBLE);
        }
    }

    @Override
    public void redo() {
        if (target != null){
            target.setVisibility(Visibility.INVISIBLE);
        }
    }

    @Override
    public String toString() {
        return "Invisibility spell";
    }
}

巫师对命令进行封装

public class Wizard {

    private Deque<Command> undoStack = new LinkedList<>();
    private Deque<Command> redoStack = new LinkedList<>();

    public Wizard() {
    }

    public void castSpell(Command command, Target target) {
        System.out.println(String.format("%s casts %s at %s", this, command, target));
        command.excute(target);
        undoStack.offerLast(command);
    }

    public void undoLastSpell() {
        if (!undoStack.isEmpty()) {
            Command previousSpell = undoStack.pollLast();
            redoStack.offerLast(previousSpell);
            System.out.println(String.format("%s undo %s", this, previousSpell));
            previousSpell.undo();
        }
    }

    public void redoLastSpell() {
        if (!redoStack.isEmpty()) {
            Command prevoiuSpell = redoStack.pollLast();
            System.out.printf("%s redoes %s %n",this,prevoiuSpell);
            prevoiuSpell.redo();
        }
    }

    @Override
    public String toString() {
        return "Wizard";
    }
}

测试

@Test
public void commandTest(){
    Wizard wizard = new Wizard();
    Goblin goblin = new Goblin();

    goblin.printStatus();

    wizard.castSpell(new ShrinkSpell(), goblin);
    goblin.printStatus();

    wizard.castSpell(new InvisibilitySpell(), goblin);
    goblin.printStatus();

    wizard.undoLastSpell();
    goblin.printStatus();

    wizard.undoLastSpell();
    goblin.printStatus();

    wizard.redoLastSpell();
    goblin.printStatus();

    wizard.redoLastSpell();
    goblin.printStatus();
}

类图

在这里插入图片描述
缺点:使用命令模式可能会导致某些系统有过多的具体命令类。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

tcoding

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值