2015-09-14 88 views
1

我這是在課堂上使用類似下面的界面避免鑄造}這種

public interface Details { 
    // nothing needed until now 
} 

public class Value { 
    // many fields 
    private Details details; 

    public Value(SomeType type) { 
     switch (type) { 
     case TYPE_1: 
     case TYPE_2: 
      this.details = new DetailsA(); 
      break; 
     case TYPE_3: 
      this.details = new DetailsB(); 
      break; 
     default: 
      throw new NotImplementedException("not yet implemented"); 
     } 
    } 

    public Details getDetails() { 
     return this.details; 
    } 
} 

的接口有兩個實現

public class DetailsA implements Details { 

    private BigDecimal betragA; 

    public DetailsA() { 
    } 

    public BigDecimal getBetragA() { 
     return this.betragA; 
    } 

    public void setBetragA(BigDecimal betragA) { 
     this.betragA = betragA; 
    } 

} 

public class DeailsB implements Details { 

    private BigDecimal betragB; 
    private boolean booleanB; 

    public BetragB() { 
    } 

    public BigDecimal getBetragB() { 
     return this.betragB; 
    } 

    public void setBetragB(BigDecimal betragB) { 
     this.betragB = betragB; 
    } 

    public boolean isBooleanB() { 
     return this.booleanB; 
    } 

    public void setBooleanB(boolean booleanB) { 
     this.booleanB = booleanB; 
    } 

    // some more fields 

} 

我得到了一個模型類,我想要使用這些細節,具體取決於實例。

public class Model extends AbstractModel { 

    private Details details; 

    public void init(StoerungValue stoerung) { 
     setDetails(stoerung.getSchaden().getDetails()); 
    } 

    private void setDetails(Details details) { 
     this.details = details; 
    } 
    // ... 

在那裏我有一個像下面

// ... 
    public void setBooleanB(boolean booleanB) { 
     if (details instanceof DetailB) { 
      ((DetailB) details).setBooleanB(booleanB); 
     } 
    } 
    // ... 

一些操作我怎樣才能避免這種鑄造}這種東西?這裏有適用的設計模式嗎?

+2

您是否考慮過將isBoolean和setBoolean函數添加到接口中並將它們添加到這兩個類,其中類A的實現什麼都不做? – xception

+3

這裏你可能有一個抽象問題。 如果您的操作需要知道細節的實現是什麼,它應該直接與受支持的實現協同工作。否則,每次添加新的實現時,都必須更新操作代碼,這與抽象模型相違背。 或者,您的操作只能處理所有細節實現的常見操作,並將特定於實現的處理委託給接口中的專用方法。 –

+1

沒有方法的接口是一種設計氣味。接口的全部目的是定義一個對象必須遵守的交互協議。如果該協議不包含任何方法,那麼它只提供「Object」。你所有的'Details'類都有一個通用的交互模式,或者它們不是。如果他們不相關,他們的類型應該反映這一點。如果他們這樣做,那麼接口應該定義這種關係。 –

回答

3

我認爲你在這裏遇到的問題是設計氣味的集合。你已經把自己描繪在一個角落,並且可能不是一個簡單的出路。我不知道這種解決方案是否適用於您,但您至少可以考慮這一點。

第一個設計嗅覺是你已經創建了一個沒有實際存在的繼承關係。總之,根植於Details的層次結構違反了Liskov Substitution Principle。當一個類聲明(如Model)支持Details接口時,它聲稱Details的任何執行。程序的正確性和行爲不應該改變,不管它是否被給出DetailsADetailsB或一些還沒有被髮明的FooDetails類。

現實情況是,DetailsADetailsB實際上並沒有關聯。你可以看到這個,因爲Details沒有方法,因此也可能是Object其中任何兩個類已經繼承。

第二個設計氣味是「特徵嫉妒」。看起來Model的許多方法只是對其底層details屬性的傳遞調用。您可以考慮,而不是讓上的setBooleanB只提供getDetails方法,然後讓呼叫者直接在Details對象上工作。這不會刪除instanceof檢查或投射,但會將它們移出此類。

這裏的第三件事是前兩件相關的兩件事。 Model不取決於Details,因爲它的屬性類型會告訴你,而不是(至少)DetailsB。如果是這種情況,那麼它的屬性類型應該這樣說。現在,它可能是有時你需要一個ModelDetailsA有時你需要一個DetailsB一個Model,但它不能同時同時。在這種情況下,你可以用泛型來解決這個問題。

首先,使Model類具有通用性,並帶有一個類型參數,該參數告知其基本Details實際上必須是什麼。

public abstract class Model<T extends Details> { 
    private T details; 

    public void init(T dets) { 
     setDetails(dets); 
    } 

    public void setDetails(T dets) { 
     this.details = dets; 
    } 

    public T getDetails() { 
     return this.details; 
    } 
} 

然後,創建綁定到不同類型的Details兩個子類,因此可以答應做正確的事情,而不需要鑄造或電話的instanceof。

public class ModelA extends Model<DetailsA> { 
    public BigDecimal getBetragA() { 
     return this.getDetails().getBetragA(); 
    } 
} 

public class ModelB extends Model<DetailsB> { 
    public boolean getBooleanB() { 
     return this.getDetails().isBooleanB(); 
    } 

    public void setBooleanB(boolean boolB) { 
     this.getDetails().setBooleanB(boolB); 
    } 
} 

我不確定這是否能解決您的問題,但這是需要考慮的問題。