2010-06-10 15 views
5

Projektowałem warstwę dostępu do bazy danych, która pozwala nam obsługiwać wiele baz danych w naszych programach. W końcu użytkownicy naszych programów będą mogli wybrać bazowy system baz danych z wielu systemów baz danych. Niektórzy mali klienci mogą być zadowoleni z MS Access, inni wolą MySql, inni DB2. Te systemy db to te, na które chcę teraz celować.Pytanie o projekt warstwy bazowej

Biorąc pod uwagę te wymagania, wymyśliłem abstrakcyjną klasę DatabaseConnection. Wewnętrznie używam klasy System.Data.Common.Data.DbConnection, co już daje mi trochę elastyczności.
Rzeczy wymagające konkretnych instancji (np. OleDbCommand zamiast DbCommand) są ukryte w abstrakcyjnych metodach, takich jak CreateDbCommand(). Podklasy (takie jak AccessDbConnection) implementują je i zapewniają konkretne instancje. Obecnie, która prowadzi do tej hierarchii (skrót nazwy klas dla czytelności):

  DatabaseConnection 
     /  |  \ 
AccessConn  MySqlConn  DB2Conn 

Jednakże, istnieje kilka operacji, które są specyficzne dla bazowego systemu baz danych, takich jak pobieranie wszystkie nazwy tabel. Wprowadzanie abstrakcyjnej metody GetTableNames() do klasy DatabaseConnection jest niepoprawne, a jej podklasy nadpisują ją.

Pomyślałem, że może uda mi się stworzyć kolejną abstrakcyjną klasę bazową o nazwie DatabaseTools, zadeklarować tam te operacje, a następnie zaimplementować je w podklasach przypominających podklasy klasy DatabaseConnection. Co oznacza, że ​​dla AccessDbConnection, chciałbym również mieć klasę AccessTools etc etc:

  DatabaseConnection      DatabaseTools 
     /  |  \     /  |  \ 
AccessConn  MySqlConn  DB2Conn AccessTools MySqlTools DB2Tools 

Jakoś nie jestem zachwycony tym pomysłem.

Jakie pomysły masz na rozwiązanie tego problemu projektowego?

Dzięki z góry za poświęcony czas i odpowiedzi :)

Cheers

Christian

+0

Co martwi Cię o projekcie? Wydaje mi się to rozsądne (na pierwszy rzut oka). Chciałbym włączyć jakiś sposób zapewnienia, że ​​nie można używać 'AccessTools' z' MySQLConn', ale to jedyna rzecz, o której mogę myśleć. – ChrisF

+0

Myślę, że podejście metody abstrakcyjnej jest w porządku. Jaki rozsądny powód możesz podać za pogwałcenie brzytwy Ockhama i zasady KISS i stworzenie drugiego zestawu zajęć, w których jeden byłby wystarczający? Użyłem pierwszej architektury opisanej w kilku projektach i nigdy nie miałem z nią problemów. Po prostu nie wymaga wiele kodu, pod warunkiem, że będziesz trzymać się standardowego kodu SQL. –

+0

@ChrisF: Kiedy myślę o klasie DatabaseConnection, po prostu myślę o tym jako o samym połączeniu, które pozwala mi tworzyć, otwierać i zamykać połączenie. Zapytanie o wszystkie nazwy tabel i inne operacje specyficzne dla systemu db muszą zrobić coś z połączeniem (w końcu działają na nim), ale czuję, że nie powinny być związane z połączeniem zbytnio. – Christian

Odpowiedz

1

Ponieważ nie otrzymujesz punktów za posiadanie 100% czystości OO, skorzystaj z porady Swingline Rage. Możesz też zrobić to samo, zmieniając nazwę klasy ;-)

Jedyna rzecz, jeśli użyjesz interfejsów zamiast klas abstrakcyjnych i dziedziczenia, prawdopodobieństwo, że zostaniesz spalony, jest mniejsze. Interfejsy mogą dziedziczyć po sobie nawzajem, ale prawdopodobnie nie będzie tego potrzebować. Trochę trudniejsze do napisania, ale możesz używać ich w ten sam sposób.

http://www.codeproject.com/KB/cs/abstractsvsinterfaces.aspx
Interface or an Abstract Class: which one to use?

"co wspólnego kodu w klasie bazowej?" - Możesz zostać DRY, jeśli używasz klas statycznych i wywołujesz je (nie jest to grzechem użycie niektórych technik proceduralnych w OO).Pytanie nr 2 w powyższym temacie dotyczącego przepełnienia stosu wygląda interesująco, ale nie mogę za to ręczyć.

3

Zamiast abstrakcyjnej metody, dlaczego nie realizować taki, który pobiera nazwy tabel za pomocą ANSI standardowe INFORMATION_SCHEMA widoki, a następnie po prostu zastąpić go w implementacji DatabaseConnection dla dostawcy, który nie jest zgodny z ANSI?

Poza tym nie widzę niczego złego w abstrakcyjnym podejściu metodologicznym z punktu widzenia projektu.

1

Moim zdaniem, zdefiniowanie operacji db w oddzielnej hierarchii jest lepszym pomysłem. Wolałbym zamknąć narzędzia wewnątrz konkretnych obiektów połączeń, a następnie uzyskać połączenia za pośrednictwem jednej fabryki.

Precyzyjnie, aby wykonać zadanie, aby wszystkie nazwy tabel, rozmowa będzie wyglądać następująco:

ConnectionFactory(ACSESS).getConnection().getTools().fetchSchema();