2009-12-16 91 views
6

設計模式的問題,我不知道是否有應該在這裏使用的模式,但這裏的情況是:可維護性

我有許多實現接口的具體類:

public interface IPerformAction 
{ 
    bool ShouldPerformAction(); 
    void PerformAction(); 
} 

我有另一個類來檢查輸入,以確定是否應該執行ShouldPerformAction。蹭的是,新的檢查相當頻繁地加入。爲檢查類的接口定義如下:每次

public class ConcreteClass : IPerformAction 
{ 
    public IShouldPerformActionCheck ShouldPerformActionChecker { get; set; } 

    public string Property1 { get; set; } 
    public string Property2 { get; set; } 
    public int Property3 { get; set; } 

    public bool ShouldPerformAction() 
    { 
     return 
     ShouldPerformActionChecker.CheckA(this.Property1) || 
     ShouldPerformActionChecker.CheckB(this.Property2) || 
     ShouldPerformActionChecker.CheckC(this.Property3); 
    } 

    public void PerformAction() 
    { 
     // do something class specific 
    } 
} 

現在:

public interface IShouldPerformActionChecker 
{ 
    bool CheckA(string a); 
    bool CheckB(string b); 
    bool CheckC(int c); 
    // etc... 
} 

最後我現在有具體的類調用每個特定於該具體類的檢查方法與數據我添加一個新的支票,我必須重新構造具體的類以包含新的支票。每個具體類都將不同的屬性傳遞給檢查方法,所以具體類的子類不是一個選項。關於如何以更清潔的方式實施這些想法的任何想法?

+0

我個人認爲,當前的方法是很乾淨。我們在講多少課?新的支票進來後,真的很難調整必要的具體課程嗎?我認爲不管你如何削減它,你仍然會得到一些你必須調整的具體課程。避免這種情況的唯一方法是在具體類使用的某處執行「CheckAll()」樣式函數。總體而言,我認爲無需調整的性能提高不會超過泥土因素。 – mike 2009-12-16 03:22:45

回答

2

「CheckA」,「CheckB」等名稱,大概是爲了避免暴露機密信息而選擇的,也混淆了類之間關係的性質,所以我必須加以解釋。

但是,這是非常接近double dispatch,除非您正在執行中間對象的轉換。

編輯:嘗試播放雙「調度模式」的書「,而不是分解對象中派遣。要做到這一點,你需要像下面這樣:

public interface IPerformAction 
{ 
    bool ShouldPerformAction(IShouldPerformActionChecker checker); 
    void PerformAction(); 
} 

public interface IShouldPerformActionChecker 
{ 
    bool CheckShouldPerformAction(FloorWax toCheck); 
    bool CheckShouldPerformAction(DessertTopping toCheck); 
    // etc... 
} 

public class FloorWax : IPerformAction 
{ 
    public string Fragrance { get; set; } 

    // Note that the text of this method is identical in each concrete class, 
    // but compiles to call a different overload of CheckShouldPerformAction. 
    public bool ShouldPerformAction(IShouldPerformActionChecker checker) 
    { 
     return checker.CheckShouldPerformAction(this); 
    } 
} 

public class DessertTopping: IPerformAction 
{ 
    public string Flavor { get; set; } 

    // Note that the text of this method is identical in each concrete class, 
    // but compiles to call a different overload of CheckShouldPerformAction. 
    public bool ShouldPerformAction(IShouldPerformActionChecker checker) 
    { 
     return checker.CheckShouldPerformAction(this); 
    } 
} 

public class ShimmerApplicationChecker : IShouldPerformActionChecker 
{ 
    // handles binding of FloorWax class to required checks 
    public bool CheckShouldPerformAction(FloorWax toCheck) 
    { 
     return CheckAroma(toCheck.Fragrance); 
    } 

    // handles binding of DessertTopping class to required checks 
    public bool CheckShouldPerformAction(DessertTopping toCheck); 
    { 
     return CheckAroma(toCheck.Flavor); 
    } 

