Ich muss eine Klassenhierarchie für mein C # -Projekt entwerfen. Grundsätzlich ähneln die Klassenfunktionen den WinForms-Klassen. Nehmen wir als Beispiel das WinForms-Toolkit. (Ich kann jedoch weder WinForms noch WPF verwenden.)
Es gibt einige grundlegende Eigenschaften und Funktionen, die jede Klasse bereitstellen muss. Maße, Position, Farbe, Sichtbarkeit (wahr / falsch), Zeichenmethode usw.
Ich brauche Designberatung Ich habe ein Design mit einer abstrakten Basisklasse und Schnittstellen verwendet, die keine echten Typen sind, sondern eher Verhaltensweisen. Ist das ein gutes Design? Wenn nicht, was wäre ein besseres Design.
Der Code sieht folgendermaßen aus:
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();
}
Einige Steuerelemente können andere Steuerelemente enthalten, andere können nur (als untergeordnete Elemente) enthalten sein. Daher denke ich darüber nach, zwei Schnittstellen für diese Funktionen zu erstellen:
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 steuert den Anzeigetext, sodass dies auch in die Benutzeroberfläche eingeht:
interface ITextHolder
{
string Text { get; set; }
int TextPositionX { get; set; }
int TextPositionY { get; set; }
int TextWidth { get; }
int TextHeight { get; }
void DrawText();
}
Einige Steuerelemente können in ihrem übergeordneten Steuerelement angedockt werden.
enum Docking
{
None, Left, Right, Top, Bottom, Fill
}
interface IDockable
{
Docking Dock { get; set; }
}
... und jetzt erstellen wir einige konkrete Klassen:
class Panel : Control, IDockable, IContainer, IChild {}
class Label : Control, IDockable, IChild, ITextHolder {}
class Button : Control, IChild, ITextHolder, IDockable {}
class Window : Control, IContainer, IDockable {}
Das erste "Problem", das mir hier einfällt, ist, dass die Schnittstellen nach ihrer Veröffentlichung im Grunde genommen in Stein gemeißelt sind. Nehmen wir jedoch an, dass ich meine Benutzeroberflächen so gut gestalten kann, dass sie in Zukunft nicht mehr geändert werden müssen.
Ein weiteres Problem, das ich in diesem Entwurf sehe, ist, dass jede dieser Klassen ihre Schnittstellen implementieren müsste und dass eine Vervielfältigung von Code schnell erfolgen wird. Beispielsweise wird in Label und Button die DrawText () -Methode von der ITextHolder-Schnittstelle oder von jeder Klasse abgeleitet, die aus der IContainer-Verwaltung von untergeordneten Elementen stammt.
Meine Lösung für dieses Problem besteht darin, diese "duplizierten" Funktionen in dedizierten Adaptern zu implementieren und Aufrufe an diese weiterzuleiten. Daher hätten sowohl Label als auch Button einen TextHolderAdapter-Member, der innerhalb von Methoden aufgerufen würde, die von der ITextHolder-Schnittstelle geerbt wurden.
Ich denke, dieses Design sollte mich davor schützen, dass ich zu viele gemeinsame Funktionen in der Basisklasse habe, die mit virtuellen Methoden und unnötigem "Rauschcode" schnell aufgebläht werden könnten. Verhaltensänderungen würden durch Erweitern von Adaptern und nicht durch von Steuerelementen abgeleitete Klassen erreicht.
Ich denke, dies wird das "Strategie" -Muster genannt, und obwohl es zu diesem Thema Millionen von Fragen und Antworten gibt, möchte ich Sie um Ihre Meinung bitten, was ich für dieses Design in Betracht ziehe und an welche Fehler Sie denken können mein Ansatz.
Ich sollte hinzufügen, dass es eine fast 100% ige Chance gibt, dass zukünftige Anforderungen neue Klassen und neue Funktionalitäten erfordern.
IChild
scheint wie ein schrecklicher Name.
System.ComponentModel.Component
oderSystem.Windows.Forms.Control
einer der anderen vorhandenen Basisklassen erben ? Warum müssen Sie eine eigene Steuerelementhierarchie erstellen und alle diese Funktionen neu definieren?