2010-06-10 12 views
5

Ho progettato un livello di accesso al database che ci consente di supportare più database nei nostri programmi. Alla fine, gli utenti dei nostri programmi dovranno essere in grado di scegliere il sistema di database sottostante da una serie di sistemi di database. Alcuni piccoli clienti potrebbero essere felici con MS Access, altri preferiscono MySql, altri DB2. Quei sistemi db sono quelli che voglio prendere di mira per ora.Domanda di progettazione livello database

Dati questi requisiti, ho creato una classe astratta DatabaseConnection. Internamente, utilizzo la classe System.Data.Common.Data.DbConnection, che mi dà già un po 'di flessibilità.
Le cose che richiedono istanze concrete (OleDbCommand anziché DbCommand ad es.) Sono nascoste in metodi astratti come CreateDbCommand(). Sottoclassi (come AccessDbConnection) implementano quelle e forniscono le istanze concrete. Attualmente che porta a questa gerarchia (nomi di classe abbreviati per migliorare la leggibilità):

  DatabaseConnection 
     /  |  \ 
AccessConn  MySqlConn  DB2Conn 

Tuttavia, ci sono alcune operazioni che sono specifici per il sistema di database sottostante, come ad esempio il recupero di tutti i nomi di tabella. È sbagliato posizionare un metodo astratto GetTableNames() nella classe DatabaseConnection e fare in modo che le sottoclassi lo sovrascrivano.

Ho pensato che forse posso creare un'altra classe base astratta chiamata DatabaseTools, dichiarare quelle operazioni lì e quindi implementarle in sottoclassi che assomigliano alle sottoclassi della classe DatabaseConnection. Il che significa che per un AccessDbConnection, mi piacerebbe anche avere una classe AccessTools etc etc:

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

In qualche modo io non sono davvero entusiasta da questa idea.

Quali idee avete per risolvere questo problema di progettazione?

Grazie in anticipo per il vostro tempo e le risposte :)

Acclamazioni

Christian

+0

Quello che si preoccupa per il design? Mi sembra ragionevole (a prima vista). Vorrei includere un modo per garantire che non si possa usare un 'AccessTools' con un' MySQLConn', ma questa è l'unica cosa che riesco a pensare. – ChrisF

+0

Penso che l'approccio al metodo astratto sia corretto. Quale motivo convincente puoi dare per aver violato il rasoio di Occam e il principio KISS e aver creato un secondo set di classi in cui sarebbe bastato? Ho usato la prima architettura che hai descritto in una mezza dozzina di progetti e non ho mai avuto problemi con essa. Non c'è solo un sacco di codice specifico per DB che è richiesto, purché si rispetti lo standard SQL. –

+0

@ChrisF: Quando penso a una classe DatabaseConnection, la penso semplicemente come la connessione stessa, che mi consente di creare, aprire e chiudere la connessione. Interrogare tutti i nomi delle tabelle e altre operazioni specifiche del sistema db devono fare qualcosa con la connessione (dopotutto, operano su di esso), ma ritengo che non debbano essere legati alla connessione troppo stretta. – Christian

risposta

1

Poiché non si ottengono punti per avere la purezza OO al 100%, seguire il consiglio di Swingline Rage. Puoi anche renderlo puro semplicemente rinominando la classe ;-)

Unica cosa è che se si utilizzano le interfacce anziché le classi astratte e l'ereditarietà è meno probabile che vengano bruciate. Le interfacce possono ereditare l'una dall'altra ma probabilmente non ne avrai bisogno. Un po 'più difficile da scrivere ma puoi usarli allo stesso modo.

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

"che dire di codice condiviso nella classe base?" - Puoi rimanere DRY se usi le classi statiche e chiamale (non è un peccato usare alcune tecniche procedurali in OO).Q # 2 nell'argomento di overflow dello stack sopra sembra interessante ma non posso garantire per questo.

3

Invece di un metodo astratto, perché non implementare uno che recupera i nomi delle tabelle che utilizzano le ANSI standard INFORMATION_SCHEMA vista, e quindi basta sovrascriverlo in un'implementazione DatabaseConnection per un provider che non è ANSI compatibile?

A parte ciò, non vedo nulla di sbagliato nell'approccio al metodo astratto dal punto di vista del design.

1

A mio avviso, la definizione delle operazioni DB in una gerarchia separata è un'idea migliore. Preferirei incapsulare gli strumenti all'interno degli oggetti di connessione concreti e quindi ottenere i collegamenti tramite una singola fabbrica.

Precisamente, per eseguire un compito per ottenere tutti i nomi di tabella, la chiamata sarà simile:

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