    // some concrete check 
    private bool CheckAroma(string aroma) 
    { 
     return aroma.Contains("chocolate"); 
    } 
} 
+0

謝謝Jeffey。很好的解釋。 – bmancini 2009-12-16 15:38:15

0

當你創建一個新的CheckN時,你將不得不在每個具體的檢查器類中實現它,不是嗎?

或者您是否在談論重構您的IPerformActions以實際調用該支票?

爲什麼不只是有一個叫做一切的CheckAll

+0

對CheckN的每次調用都將具有特定於調用它的具體類的數據。 CheckAll方法可以工作,但它仍然需要具體的類將其特定的數據應用到它。考慮得越多,我就越想越多,實際上沒有辦法阻止每次增加都要進入具體課程。 我想一個替代方案是ShouldPerformActionCheckerFactory,並在那裏應用具體的類特定邏輯。我不確定那是不是隻是混濁了水。 – bmancini 2009-12-16 01:24:36

+0

如果您必須針對哪個數據傳遞給哪個方法做出特定於類的決定,那麼無論您使用哪種方式對其進行分片,您都必須在添加其他校驗時調整每個類。 – 2009-12-16 01:39:37

+0

不一定。看到我的雙重調度的描述。 – 2009-12-16 02:20:48

1

你可以鞏固支票兌換成接受一個對象的單個一般方法:

public interface IShouldPerformActionChecker 
{ 
    bool Check(object o); 
} 

然後在你的具體類這些檢查列表:

public List<IShouldPerformActionCheck> ShouldPerformActionChecker { get; set; } 

以下類型安全,但更靈活。

而不是使用IShouldPerformActionCheck你可以看看使用Predicate<T>委託,這大致相同的事情。

3

讓我們退一步 - 爲什麼您首先使用接口?在IPerformAction的多個實現之間可以共享IShouldPerformActionCheck的單個實現嗎?看起來答案是否定的,因爲ICheck必須知道Action上的特定於實現的屬性(Property1,Property2,Property3)才能執行檢查。因此,IAction和ICheck之間的關係需要比IAction合同可以提供給ICheck更多的信息。看來你檢查類,應根據被耦合到特定類型的動作的具體實現,他們檢查,如:

abstract class CheckConcreteClass 
{ 
    abstract void Check(ConcreteClass concreteInstance); 
} 
+0

是的,IShouldPerformCheck的單個實現可以共享。它實際上執行共享驗證規則,例如驗證IP未被阻止,電子郵件未被阻止,或者該關鍵字未被阻止。所有對IShouldPerformCheck重要的是,輸入是特定於驗證規則的。具體的類可以以不同的方式提供這些輸入。例如,關鍵字檢查可能包括具體類的幾個不同的屬性。 – bmancini 2009-12-16 01:34:06

0

而是有具體的類嘗試檢查是否應執行的動作,有可能成爲安排這些對象的更可維護的方式。

如果檢查程序實際執行了IPerformAction並且有一個IPerformAction成員,如果該操作應該執行,它會調用該怎麼辦?該成員可以是鏈中的另一個檢查器,或者如果所有條件都已通過,那麼執行該操作的實際類將是?

要做到這一點,可能需要稍微重構,以便執行該操作的邏輯包含在一個類中,而要使用的特定數據位於另一個類中(類似於Command模式),以便檢查員可以完成他們的工作。

通過這種方式,您可以輕鬆添加另一個驗證規則,只需將其放入導致最終操作的對象的「鏈」中即可。

0

你可以嘗試這樣的:

List<IShouldPerformActionChecker> checkers = new List<IShouldPerformActionChecker>(); 

//... add in each checker to try 

foreach(ConcreteClass objectToCheck in checkset) { 
    bool isGood = true; 
    foreach(IShouldPerformActionChecker checker in checkers) { 
     isGood &= checker.DoCheck(objectToCheck.Property); 

     if (!isGood) { break; } 
    } 

    //handle failed check here 
}