2012-09-25 25 views
5

Właśnie dzisiaj dowiedziałem się trochę o Kompozycji na dziedziczenie. Zastanawiałem się, czy powinienem zastosować tę koncepcję do czegoś, co napisałem niedawno.Klasa abstrakcyjna lub pomocnik Klasa

Mamy wcześniej miał dwie klasy, które były prawie identyczne, poza kilkoma małymi różnicami. Zawierały one kilka podstawowych funkcji dostępu do baz danych, ale działały na różnych (ale powiązanych) typach obiektów. Więc wcześniej miał klasę, które zostały zorganizowany mniej więcej tak:

class BallMillDBHandler{ 

    public BallMillDBHandler(){ ... } 

    public void InsertTool(BallMill tool) { ... } 
    public BallMill QueryTool(string toolID) { ... } 
    public void UpdateTool(BallMill tool) { ... } 
    public void DeleteTool(string toolID) { ... } 
} 

class DiamondToolDBHandler{ 

    public DiamondToolDBHandler(){ ... } 

    public void InsertTool(DiamondTool tool) { ... } 
    public DiamondTool QueryTool(string toolID) { ... } 
    public void UpdateTool(DiamondTool tool) { ... } 
    public void DeleteTool(string toolID) { ... } 
} 

wziąłem większość metod zbliżonych powielany i refactored je do klasy BaseToolDBHandler() i odziedziczył go od dwóch pozostałych, zapewniając kilka abstrakcyjnych metod i właściwości do obsługi różnic w dostępie do samych parametrów bazy danych.

Czy ma to sens, aby zamiast tego uczynić z BaseToolDBHandler klasę pomocniczą, zawartą w akcesoriach do baz danych i udostępnić im wspólny interfejs poprzednio abstrakcyjnych właściwości/metod? Czy powinienem zostawić to jako przypadek dziedziczenia?

+5

To brzmi jak idealne miejsce do dziedziczenia dla mnie, więc zostawiłbym to w ten sposób. –

+0

