Необязательный компонент функциональности против SRP - PullRequest
1 голос
/ 15 июня 2011

У меня проблема с дизайном, с которой я сейчас сталкиваюсь.

Допустим, существует иерархия компонентов. Каждый из этих компонентов происходит от абстрактного 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 ]

1 голос
/ 15 июня 2011

Возможный вариант:

Если реализация поиска / выбора выбирается посредством шаблона стратегии (внедрение зависимости), как вы говорите, тогда я думаю, что интерфейсы для ISearchable и ISelectable - лучшая идея.

Вы можете получить объект своей стратегии из этих интерфейсов и реализовать для них методы получения в своем классе базовых компонентов - GetSearchable (), GetSelectable () - где реализация по умолчанию в Компоненте возвращает ноль (или неопределяемая реализация интерфейс, если вам не нравится нуль).

0 голосов
/ 19 июня 2011

Хорошо, еще один: на этот раз вы также знаете точки расширения компонента.с рисунком, похожим на посетителя

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
        }
    }
0 голосов
/ 17 июня 2011

Почему вы не используете декоратор?

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