Muszę zaprojektować hierarchię klas dla mojego projektu w języku C #. Zasadniczo funkcje klas są podobne do klas WinForms, więc weźmy na przykład zestaw narzędzi WinForms. (Nie mogę jednak użyć WinForms ani WPF.)
Istnieje kilka podstawowych właściwości i funkcjonalności, które musi zapewnić każda klasa. Wymiary, pozycja, kolor, widoczność (prawda / fałsz), metoda rysowania itp.
Potrzebuję porady projektowej. Użyłem projektu z abstrakcyjną klasą bazową i interfejsami, które nie są tak naprawdę typami, ale bardziej zachowaniami. Czy to dobry projekt? Jeśli nie, jaki byłby lepszy projekt.
Kod wygląda następująco:
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();
}
Niektóre kontrolki mogą zawierać inne kontrolki, niektóre mogą być zawarte tylko (jako dzieci), więc myślę o stworzeniu dwóch interfejsów dla tych funkcji:
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 steruje wyświetlanym tekstem, więc przechodzi on również do interfejsu:
interface ITextHolder
{
string Text { get; set; }
int TextPositionX { get; set; }
int TextPositionY { get; set; }
int TextWidth { get; }
int TextHeight { get; }
void DrawText();
}
Niektóre elementy sterujące można zadokować w obrębie elementu nadrzędnego, aby:
enum Docking
{
None, Left, Right, Top, Bottom, Fill
}
interface IDockable
{
Docking Dock { get; set; }
}
... a teraz stwórzmy konkretne klasy:
class Panel : Control, IDockable, IContainer, IChild {}
class Label : Control, IDockable, IChild, ITextHolder {}
class Button : Control, IChild, ITextHolder, IDockable {}
class Window : Control, IContainer, IDockable {}
Pierwszym „problemem”, jaki mogę tutaj wymyślić, jest to, że interfejsy są zasadniczo zepsute po ich opublikowaniu. Załóżmy jednak, że będę w stanie sprawić, że moje interfejsy będą wystarczająco dobre, aby uniknąć konieczności wprowadzania w nich zmian w przyszłości.
Innym problemem, jaki widzę w tym projekcie, jest to, że każda z tych klas musiałaby zaimplementować swoje interfejsy i szybko nastąpi duplikacja kodu. Na przykład w Label i Button metoda DrawText () pochodzi z interfejsu ITextHolder lub w każdej klasie pochodzącej z zarządzania dziećmi przez IContainer.
Moim rozwiązaniem tego problemu jest wdrożenie tej „zduplikowanej” funkcjonalności w dedykowanych adapterach i przekazywanie do nich wywołań. Zatem zarówno Label, jak i Button miałyby element TextHolderAdapter, który byłby wywoływany w metodach odziedziczonych z interfejsu ITextHolder.
Myślę, że ten projekt powinien uchronić mnie przed wieloma powszechnymi funkcjami w klasie bazowej, które mogłyby szybko zostać rozdęte wirtualnymi metodami i niepotrzebnym „kodem szumu”. Zmiany w zachowaniu zostałyby osiągnięte poprzez rozszerzenie adapterów, a nie klas pochodnych od Control.
Myślę, że nazywa się to „strategią” i chociaż na ten temat są miliony pytań i odpowiedzi, chciałbym zapytać o opinie na temat tego, co biorę pod uwagę przy tym projekcie i jakie wady można sobie wyobrazić w moje podejście.
Powinienem dodać, że istnieje prawie 100% szansa, że przyszłe wymagania będą wymagać nowych klas i nowych funkcjonalności.
IChild
wygląda na okropne imię.
System.ComponentModel.Component
lubSystem.Windows.Forms.Control
lub którykolwiek z pozostałych istniejących klas bazowych? Dlaczego musisz stworzyć własną hierarchię kontroli i zdefiniować wszystkie te funkcje od nowa?