2014-05-23 32 views
5

處理具體類型時,比方說,我有下面的類層次結構:替代品的instanceof在Java中

public interface Result { 
} 
public class Failure implements Result { 
    private String msg; 
    public Failure(String msg) { 
     this.msg = msg; 
    } 
    @Override public String toString() { return msg; } 
} 
public class Success implements Result { 
    private int time, count; 
    public Success(int time, int count) { this.time = time; this.count = count; } 
    public int getTime() { return time; } 
    public int getCount() { return count; } 
    @Override public String toString() { return time + ", " + count; } 
} 

基本上定義包含兩個具體類的接口。結果:成功和失敗。

然後,我有一個返回結果,並根據結果我應該做的事情,例如一個計算方法:

Result result = calculate(); 

我有幾種選擇弄明白具體類。其中最明顯的是使用的實例:

if (result instanceof Success) { 
    int time = result.getTime(); 
    int count = result.getCount(); 
    // Do something with them 
} else { 
    throw new RuntimeException(result.toString()); 
} 

在比如Scala支持模式匹配的編程語言,我可以用一根火柴一樣

case Success => 
case Failure => 

但由於Java不支持的話,我我不確定最好做什麼。我可以例如延伸Result接口如下:

public interface Result { 
    public boolean isSuccess(); 
    public boolean isFailure(); 
    public Success asSuccess(); 
    public Failure asFailure(); 
} 

,然後編寫客戶端代碼爲:

if (result.isSuccess()) { 
    Success success = result.asSuccess(); 
    int time = success.getTime(); 
    int count = success.getCount(); 
    // Do something with them 
} else { 
    throw new RuntimeException(result.toString()); 
} 

但在這種情況下,接口綁定具體類這也不好。

代表這種情況的最佳方式是什麼?我真的不想把處理代碼放在Result層次結構中,因爲它真的取決於客戶端來獲取數據並做他們想做的任何事情,所以多態調度解決方案可能不是最好的。結果層次至多是數據類型封裝,不是操作。

回答

0

這可以簡化爲

public interface Result { 
    public boolean isSuccess(); 
    public Integer getTime(); 
    public Integer getCount(); 
} 

你必須實施失敗的次數和時間(返回零/ null或拋出異常),然後輸入:

if (result.isSuccess()) { 
    int time = result.getTime(); 
    int count = result.getCount(); 
    // Do something with them 
} 
else { 
    throw new RuntimeException(result.toString()); 
} 

你不在界面上不需要使用String,但是您可能想要明確地告訴其他開發人員擔心是否會在未來實現另一個結果(BigSuccess,MssvieFail等)。

結果上的布爾值,表示成功似乎簡單直觀。

0

這裏有一點要注意的是,如果你的代碼result.isSuccess()回報true,你並不需要有一個asSuccess()方法將其轉換爲Success,你可以簡單的使用型鑄造(Success) result,不用擔心它會拋出一個運行時異常。

我不認爲instanceof是多大不了的這一點,但如果你仍然想有一個解決辦法,我在想,也許的類似的東西:

public interface Result { 
    public String getType(); 
} 

public class Success implements Result { 
    public static final String TYPE = "Success"; 

    //..... Some class relevant code here 

    public String getType() { 
     return TYPE; 
    } 
} 

public class Failure implements Result { 
    public static final String TYPE = "Failure"; 

    //..... Some class relevant code here 

    public String getType() { 
     return TYPE; 
    } 
} 

然後,如果你是使用7 JDK版本或更高支持與絃樂 switch語句),你可以嘗試以下方法:

switch(result.getType()) { 
    case Success.TYPE: 
     //Success code here 
    case Failure.TYPE: 
     //Failure code here 
} 

我沒有測試過這個,但我認爲它會滿足您的需求。

我希望我幫你!

0

接口中的其他字段不會限制該接口的「可用性」。正常接口被設計爲被具體類使用。

在你的情況下,我更喜歡處理「成功」和「失敗」的通用結果類。

0

還有一個選項:訪問者模式:

public interface ResultVisitor { 
    void handleSuccess(Success result); 
    void handleFailure(Failure result); 
} 

public interface Result { 
    void accept(ResultVisitor visitor); 
} 
public class Failure implements Result { 
    private String msg; 
    public Failure(String msg) { 
     this.msg = msg; 
    } 
    @Override public String toString() { return msg; } 
    @Override void accept(ResultVisitor visitor) {visitor.visit(this);} 
} 
public class Success implements Result { 
    private int time, count; 
    public Success(int time, int count) { this.time = time; this.count = count; } 
    public int getTime() { return time; } 
    public int getCount() { return count; } 
    @Override public String toString() { return time + ", " + count; } 
    @Override void accept(ResultVisitor visitor) {visitor.visit(this);} 
} 

然後,地方在你的代碼:

result.accept(new ResultVisitor() { 
    void handleSuccess(Success success) { 
     // do something with success 
    } 
    void handleFailure(Failure failure) { 
     // do something with failure 
    } 
}); 
0

如果沒有隻有兩種亞型,那麼訪問者模式將是合適的。試想一下:

interface Result { 
    // resut of the implementation 
    public <T> T accept(Visitor<T> visitor); 
} 

class Success implements Result { 
    @Override 
    public <T> T accept(Visitor<T> visitor) { 
     return visitor.visit(this); 
    } 
} 

class Failure implements Result { 
    @Override 
    public <T> T accept(Visitor<T> visitor) { 
     return visitor.visit(this); 
    } 
} 

然後創建一個訪問者類:

interface Visitor<T> { 
    T visit(Failure failure); 
    T visit(Success success); 
} 

然後在那裏你會使用instanceof

Result result = ...; 
// this could be something else, with a different template parameter. 
String visitorResult = result.accept(new Visitor<String>() { 
    @Override 
    public String visit(Failure failure) { 
     return "Failure visited"; 
    } 

    @Override 
    public String visit(Success success) { 
     return "Success visited"; 
    } 
}); 

這只是我實現的想法,你可以添加更多的仿製藥可定製的功能。如果您想了解更多關於此:http://en.wikipedia.org/wiki/Visitor_pattern

2

IMO,這是「標記接口」模式的不當使用。你確實想使用界面定義的一些功能,那麼不要把它作爲標記。爲了使其通用,你可能想知道Result的類型/類別,如Success, Error, Fatal, Warning, etc...,你可以考慮做一個枚舉,enum ResultType並在你的界面中,除了功能方法(getTime, getCount...)加上getType()或者,只需使用abstract class Result並聲明protected Type type即可。

要決定具體的類型並做相應的操作,可以考慮在這些枚舉類型上使用case語句。但是您不必將它們轉換爲具體類型,因爲您需要的所有功能都是在接口/摘要類Result中定義的。

對於缺乏代碼示例感到抱歉。現在不方便編碼。

0

但在這種情況下,接口綁定到具體的類別,這是不好的。

如果這是您的擔憂,並且您希望有更多的成功和失敗實現,那麼只需創建成功和失敗界面。

所有對象都有一個toString(),所以你可能不需要失敗。