2013-03-30 17 views
4

我发现自己在需要在java中调用super.super.method(),这是不可能的。我需要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(); 
      } 
     } 
    } 
} 

基本上我想要的命令的​​的安全,而我不希望的execute()为ExecutedCompoundCommandCompoundCommand实施做,但我不希望只是依赖于CompoundCommand的add(),remove()和undo()操作。

作为一名学生,从事具有必需的javadoc和单元测试的项目,确实需要尽可能少的代码重复,因为它只会使更多的工作。

+0

尼斯标题btw ... – Mysticial

回答

2

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

意图:定义一个算法的骨架,在操作,deffering 一些步骤来子类。通过模板方法,子类可以在不更改算法的 结构的情况下,重新定义算法的某些步骤的 。

从四个设计模式刚

你要确保一定的步骤被执行。所以你会做一个最终的模板方法execute()并委托给doExecute()方法,该方法可以添加额外的逻辑并需要由子类实现。

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

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

我认为这个答案可能是最适合这种情况的答案。我在课堂上已经有了它,但它并没有想到。但这正是我想要做的,因为我想改变for循环内部件的行为。这似乎是合理的,而仅仅将Command类的execute()代码复制到ExecutedCompoundCommand的execute()中并不合理。 – skiwi

0

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

由于从链接引用:

你不应该能够绕过父类的行为。有时候能够绕过自己班级的行为(特别是在同一方法中),而不是父母的行为是有道理的。

在链接中显示的示例中,所谓的“中间”类正在实现一些功能或有效性检查,这些功能或有效性检查将通过“跳过”层次结构中的类来绕过。

阅读this封装的好处小文章。

+0

请引用相关信息,以便您的答案实际上回答问题。否则,只需将链接发布为评论,并将答案留给其他人! –

+0

我已经阅读过这个答案,我也了解它,但是我找不到一个直接重要(并会回答)我的问题的段落。因为我不认为我的例子100%会遵循那个答案的作者的想法。 – skiwi

+0

在这种情况下,你所要做的并不是错误,而只是不允许的。所以在我看来,最好的选择是实现add(),remove()和undo()作为接口。 –

1

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

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

CompoundCommand扩展命令并有一个CommandList。

ExecutedCompoundCommand extends Command并有一个CommandList。

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

CompoundCommand会扩展它并覆盖刚刚执行。

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

1

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