Neil Kennendy ma rację. Ale jeśli Twoja BaseClass właśnie oferuje abstrakcyjne metody i właściwości i nigdy nie oferuje żadnej zaimplementowanej funkcjonalności, użyj zamiast tego interfejsu (np. IDBHandler '). –

Odpowiedz

3

Wygląda to na scenariusz, który przyniesie korzyści zarówno rodzajowym, jak i dziedziczenia za pośrednictwem klasy bazowej/interfejsu.

class DBHandler<TTool> where TTool : ToolBase // or ITool 
{ 
    public DBHandler(){ ... } 

    public void InsertTool(TTool tool) { ... } 
    public TTool QueryTool(string toolID) { ... } 
    public void UpdateTool(TTool tool) { ... } 
    public void DeleteTool(string toolID) { ... } 
} 

Jeśli trzeba, można zrobić bazę (opcjonalnie streszczenie) klasę lub interfejs do wykorzystania jako rodzaj przymusu, który gwarantowałby, że pewne elementy potrzebne narzędzia, które mają wewnątrz ciał metod.

Przykłady:

var handler = new DBHandler<BallMill>(); 
BallMill value = handler.QueryTool("xyz"); 
value.SomeProperty = "New Value"; 
handler.UpdateTool(value); 
+1

Wygląda na to, że może to być opcja, ale zależy to od tego, co dzieje się wewnątrz tych metod; mogą one, ale nie muszą, być na tyle podobne, aby działały. – Servy

+0

@Jamiec Rzeczywiście. Rozumiem. – Dan

+0

Myślę, że stworzenie bazy rodzajowej pomogłoby w dobrym interesie. Nadal muszę utrzymywać inny zestaw parametrów, za pomocą których uzyskuje się dostęp do bazy danych i myślę, że zachowanie tych w oddzielnych klasach jest lepsze niż przekazywanie ich w każdej instancji. Ale to jest pomocne, myślę, że oznaczy to jako akceptowaną odpowiedź. – KChaloux

3

Dziedziczenie jest często nadużywane, ale wydaje się, że jest to odpowiedni przypadek. W wielu przypadkach ludzie widzą tylko zduplikowany kod i myślą: "Wykorzystam dziedziczenie do usunięcia duplikatu kodu przez klasę podstawową". W rzeczywistości większość zduplikowanych kodów może zostać ponownie przetworzona na inną klasę, która jest używana w kilku miejscach. Zwykle klasy używające go nie są "powiązane", robią dwie całkowicie różne rzeczy i po prostu dzielą się potrzebą wykonania niektórych (lub niektórych serii) małych zadań.

Dziedziczenie powinno być używane w przypadku klas, w których można naprawdę powiedzieć, że klasa "jest" instancją klasy bazowej, a nie tylko jakaś klasa, która potrzebuje dostępu do zestawu metod zdefiniowanych gdzie indziej. W twoim konkretnym przypadku jasne jest, że obie klasy to sterowników DB. W ich sednie, obaj służą temu samemu ogólnemu celowi, ale są to dwie różne możliwe implementacje tego celu. Jedyny problem, który mogłem tu zauważyć (biorąc pod uwagę, że nie pokazałeś zawartości żadnej z metod), to że możesz połączyć obie klasy w jedną klasę, ale musielibyśmy dowiedzieć się więcej o szczegółach. wiedzieć, czy jest to możliwe, czy to możliwe.

+0

Spodobała mi się twoja definicja tego, kiedy należy korzystać z dziedziczenia - nie jest to tylko definicja "jest", ale "ma", ale faktycznie wyjaśniasz, że zajęcia służą temu samemu ogólnemu celowi (i dlatego może być potrzeba odniesienia się do nich w sposób polimorficzny, więc istnieje dobry powód, aby korzystać z dziedziczenia). Poza tym nie ma rzeczywistej korzyści z dziedziczenia, ponieważ ponowne użycie kodu może być osiągnięte przez kompozycję bez sprzężenia i niebezpieczeństw, które mogą wystąpić w przypadku dziedziczenia. – BornToCode

0

powiedziałbym to zdecydowanie zadanie dla dziedziczenia ... ale przejdźmy jedną rzecz pierwsza. Skład jest wzorcem projektowym, który może i powinien być stosowany tam, gdzie dziedziczenie wielu klas nie jest cechą danego języka (np. C#)

Skład oznacza, że ​​twoja klasa kompozytowa tworzy instancje klas, na których zazwyczaj będą dziedziczone. W tym przypadku dostarczasz umowę do implementacji za pośrednictwem interfejsów.

Aby dać przykład, jak szorstki dziedziczenie może być stosowana do kodu, rozważ to: (nie jest to za pomocą kompozycji)

public interface IHandler 
{ 
    void InsertTool(ITool tool); 
    void UpdateTool(ITool tool); 
    void DeleteTool(string toolID); 
    //void DeleteTool(ITool tool) - seems more consistent if possible!? 

    ITool QueryTool(string toolID); 
} 

public interface ITool 
{ 

} 

class BallMill : ITool 
{ 
} 

class DiamondTool : ITool 
{ 
} 

class BallMillDBHandler : IHandler 
{ 

    public BallMillDBHandler(){ ... } 

    public void InsertTool(ITool tool) { ... } 
    public BallMill QueryTool(string toolID) { ... } 
    public void UpdateTool(ITool tool) { ... } 
    public void DeleteTool(string toolID) { ... } 
} 

class DiamondToolDBHandler : IHandler 
{ 

    public DiamondToolDBHandler(){ ... } 

    public void InsertTool(ITool tool) { ... } 
    public DiamondTool QueryTool(string toolID) { ... } 
    public void UpdateTool(ITool tool) { ... } 
    public void DeleteTool(string toolID) { ... } 
} 
+0

'QueryTool' nie będąc na interfejsie, prawie ufa tej odpowiedzi jako niewykonalne IMO. Interfejs nie ma rzeczywistego zastosowania. – Jamiec

+0

@Jamiec ... czas na edycję ... – series0ne

0

Zamiast dziedziczenia użyć rodzajowych. Chcesz wykonać tę samą operację na różnych typach obiektów, co jest właśnie tym, co generycy robią najlepiej.

Powiązane problemy