可选组件功能与SRP

时间:2011-06-15 09:09:14

标签: components single-responsibility-principle coupling

我目前遇到了一个设计问题。

假设有一个组件层次结构。这些组件中的每一个都源自抽象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);
    }
}

您会选择哪种策略或者您有更好的想法?

提前致谢!

3 个答案:

答案 0 :(得分:1)

可能的选择:

如果通过策略模式(依赖注入)提供可搜索性/可选择性实现,正如您所说,那么我认为ISearchable和ISelectable的接口是更好的主意。

您可以从这些接口派生您的策略对象,并在您的base-Component类中实现它们的getter - GetSearchable(),GetSelectable() - 其中Component中的默认实现返回null(或者是no-op实现的界面,如果你不喜欢null)。

答案 1 :(得分:0)

你为什么不使用装饰师?

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

答案 2 :(得分: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
        }
    }