2011-06-15 27 views
1

我有一個設計問題,我目前遇到的問題。可選組件功能VS SRP

比方說,有分量的層次結構。每個組件從抽象Component型看起來是這樣的推導:

public abstract class Component 
{ 
    public abstract Component Parent { get; } 
    public abstract ComponentCollection Children { get; } 
} 

現在我想一些可選功能添加到這些組件,讓我們能夠在組件層次結構中搜索和選擇中的組件層次結構作爲例子。

是它認爲不好的做法,提供了基類這樣的可選功能:

public abstract class Component 
{ 
    // Other members 

    public abstract bool IsSearchable { get; } 
    public abstract bool Search(string searchTerm); 

    public abstract bool IsSelectable { get; } 
    public abstract bool Select(); 
} 

雖然「搜索能力」和「選擇能力」的通過,例如衍生部件進行管理使用戰略模式?

不知怎的,這似乎是違反了SRP給我,但在我看來,唯一的選擇就是讓每個可選功能的接口,只有實現它在支持此功能部件。

在我看來,這將有一個我必須寫這樣的代碼,每次我要檢查的缺點,如果一個組件提供特定功能:

public bool Search(Component component, string searchTerm) 
{ 
    ISearchable searchable = component as ISearchable; 
    if(searchable != null) 
    { 
     searchable.Search(searchTerm); 
    } 
} 

你會選擇還是你哪種策略有什麼更好的想法?

提前感謝!

+0

爲什麼你指出的缺點與你當前的代碼有很大的不同,它必須首先檢查component.IsSearchable()? – 2011-06-15 09:18:14

+0

這是我不確定的。就我個人而言,我會考慮檢查一個屬性比檢查對象的類型更清潔(可能更快)。 – 2011-06-15 09:21:31

+1

概念上,對象的類型是它的一個屬性(一般意義上),所以這不是問題。性能可能是一個問題,並且可能會使用C++之類的語言,但可能不是Java或C#。還要考慮具有ISearchable接口的好處 - 您可能也有可搜索的非組件。 – 2011-06-15 09:24:24

回答

1

一個可能的選項:

如果可搜索/可選擇的實施將通過策略模式(依賴注入)提供的,就像你說的,那我覺得ISearchable和ISelectable接口是一個更好的主意。

您可以從這些接口派生您的策略對象,並在您的base-Component類中爲它們實現getter - GetSearchable(),GetSelectable() - Component中的默認實現返回null(或者無操作實現界面如果你不喜歡空)。

+0

謝謝你,對我來說似乎很合理。我會盡力這樣做。 – 2011-06-17 07:21:10

0

你爲什麼不使用的裝飾?

Component c = new Component(); 
var selectableAndSearchableOne = new SelectableComponent (new SearchableComponent (c)); 
+0

我非常喜歡這個想法,但是如何在使用'Component'時如何訪問select/search功能? – 2011-06-17 07:18:01

+0

該解決方案的潛在缺點是它必須在編譯時工作 - 即SearchableComponent必須可以從Component構建。在這種情況下,這聽起來不像是一個問題,但我可以想象在編譯時不知道「c」是否實際上是可搜索/可選類型的場景。另一方面,如果你真的想強制所有的組件至少是默認搜索和可選的,那麼當你犯了一個錯誤時得到編譯時錯誤是肯定的,而不是負面的。 – 2011-06-17 07:44:11

+0

我沒有看到任何缺點。你提到的要求是「我想要可搜索的組件」,這是我認爲的設計漏洞。它刻畫出複雜性。這不是組件的責任(位於更高層次的層面)。 – 2011-06-18 22:40:17

0

好的另一個:這次你也知道組件的擴展點。與訪客般的模式

public interface IHasExtensions 
    { 
     List<Extension> Extensions { get; } 
     void Extend (Extension ext); 
    } 

    public class Component : IHasExtensions 
    { 
     List<Extension> exts = new List<Extension>(); 

     public List<Extension> Extensions 
     { 
      get { return exts; } 
     } 

     public void Extend (Extension ext) 
     { 
      exts.Add (ext); 
     } 

     void Draw() { } 
    } 

    public abstract class Extension 
    { 
     readonly protected Component _Component; 

     public Extension(Component component) 
     { 
      _Component = component; 
     } 
    } 

    public class SearchExtension : Extension 
    { 
     public SearchExtension (Component component) : base (component) 
     { 

     } 
    } 

    public class SelectionExtension : Extension 
    { 
     public SelectionExtension (Component component) : base (component) 
     { 

     } 
    } 

    public class test_fly 
    { 
     void start() 
     { 
      Component c = new Component(); 
      c.Extend (new SearchExtension (c)); 
      c.Extend (new SelectionExtension (c)); 

      var exts = c.Extensions; // I Know the extensions now 
     } 
    }