4

我发现自己需要在 java 中调用 super.super.method(),这是不可能的。

我只是想知道我的设计是否存在设计缺陷?

课程:

package solvers.command;

/**
 *
 * @author student
 */
public abstract class Command {
    private boolean executed;   //executed state

    /**
     * Constructs a new Command object.
     * 
     * @modifies    this.executed = false
     */
    public Command() {
        this.executed = false;
    }

    /**
     * Executes this command.
     * 
     * @modifies executed = true
     * @pre {@code !executed}
     * @throws IllegalStateException if {@code executed}
     */
    public void execute() {
        if (executed) {
            throw new IllegalStateException("solvers.command.Command.execute: already executed");
        }
        executed = true;
    }

    /**
     * Undoes this command.
     * 
     * @modifies executed = false
     * @pre {@code executed}
     * @throws IllegalStateException if {@code !executed}
     */
    public void undo() {
        if (!executed) {
            throw new IllegalStateException("solvers.command.Command.undo: not executed yet");
        }
        executed = false;
    }

    /**
     * Returns the executed state
     * 
     * @return executed state
     */
    public boolean getExecuted() {
        return executed;
    }
}

package solvers.command;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 *
 * @author student
 */
public class CompoundCommand extends Command {
    List<Command> commands; //list of commands

    /**
     * Creates a new CompoundCommand.
     * 
     * @modifies this.commands is initialised
     */
    public CompoundCommand() {
        super();
        this.commands = new ArrayList<>();
    }

    /**
     * Adds a command to the list of commands.
     * 
     * @param command   The new command
     * @pre {@code command != null}
     * @throws IllegalArgumentException if {@code command == null}
     */
    public void add(final Command command) {
        if (command == null) {
            throw new IllegalArgumentException("solvers.command.CompoundCommand.add: "
                    + "command == null");
        }
        commands.add(command);
    }

    /**
     * Removes a command from the list of commands.
     * 
     * @param command   The command to be removed
     * @pre {@code command != null && commands.contains(command}
     * @throws IllegalArgumentException if {@code command == null || !commands.contains(command)}
     */
    public void remove(final Command command) {
        if (command == null) {
            throw new IllegalArgumentException("solvers.command.CompoundCommand.remove: "
                    + "command == null");
        }
        if (!commands.contains(command)) {
            throw new IllegalArgumentException("solvers.command.CompoundCommand.remove:"
                    + "command is not found in commands");
        }
        commands.remove(command);
    }

    /**
     * Returns if the list of commands is empty.
     * 
     * @return {@code commands.isEmpty()}
     */
    public boolean isEmpty() {
        return commands.isEmpty();
    }

    @Override
    public void execute() {
        super.execute();
        for (Command c : commands) {
            c.execute();
        }
    }

    @Override
    public void undo() {
        super.undo();
        Collections.reverse(commands);
        for (Command c : commands) {
            c.undo();
        }
        Collections.reverse(commands);
    }
}

package solvers.command;

/**
 *
 * @author student
 */
public class ExecutedCompoundCommand extends CompoundCommand {

    /**
     * Creates a new ExecutedCompoundCommand.
     */
    public ExecutedCompoundCommand() {
        super();
    }

    @Override
    public void add(final Command command) {
        if (!command.getExecuted()) {
            throw new IllegalStateException("solvers.command.ExecutedCompoundCommand.add: "
                    + "command has not been executed yet.");
        }
        super.add(command);
    }

    @Override
    public void execute() {
        super.super.execute(); /* Does not work obviously */
        for (Command c : commands) {
            if (!c.getExecuted()) {
                c.execute();
            }
        }
    }
}

基本上我确实想要 Command 的安全性execute(),而我不希望执行CompoundCommand'execute() for ExecutedCompoundCommand,但我确实想只依赖CompoundCommand.

作为一名学生,在一个需要 javadoc 和单元测试的项目上工作,确实需要尽可能少的代码重复,因为它只会做更多的工作。

4

4 回答 4

2

我认为这是一个设计缺陷。您可以应用模板方法模式 [GOF 325]

意图:在操作中定义算法的骨架,将一些步骤推迟到子类。模板方法让子类在不改变算法结构的情况下重新定义算法的某些步骤。

来自四种设计模式的帮派

您要确保执行某些步骤。因此,您将创建一个最终模板方法 execute() 并委托给 doExecute() 方法,该方法可以添加额外的逻辑并且需要由子类实现。

public final void execute() {
  importantOperation();
  runsAlways();
  doExecute();
}

public abstract void doExecute(); // Override in subclasses
于 2013-03-30T16:09:50.960 回答
1

有几种方法可以解决这个问题,最好的方法取决于你的意图。这里有几个建议:

创建一个新类 CommandList,它支持 add()、remove() 和 undo() 操作。

CompoundCommand 扩展了 Command 并具有一个 CommandList。

ExecutedCompoundCommand 扩展了 Command 并有一个 CommandList。

另一种选择是创建一个新的 Command 子类,它支持常用操作并继承 Command 的 execute() 方法。

CompoundCommand 将扩展它并覆盖只是执行。

ExecutedCompoundCommand 也会扩展它,因此它的 super.execute() 将是 Command execute()。

于 2013-03-30T16:13:35.043 回答
1

将委托模式用于通用功能而不是继承。如果你想使用继承,或者模板模式。

于 2013-03-31T12:46:21.077 回答
0

看看这里。基本上它解释了为什么你永远不需要做你想做的事情。

正如链接中所引用的:

您不应该能够绕过父类的行为。有时能够绕过您自己的类的行为(尤其是在同一方法中)而不是您父母的行为是有意义的。

在链接中显示的示例中,所提出的论点是“中间”类可以说正在实现一些功能或有效性检查,这些功能或有效性检查将通过“跳过”层次结构中的一个类来绕过。

阅读这篇小文章,了解封装的好处。

于 2013-03-30T15:59:19.390 回答