Il design di un generico sincronizzatore di dati, o, un [oggetto] che fa [azioni] con l'aiuto di [aiutanti]

2

Mi piacerebbe creare un "sincronizzatore" generico di origine dati, dove i "tipi" di origine dati possono includere database MySQL, documenti di Google Spreadsheets, file CSV, tra gli altri. Ho cercato di capire come strutturare questo in termini di classi e interfacce, tenendo a mente (quello che ho letto su) composizione contro ereditarietà ed è-a vs. ha-a, ma ogni percorso scendo sembra violare alcuni principi.

Per semplicità, supponiamo che tutte le fonti di dati abbiano un formato di riga di intestazione più righe dati. Ad esempio, supponi che le prime righe dei documenti di Google Spreadsheets e i file CSV dispongano di intestazioni di colonna, a.k.a. "campi" (su campi di database paralleli).

Inoltre, alla fine, vorrei implementarlo in PHP, ma evitare discussioni specifiche per la lingua sarebbe probabilmente più produttivo.

Ecco una panoramica di ciò che ho provato.

Parte 1/4: ISyncable

class CMySQL implements ISyncable
    GetFields()     // sql query, pdo statement, whatever
    AddFields()
    RemFields()
    ...
    _dbh
class CGoogleSpreadsheets implements ISyncable
    GetFields()     // zend gdata api
    AddFields()
    RemFields()
    ...
    _spreadsheetKey
    _worksheetId
class CCsvFile implements ISyncable
    GetFields()     // read from buffer
    AddFields()
    RemFields()
    ...
    _buffer
interface ISyncable
    GetFields()
    AddFields($field1, $field2, ...)
    RemFields($field1, $field2, ...)
    ...
    CanAddFields()  // maybe the spreadsheet is locked for write, or
    CanRemFields()  // maybe no permission to alter a database table
    ...
    AddRow()
    ModRow()
    RemRow()
    ...
    Open()
    Close()
    ...

Prima domanda: ha senso utilizzare un'interfaccia, come sopra?

Parte 2/4: CSyncer

Successivamente, la cosa che esegue la sincronizzazione .

class CSyncer
    __construct(ISyncable $A, ISyncable $B)
    Push()          // sync A to B
    Pull()          // sync B to A
    Sync()          // Push() and Pull() only differ in direction; factor.
                    // Sync()'s job is to make sure that the fields on each side
                    // match, to add fields where appropriate and possible, to
                    // account for different column-orderings, etc., and of
                    // course, to add and remove rows as necessary to sync.
    ...
    _A
    _B

Seconda domanda: Ha senso definire una tale classe, o sto camminando pericolosamente vicino al "Regno dei nomi"?

Parte 3/4: CTranslator? ITranslator?

Ora, ecco dove mi perdo davvero, supponendo che quanto sopra sia accettabile.

A volte, due ISyncable s parlano diversi "dialetti".

Ad esempio, che ci crediate o no, Google Spreadsheets (accessibile tramite l'API di Google Data "feed elenco") restituisce le intestazioni delle colonne lower-cased e stripped di tutti gli spazi e simboli ! Cioè, sys_TIMESTAMP è systimestamp , per quanto il mio codice può dire. (Sì, sono consapevole che il "cell feed" non ne spoglia il nome, tuttavia la manipolazione cella per cella è troppo lenta per quello che sto facendo.)

Si possono immaginare altri esempi ipotetici. Forse anche i dati stessi possono essere in "dialetti" diversi. Ma prendiamolo come dato per ora, e non discutere questo se possibile.

Terza domanda: in che modo tu implementa la "traduzione"?

Nota: Considerando tutto questo come un esercizio, sono più interessato al design "idealizzato" piuttosto che a quello pratico. (Dio sa che è stato spedito a vela quando ho iniziato questo progetto.)

Parte 4/4: ulteriore pensiero

Ecco il mio modo di pensare per dimostrare che ho cantato, anche se senza freni:

  1. In primo luogo, ho pensato, in primis, "modificheremo solo CMySQL::GetFields() nei nomi di campi minuscoli e in strip, in modo che siano compatibili con Google Spreadsheets." Ma ovviamente, la mia classe dovrebbe essere chiamata, CMySQLForGoogleSpreadsheets , e non può essere corretta.

  2. Quindi, la cosa che traduce deve esistere al di fuori di un ISyncable implementor.

  3. E sicuramente non può essere giusto rendere ogni traduzione un metodo in CSyncer .

  4. Se esiste al di fuori di entrambi ISyncable e CSyncer , allora che cos'è? (È anche un "it" ?)

  5. È una classe astratta, cioè abstract CTranslator ?

  6. È un'interfaccia, dal momento che un traduttore fa , non ha , cioè interface ITranslator ?

  7. Richiede addirittura l'istanziazione? per esempio. Se è un ITranslator , allora i suoi metodi di traduzione dovrebbero essere static ? (Ho appreso cosa significa "legatura statica avanzata", oggi.)

E, mio Dio, qualunque cosa sia, come dovrebbe un CSyncer usarlo ? Lo ha "ha"? it , "it" ?

Chi sono io? ... sono io, "I"?

Ho tentato di suddividere la domanda in sotto-domande, ma essenzialmente la mia domanda è singolare:

Come si implementa un oggetto A che concettualmente "collega" ( ha ) due oggetti b1 e b2 che condividono un'interfaccia comune B , ma dove alcune coppie di b1 e b2 richiedono un helper, es un traduttore, che deve essere gestito da A ?

Qualcosa mi dice che ho sovradimensionato questo progetto o violato un principio molto più in alto.

Grazie infinite per il vostro tempo e i consigli che potete fornire.

    
posta Andrew Cheong 01.07.2012 - 16:58
fonte

1 risposta

4

I tuoi traduttori sono un caso d'uso standard per il modello di decoratore . Il traduttore implementa l'interfaccia, ma usa un hard implementor per fare la maggior parte del lavoro; modellando i dati in modo coerente e / o uniforme dove necessario.

    
risposta data 01.07.2012 - 17:29
fonte

Leggi altre domande sui tag