Ho avuto un pattern di stranezza in un codice che stavo scrivendo. In un progetto con account utente, c'era un sacco di codice necessario per fare cose comuni come la creazione di account, la cancellazione, l'accesso e la disconnessione, l'estensione della sessione di accesso, ecc. Ecc. Ecc. Ora, quando ero prima scrivendo questo, ho appena buttato tutte quelle responsabilità in una classe (che era orribile lo so). Quando è arrivato il momento di ripulire tutto, ho finito con un approccio che sembrava giusto ma anche strano.
Ho impostato una classe AccountAccessor che conteneva funzioni private per ottenere gli oggetti di trasferimento dati associati a un account, quindi ho creato diverse classi di "azione" che ognuna farebbe una cosa con accesso a un account, permettendomi di scrivere:
new AccountPasswordSetter(new AccountAccessor(username)).SetPassword(password);
Questo mi sembrava sbagliato, perché
- Le classi di azione erano molto, molto strettamente associate alla classe
AccountAccessor
- non c'era speranza di testarle - La classe
AccountAccessor
dovrebbe esporre le sue funzioni di accesso ai dati affinché le classi di azioni possano utilizzarle. - Devo esporre la costruzione delle classi di azioni al codice cliente. Ciò è sembrato problematico perché, in realtà, non c'è alcun motivo ragionevole per cui qualcosa al di fuori del progetto debba preoccuparsi della loro istanziazione.
- Ciascuna classe di azioni richiedeva solo una degli oggetti di trasferimento dati forniti da
AccountAccessor
- ad esempio, una classe di azioni responsabile della registrazione dell'utente non ha bisogno di accedere alla password dell'account. - Scrivere ciò sembra molto verboso e "dentro e fuori".
Quello che ho finito invece è stato che ho reso le classi di azioni tutte in grado di essere costruite solo all'interno del progetto, e invece di aver bisogno di AccountAccessor
le ho impostate per accettare semplicemente una funzione che avrebbe preso una connessione al database e restituire l'unico DTO di cui avevano bisogno. Quindi, quando è stata costruita la funzione di accesso all'account, si creerebbe un'intera serie di questi oggetti azione e si passerà a ciascuno di essi uno dei metodi privati per ottenere il DTO. Qualcosa come:
public class AccountAccessor {
public AccountPasswordSetter PasswordSetter { get; private set; }
public AccountSessionExtender SessionExtender { get; private set; }
public string Username { get; private set; }
public AccountAccessor(string username) {
Username = username;
PasswordSetter = new PasswordSetter(getPasswordEntity);
SessionExtender = new SessionExtender(getSessionEntity);
}
private PasswordEntity getPasswordEntity(Connection databaseConnection) { ... }
private SessionEntity getSessionEntity(Connection databaseConnection) { ... }
}
Ora, il codice cliente può semplicemente chiamare qualcosa del tipo:
new AccountAccessor(username).PasswordSetter.Set(password)'
Le responsabilità sono suddivise e le classi di azioni non devono sapere o preoccuparsi di cosa sia un AccountAccessor. Il codice cliente non deve sapere o preoccuparsi di come vengono impostati i vari oggetti che forniscono funzionalità. AccountAccessor espone solo selettivamente l'accesso alle entità del database. Questo mi è sembrato molto, molto meglio. Quello che mi è piaciuto di più di questo design è stato risolvere molti dei problemi che avevo senza imporre alcun problema di architettura al codice client. Se il codice cliente vuole disconnettere un account ed eliminarlo, ottiene solo un accesso, quindi lo registra ed elimina: non è necessario capire come trasferire correttamente gli oggetti. L'approccio ovvio per il codice client funziona solo .
Ma sembra ancora un po 'off - passando metodi privati come argomenti per gli altri oggetti mi sembra fondamentalmente strano. Volevo sapere di più su che tipo di problemi ha questo, e cosa dovrei tenere a mente quando progetti le cose che si adattano a questo tipo di scenario in futuro.