Problemi che decidono sull'approccio alla creazione di un oggetto

3

Sto cercando di decidere quale sia l'approccio migliore per creare un'istanza di una particolare classe. Fondamentalmente ci sono due casi d'uso: istanziarlo per salvare una nuova voce nel database e recuperare una voce esistente dal database (e magari modificare la voce recuperata e salvarla nel database).

Il problema che sto avendo ora è che non riesco a decidere quale meccanismo di istanziazione di quella classe e popolamento dei suoi campi da scegliere. Dì che ho questa classe

public class Student
{
    public int Id { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public Address Address { get; set; }
}

E qui ci sono gli usi. Se vuoi recuperare uno studente per il database, il codice ha un aspetto simile a:

Student student = MyLibrary.GetStudent(id);

E se vuoi creare un nuovo studente e aggiungerlo al database:

Student student = new Student();
student.FirstName = "James";
student.LastName = "Jackson";
// etc
MyLibrary.CreateStudent(student);

L'enorme problema con questo approccio è che tutti i setter sono pubblici e io assolutamente non lo voglio. Ma allo stesso tempo voglio che l'utente sia in grado di popolare liberamente la maggior parte dei campi Student (forse con l'eccezione di Id .

Penso che il modello di builder possa essere impiegato qui. In questo modo posso mantenere privati i setter e costringere l'utente a creare studenti di sola lettura tramite i costruttori. Tuttavia diventa davvero imbarazzante se l'utente desidera aggiornare un campo e salvarlo nel database:

var student = MyLibrary.GetStudent(id);
var newStudent = new Student.Builder(id).FirstName("NewFirstName").LastName(student.LastName)...etc...Build();
MyLibrary.CreateStudent(newStudent);

Fondamentalmente il mio unico problema con l'approccio del builder è che il codice può diventare piuttosto noioso e noioso se si desidera aggiornare una voce esistente. Alcune delle classi che ho possono avere circa 10 campi e non è bello dover copiare 9 dei campi e aggiornarne uno. Ma potrebbe essere molto più bello di avere una classe con i setter pubblici.

Quali altre opzioni ho?

    
posta async 13.07.2015 - 19:04
fonte

4 risposte

1

Ciò di cui hai bisogno è CQRS (Segregazione di responsabilità della query di comando)

L'idea è che ciò che si salva e ciò che si carica e si modifica successivamente non è lo stesso oggetto. In questo modo hai il controllo su quali campi sono privati e quali sono pubblici. Cosa può essere aggiornato e cosa no.

In CQRS hai modello di comando e modello di query. Il modello di comando è responsabile della funzionalità CREATE / UPDATE, il modello di query è responsabile del recupero dei dati.

    
risposta data 13.07.2015 - 19:29
fonte
0

Penso che una percentuale non pubblica set per le proprietà "modificabili dall'utente" stia semplicemente lavorando per te.

Li lascerei public (per le proprietà modificabili, ovvero non Id ) e quindi utilizzare i metodi di modifica dello stato di tipo .Edit e .Update (in cui si tenta di modificare prima di chiamare .Edit genera un errore di runtime), o semplicemente consente sempre modifiche e fornisce .CommitChanges per memorizzarle, simile a .NET DataContext .

Ciò consente anche qualcosa come:

LoadStudent(s);
s.Name="Harry";
if(UserConfirmsChanges(s))
  s.CommitChanges();

dove il bit importante a cui mi riferisco è UserConfirmsChanges che può funzionare semplicemente con dati modificati, ma non salvati.

Se vuoi davvero qualcosa di simile al modo DAO, ma con le proprietà di sola lettura in fase di compilazione prima di .Edit , dovrai avere classi diverse o in altro modo duplicare il codice.

    
risposta data 21.08.2015 - 17:36
fonte
0

Se si desidera mantenere privato il setter, è necessario utilizzare gli argomenti di costruzione per impostare le proprietà.

es

public class Student
{
    public Student(string firstName, string lastName....

Anche se usi una classe di builder aggiuntiva, sarà comunque necessario farlo sotto. Non mi preoccuperei di farlo, a meno che tu non stia pubblicando la classe o sia necessario applicare alcune complicate logiche di configurazione.

Quando si arriva ad aggiornare un oggetto esistente, nel mondo OOP ci si aspetterebbe di chiamare un metodo sul proprio oggetto che modificherebbe le proprietà private in conformità con alcune logiche di business, piuttosto che semplicemente impostando un valore di dati.

es

myStudent.MoveIntoAccomadation(myCollege);

anziché

myStudent.Address = myCollege.Address;

se stai facendo solo quest'ultimo, ti suggerisce che l'oggetto è in realtà solo una struttura di dati. Non c'è niente di sbagliato in questo, si potrebbe essere apssing su servizi come DTO, o semplicemente spostandolo intorno ai database ecc.

    
risposta data 20.09.2015 - 18:00
fonte
0

Per quanto posso vedere, il tuo Student è una struttura composta di campi correlati.

Dalla mia esperienza preliminare con questi, consiglio vivamente di provare a renderli completamente immutabili , che è anche quello che sembra avere in mente (?)

Per quanto riguarda la tua preoccupazione wrt. Schema costruttore:

Some of the classes I have can have around 10 fields and it's not great having to copy 9 of the fields and update one.

Devi dare al tuo costruttore un ctor che prende un Student , quindi il Builder può copiare un Student esistente e puoi modificare solo i campi di aggiornamento.

    
risposta data 19.11.2015 - 20:41
fonte

Leggi altre domande sui tag