java 如何在“命令”模式中实现“历史”命令?[关闭]

km0tfn4u  于 2023-05-12  发布在  Java
关注(0)|答案(1)|浏览(87)

已关闭,此问题需要更focused。目前不接受答复。
**想改善这个问题吗?**更新问题,使其仅通过editing this post关注一个问题。

2天前关闭。
Improve this question
我是编程新手。我正在用Java编写一个小应用程序,使用设计模式“命令”。
1.我创建了一个主类“App”,它扮演客户端的角色。“App”创建命令并将其发送到“Invoker”类。
1.“Invoker”已经运行命令并将命令的历史记录存储为ArrayList。
1.运行该命令会激活“Receiver”中的一个方法,该方法定义了命令的主要执行。
我有几个问题
1.如果实现“Do Something”命令不是太难,那么如何实现“History”命令呢?“Receiver”必须有一个到“Invoker”的链接吗?“Invoker”是否应该捕获“History”命令,而不运行它,自己发出请求?
1.与“退出”命令相同的问题。“App”是否应该在一开始就通过检查来捕获“Exit”命令,或者该命令应该从“Invoker”通过“Recevier”并返回到“App”?
1.我曾想过赋予所有类一个“Receiver”接口,但我认为这不是一个好主意。值得这么做吗?
我已经尝试了很多选项,其中之一是将Invoker和Receiver结合起来。但在这种情况下,“Exit”命令将需要组合和“App”类。
我还搜索了这种模式的完整示例,但它们都没有使用一个或多个类。
我可以通过一个类来实现这一切,但我真的很想理解这个模式并使用所有的类。
Upd.我被要求添加一些代码。
App.class

// creating receiver, invoker
// creating commands
invoker.execute(command);

Invoker.class

private ArrayList<Command> history = new ArrayList<>();
public void execute(Command command) {
    this.history.add(command);
    command.execute();
}

Reciever.class

public void commandA(String... args){}
public void commandB(String... args){}
// and other commands

CommandA.class扩展了ConcreteCommand

public CommandA(Receiver receiver, String... args) {
    super(receiver, args);
}

public void execute() {
    super.getReceiver().CommandA(getArgs());
}

ConcreteCommand.class

private Receiver receiver;
private String[] args;
public ConcreteCommand(Receiver receiver, String... args){}
// getter and setter for them
1u4esq0p

1u4esq0p1#

这里有一个为我工作的系统:
1.否,接收器不应参考Invoker,因为接收器的电平较低。相反,每个命令都应该知道如何撤消自己,execute方法返回一个Command,它撤消刚刚执行的命令。
下面是Command接口:

public interface Command {
    public Command execute();
}

Invoker将包含历史,看起来像这样:

public class Invoker {
    private final List<Command> history = new ArrayList<>();
    private int top;

    public void invoke(Command command) {
        while (top < history.size()) {
            history.remove(top);
        }
        history.add(command.execute());
        ++top;
    }

    public boolean canUndo() {
        return top > 0;
    }

    public void undo() {
        if (top <= 0) {
            throw new IllegalStateException("Cannot undo");
        }
        --top;
        history.set(top, history.get(top).execute());
    }

    public boolean canRedo() {
        return top < history.size();
    }

    public void redo() {
        if (top >= history.size()) {
            throw new IllegalStateException("Cannot redo");
        }
        history.set(top, history.get(top).execute());
        ++top;
    }
}

1.“Exit”命令不涉及此机制,因此没有必要为它定义命令(无论如何它都无法撤消)。
1.正如我所说,接收器是一个低级类。模式中没有Receiver接口。接收器对于处理它的命令集是已知的。你可以让一个类为接收器构建命令。
示例:操作字符串列表的命令:

public class ListHolder {
    private final List<String> list = new ArrayList<>();

    public List<String> getList() {
        return new ArrayList<>(list);
    }

    
    public Command add(String s) {
        return () -> {
            int ix = list.size();
            list.add(s);
            return remove(ix);
        };
    }
    
    public Command remove(int ix) {
        return () -> {
            String s = list.remove(ix);
            return add(ix, s);
        };
    }
    
    public Command add(int ix, String s) {
        return () -> {
            list.add(ix, s);
            return remove(ix);
        };
    }
}

更新:
示例:

Invoker invoker = new Invoker();
    ListHolder holder = new ListHolder();
    invoker.invoke(holder.add("1"));
    invoker.invoke(holder.add("2"));
    invoker.invoke(holder.add("3"));
    invoker.undo();
    invoker.undo();
    invoker.redo();
    invoker.invoke(holder.remove(0));
    invoker.invoke(holder.add("4"));
    invoker.undo();
    invoker.undo();
    invoker.invoke(holder.add("5"));
    System.out.println(holder.getList());

正如您所料,它将打印:

[1, 2, 5]

您还可以使列表保持器Invoker-aware:

public class ListHolder2 {
    private final Invoker invoker;
    private final List<String> list = new ArrayList<>();

    public ListHolder2(Invoker invoker) {
        this.invoker = invoker;
    }

    public List<String> getList() {
        return new ArrayList<>(list);
    }

    public void add(String s) {
        invoker.invoke(makeAdd(s));
    }

    public void add(int ix, String s) {
        invoker.invoke(makeAdd(ix, s));
    }

    public void remove(int ix) {
        invoker.invoke(makeRemove(ix));
    }

    private Command makeAdd(String s) {
        return () -> {
            int ix = list.size();
            list.add(s);
            return makeRemove(ix);
        };
    }

    private Command makeAdd(int ix, String s) {
        return () -> {
            list.add(ix, s);
            return makeRemove(ix);
        };
    }

    private Command makeRemove(int ix) {
        return () -> {
            String s = list.remove(ix);
            return makeAdd(ix, s);
        };
    }
}

这将简化客户端代码:

Invoker invoker = new Invoker();
    ListHolder2 holder = new ListHolder2(invoker);
    holder.add("1");
    holder.add("2");
    holder.add("3");
    invoker.undo();
    invoker.undo();
    invoker.redo();
    holder.remove(0);
    holder.add("4");
    invoker.undo();
    invoker.undo();
    holder.add("5");
    System.out.println(holder.getList());

相关问题