Ho bisogno di progettare una gerarchia di classi per il mio progetto C #. Fondamentalmente, le funzionalità di classe sono simili alle classi di WinForms, quindi prendiamo come esempio il toolkit WinForms. (Tuttavia, non posso usare WinForms o WPF.)
Ci sono alcune proprietà e funzionalità principali che ogni classe deve fornire. Dimensioni, posizione, colore, visibilità (vero / falso), metodo Disegna, ecc.
Ho bisogno di una consulenza di design Ho usato un design con una classe di base astratta e interfacce che non sono realmente tipi, ma più simili a comportamenti. È un buon design? In caso contrario, quale sarebbe un design migliore.
Il codice è simile a questo:
abstract class Control
{
public int Width { get; set; }
public int Height { get; set; }
public int BackColor { get; set; }
public int X { get; set; }
public int Y { get; set; }
public int BorderWidth { get; set; }
public int BorderColor { get; set; }
public bool Visible { get; set; }
public Rectangle ClipRectange { get; protected set; }
abstract public void Draw();
}
Alcuni controlli possono contenere altri controlli, alcuni possono essere contenuti solo (come bambini), quindi sto pensando di creare due interfacce per queste funzionalità:
interface IChild
{
IContainer Parent { get; set; }
}
internal interface IContainer
{
void AddChild<T>(T child) where T : IChild;
void RemoveChild<T>(T child) where T : IChild;
IChild GetChild(int index);
}
WinForms controlla la visualizzazione del testo, quindi anche questa entra nell'interfaccia:
interface ITextHolder
{
string Text { get; set; }
int TextPositionX { get; set; }
int TextPositionY { get; set; }
int TextWidth { get; }
int TextHeight { get; }
void DrawText();
}
Alcuni controlli possono essere agganciati all'interno del controllo principale in modo che:
enum Docking
{
None, Left, Right, Top, Bottom, Fill
}
interface IDockable
{
Docking Dock { get; set; }
}
... e ora creiamo alcune lezioni concrete:
class Panel : Control, IDockable, IContainer, IChild {}
class Label : Control, IDockable, IChild, ITextHolder {}
class Button : Control, IChild, ITextHolder, IDockable {}
class Window : Control, IContainer, IDockable {}
Il primo "problema" a cui posso pensare è che le interfacce sono fondamentalmente scolpite nella pietra una volta pubblicate. Ma supponiamo che sarò in grado di rendere le mie interfacce abbastanza buone da evitare di dover apportare modifiche a loro in futuro.
Un altro problema che vedo in questo disegno è che ognuna di queste classi avrebbe bisogno di implementare le sue interfacce e la duplicazione del codice si verificherà rapidamente. Ad esempio in Label and Button il metodo DrawText () deriva dall'interfaccia ITextHolder o in ogni classe derivata dalla gestione di IContainer di bambini.
La mia soluzione a questo problema è implementare queste funzionalità "duplicate" in adattatori dedicati e inoltrare loro le chiamate. Quindi sia Label che Button avrebbero un membro TextHolderAdapter che verrebbe chiamato all'interno di metodi ereditati dall'interfaccia ITextHolder.
Penso che questo design dovrebbe impedirmi di avere molte funzionalità comuni nella classe base che potrebbero diventare rapidamente gonfie di metodi virtuali e di "codice rumore" non necessario. I cambiamenti di comportamento si otterrebbero estendendo gli adattatori e non le classi derivate da Control.
Penso che questo sia chiamato il modello "Strategia" e sebbene ci siano milioni di domande e risposte su questo argomento, vorrei chiederti le tue opinioni su ciò che prendo in considerazione per questo disegno e quali difetti puoi pensa al mio approccio.
Devo aggiungere che c'è una probabilità quasi del 100% che i requisiti futuri richiederanno nuove classi e nuove funzionalità.