Domanda

Ho un problema di progettazione che riscontro attualmente.

Diciamo che esiste una gerarchia di componenti.Ognuna di queste componenti deriva da un abstract Component tipo che assomiglia a questo:

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

Ora voglio aggiungere alcune funzionalità opzionali a questi componenti, prendiamo la possibilità di effettuare ricerche all'interno della gerarchia dei componenti e di selezionare i componenti all'interno della gerarchia come esempi.

È considerata una cattiva pratica fornire quelle funzionalità opzionali nella classe base come questa:

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();
}

Mentre la "capacità di ricerca" e la "capacità di selezione" sono gestite in componenti derivati ​​ad es.utilizzando modelli di strategia?

In qualche modo questa mi sembra una violazione dell'SRP, ma a mio avviso l'unica alternativa sarebbe avere un'interfaccia per ogni funzionalità opzionale e implementarla solo sui componenti che supportano questa funzionalità.

Secondo me questo avrebbe lo svantaggio di dover scrivere codice come questo ogni volta che voglio verificare se un componente fornisce funzionalità specifiche:

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

Quale strategia sceglieresti o hai qualche idea migliore?

Grazie in anticipo!

È stato utile?

Soluzione

Una possibile opzione:

Se l'implementazione della ricercabilità/selezionabilità viene fornita attraverso il modello di strategia (iniezione di dipendenza), come dici tu, allora penso che le interfacce per ISearchable e ISelectable siano un'idea migliore.

Puoi derivare il tuo oggetto strategia da queste interfacce e implementare per essi i getter nella classe Base-Component - GetSearchable(), GetSelectable() - dove l'implementazione predefinita in Component restituisce null (o un'implementazione no-op dell'interfaccia se tu antipatia nulla).

Altri suggerimenti

Perché non usi il decoratore?

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

Ok, un altro:questa volta conosci anche i punti di estensione del componente.con uno schema simile a quello dei visitatori

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
        }
    }
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top