Quale principio di OOAD sta rompendo questo schema?

1

Sto tentando di dimostrare di non aver inserito la struttura nella classe padre BaseModule che ho mostrato di seguito. Sono più per un modello di strategia, e riducendo al minimo l'ereditarietà a favore delle relazioni di ha-a, ma non sono veramente sicuro di quale principio di OOAD questo schema si stia rompendo.

Quale principio di OOAD sta rompendo questo schema?

Schema potenziale:

public interface IStringRenderer
{
    string Render();
}

public class BaseModel : IRequestor
{
    public abstract void  Init();
    public abstract void Load();
}

public class BaseModule<TModel> : IStringRenderer where TModel : BaseModel
{
    public TModel Model { get; set; }

    public override string Render()
    {
        return
        string.Join(
            "",
            new string[]
            {
                "<header/>",
                "<main-container>",
                    "<side-nav>",
                        "<side-navigation/>",
                    "</side-nav>",
                    "<main-content>",
                        RenderMainContent(),
                    "</main-content>"
            });
    }

    public abstract string RenderMainContent();
}

public class MyModuleModel : BaseModel
{
    public List<int> Ints { get; set; }

            ...
}

public class MyModule : BaseModule<MyModuleModel>
{
    public override string RenderMainContent()
    {
        return
        string.Join(",", Model.Ints.Select(s => s.ToString()).ToArray());
    }
}

Pattern preferito (duplicato del codice per essere chiaro):

public interface IStringRenderer
{
    string Render();
}

public class BaseModel : IRequestor
{
    public abstract void Init();
    public abstract void Load();
}

public class MyModuleModel : BaseModel
{
    public List<int> Ints { get; set; }

    ...
}

public class MyModule : IStringRenderer
{
    public MyModuleModel Model { get; set; }

    public MyModule(MyModuleModel model)
    {
        this.Model = model;
    }

    public override string Render()
    {
        return
        string.Join(
            "",
            new string[]
            {
                "<header/>",
                "<main-container>",
                    "<side-nav>",
                        "<side-navigation/>",
                    "</side-nav>",
                    "<main-content>",
                        RenderMainContent(),
                    "</main-content>"
            });
    }

    public string RenderMainContent()
    {
        return
        string.Join(",", Model.Ints.Select(s => s.ToString()).ToArray());
    }
}

Ci sono parti di questo schema su cui non sto cercando di concentrarmi, ma invece sto pensando a dove vivono la 'struttura', o 'tag'. Nel primo esempio vivono nel genitore, ma nel secondo esempio sono stati inseriti nella classe derivata.

Al momento, gli esempi sono piuttosto semplici, ma qualcosa come "side-nav" potrebbe potenzialmente complicarsi, e potrebbe comunque essere necessario controllare il bambino.

Sento che il principio qui è che non mi sento come se la struttura del 'tag' non fosse nella classe genitore come nel primo esempio. Ci sono altre cose che ho rimosso nella mia "versione preferita", vale a dire i generici. (Qualsiasi lettura suggerita di buono / cattivo per quella scelta è la benvenuta). I fautori della struttura incorporata del primo esempio come il fatto che possono esercitare modifiche su grandi quantità di classi secondarie. Ritengo che offrire la flessibilità per le classi derivate sia la strada da percorrere e, se è necessario essere genitore, il genitore offre solo funzionalità e funzionalità trasversali, ma non imbottiglia la struttura in scatola.

    
posta lucidquiet 10.05.2013 - 00:30
fonte

2 risposte

1

Puoi avere il meglio di entrambi i mondi. Nella classe BaseModule<TModel> , quando implementi (hai digitato override lì, che non è corretto) il metodo Render() , puoi contrassegnarlo come virtual . In questo modo, le classi figlio che necessitano di un set di base di tag possono semplicemente utilizzare la classe base Render() , mentre le classi figlio con esigenze più particolari potrebbero sovrascriverle.

Informazioni sui generici, non li stai utilizzando in BaseModule<> ... a meno che tu non stia utilizzando un costruttore (non mostrato) che inizializza la proprietà Model per tutte le classi derivate, forse? In tal caso hanno il loro uso qui, dal momento che vincolano il tipo che si può passare e svuotano le classi derivate dal dover inizializzarle autonomamente. Questo è più simile a un approccio "quadro", in cui una classe base abstract viene utilizzata solo per fornire funzionalità comuni ma sovrascrivibili alle classi concrete derivate.

    
risposta data 10.05.2013 - 13:57
fonte
1

Panoramica

Sembra simile a CommonClosurePrinciple , ma avviene su un livello di classe e di metodi invece di un pacchetto-e- livello di lezioni. Vale a dire,

--Classes-- (methods) within a released --component-- (a class) should share common closure. If one (method) needs to be changed, they all (methods) are likely to need to be changed. What affects one, affects all.

(I added the words in brackets.)

Inoltre, il principio che può essere ricavato da questo esempio di codice è uno debole , il che significa che non è universalmente applicabile . Ci sono ovviamente casi in cui le modifiche non / non dovrebbero devono essere concentrate in una singola classe!

In questa particolare domanda, la validità di questo principio dipende dal fatto che i (1) tag HTML e (2) il codice da modello a stringa siano tipicamente modificati insieme quando c'è un cambiamento nel modello.

Il codice

In entrambe le versioni, MyModule è il posto per la logica della colla che esiste tra Model e IStringRenderer.Render() .

Nella prima versione, i tag HTML ( <main-content>...</> ) sono un servizio fornito da BaseModule .

  • Se lo stesso codice di wrapping è riutilizzato molte volte per molti modelli diversi, questa è una scelta corretta.
  • Se ciascun modello ha finito per dover personalizzare i suoi tag HTML, la classe BaseModule nella prima versione verrà utilizzata solo una volta .

Nella seconda versione, entrambe le parti della logica della colla sono contenute nella classe foglia ( MyModule ):

  • La conversione di numeri interi (modello) in una stringa e
  • I tag HTML

Pertanto, la seconda versione consente di modificare il rendering del modello e il codice di wrapping HTML.

Opinione:

Se ti viene in mente che ogni modello richiede tag HTML diversi, allora direi che la prima versione è non sufficiente , mentre la seconda è. Altrimenti, entrambe le versioni vanno bene.

Se si deve cercare un nome per il principio, sarebbe lungo la linea di "... metodi che devono essere cambiati insieme per la ragione stesso ( modifica del modello ), sarebbe bello da inserire nella stessa classe .

(Sottolineo "sarebbe bello" perché è un principio debole, o, una regola empirica e non un vero principio.)

Sembra simile a CommonClosurePrinciple , ma applicato a un livello di classe e metodi invece di un pacchetto-e- livello di classe.

    
risposta data 09.06.2013 - 19:30
fonte

Leggi altre domande sui tag