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:
-
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. -
Quindi, la cosa che traduce deve esistere al di fuori di un
ISyncable
implementor. -
E sicuramente non può essere giusto rendere ogni traduzione un metodo in
CSyncer
. -
Se esiste al di fuori di entrambi
ISyncable
eCSyncer
, allora che cos'è? (È anche un "it" ?) -
È una classe astratta, cioè
abstract CTranslator
? -
È un'interfaccia, dal momento che un traduttore fa , non ha , cioè
interface ITranslator
? -
Richiede addirittura l'istanziazione? per esempio. Se è un
ITranslator
, allora i suoi metodi di traduzione dovrebbero esserestatic
? (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.