我需要翻译的文本是:I am needing super.super.method() -> Possible design flaw? 可能存在设计缺陷?我需要使用super.super.method()吗?

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()是安全的,但我不想为ExecutedCompoundCommand的execute()实现CompoundCommand,而是只想依赖于CompoundCommand的add()、remove()和undo()操作。
作为一名学生,在进行需要Javadoc和单元测试的项目时,尽可能减少代码重复非常必要,因为这只会增加更多的工作。
4个回答

2
我认为这是一种设计缺陷。您可以应用模板方法模式[GOF 325]。
意图:在操作中定义算法的框架,将某些步骤推迟到子类中。模板方法允许子类重新定义算法的某些步骤,而不改变算法的结构。
来自四人帮设计模式。
您希望确保执行某些步骤。因此,您会制作一个最终的模板方法execute()并委托给doExecute()方法,该方法可以添加附加逻辑并需要由子类实现。
public final void execute() {
  importantOperation();
  runsAlways();
  doExecute();
}

public abstract void doExecute(); // Override in subclasses

1
我认为这个答案可能是这种情况下最合适的。我在课堂上学过它,但它没有浮现在脑海中。但这正是我想要做的,因为我想改变for循环内部部分的行为。这似乎是可以证明的,而仅仅将Command类中的execute()代码复制到ExecutedCompoundCommand的execute()中并不是真正可证明的。 - skiwi

1

有几种方法可以修复这个问题,最好的方法取决于你的意图。以下是一些建议:

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

CompoundCommand扩展了Command并包含了一个CommandList。

ExecutedCompoundCommand扩展了Command并包含了一个CommandList。

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

CompoundCommand将扩展它并仅覆盖execute方法。

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


1

使用委托模式来处理通用功能,而不是继承。如果您想使用继承,则可以使用模板模式。


0

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

引用链接中的话:

您不应该能够绕过父类的行为。有时可以绕过自己类的行为(特别是从同一个方法中),但不能绕过父类的行为。

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

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


请引用相关信息以确保您的回答实际上回答了问题。否则,只需将链接作为评论发布,并将回答留给其他人! - Lightness Races in Orbit
我之前已经阅读过这个答案,也理解了它,但是我找不到一个直接重要(并可以回答)我的问题的段落。因为我认为我的例子并没有完全符合该答案的作者所想象的情况。 - skiwi
你在尝试做的事情本身并没有错,但在这种情况下是不允许的。因此,在我看来,你最好实现add()、remove()和undo()作为接口。 - Jurgen Camilleri

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接