2013-03-30 25 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

將委託模式用於常用功能而不是繼承。或者如果你想使用繼承模板模式。