2011-06-15 44 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 
     } 
    }