3

I'm trying to decide what's the best approach to instantiate a particular class. Basically there are two use cases for it: instantiate it in order to save a new entry to the database and fetch an existing entry from the database (and maybe edit the fetched entry and save it back to the database).

The issue I'm having right now is that I can't decide which mechanism for instantiating that class and populating its fields to choose. Say I have this class

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

And here are the usecases. If you want to fetch a student for the database, the code looks something like:

Student student = MyLibrary.GetStudent(id);

And if you want to create a new student and add it to the database:

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

The massive issue with this approach is that all the setters are public and I absolutely do not want this. But at the same time I want the user to be able to populate most of the Student fields freely (maybe with the exception of Id.

I'm thinking the builder pattern could be employed in here. This way I can keep the setters private and force the user to create read-only students via the builders. However it then becomes really awkward if the user wants to update a field and save it to the database:

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

Basically my only issue with the builder approach is that the code can get quite awkward and tedious if you want to update an existing entry. 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. But it may be much nicer than having a class with public setters.

What other options do I have?

  • 2
    Can you clarify why you want your setters to be private? – Rich Rousseau Jul 13 '15 at 17:31
  • 2
    Is there some reason you aren't just using constructor overloads or default parameters? Default parameters aren't usually a good idea, but they'd certainly give you what you seem to be looking for... – Magus Jul 14 '15 at 14:46
  • @Magus Because in most cases my models have around 10 fields. Telescoping constructors are not great in this scenario... – async Jul 14 '15 at 17:24
1

What you need is CQRS(Command Query Responsibility Segregation)

The idea is that what you save and what you load back and edit later is not the same object. This way you have control over what fields are private and what are public. What can be updated, and what can't.

In CQRS you have Command Model and Query Model. Command model is responsible for CREATE/UPDATE functionality, query model is responsible for fetching the data.

  • 1
    Thanks. Can you elaborate how that is appropriate though? – async Jul 13 '15 at 17:51
  • And I don't see the need to separate the command & query models in my case. They are basically identical. – async Jul 13 '15 at 17:52
  • You said you want user to be able to freely assign the fields. That's your command model. You also want to protect the fields when entity is already in the database - that's your query model. So they are definitely not identical, and that's how CQRS applies :) – Alexus Jul 13 '15 at 17:55
  • I see what you mean now. So if I want to update an existing Student, I have to fetch a StudentQueryModel first, copy all its fields into a StudentCommandModel and then save the StudentCommandModel back to the database. I don't think it brings any benefits over the builder approach mentioned in my question. In fact it adds more complexity. Or maybe I'm missing something. – async Jul 13 '15 at 17:59
  • I don't see how builder patterns solves your issue? All I see it makes code look way more complicated and adds an extra pass-through layer. You might want to read Martin Fowler's article that I linked in my answer. – Alexus Jul 13 '15 at 18:04
0

I think a nonpublic set for "user editable" properties is just making work for yourself.

I'd leave them public (for changeable properties, i.e. not Id) and then either use the DAO-style .Edit and .Update state change methods (where attempting to change before calling .Edit throws a runtime error), or simply always allow changes and supply .CommitChanges to store them, similar to .NET DataContext.

This also allows something like:

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

where the important bit I'm referring to is UserConfirmsChanges which can work with modified, but not saved, data simply.

If you really want something similar to the DAO way, but with compile-time read only properties before .Edit, you'll have to have different classes or otherwise duplicate code.

0

If you want to keep the setter private then you have to use construction arguments to set the properties.

ie

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

Even if you use an additional builder class it will still need to do this underneath. I wouldn't bother with one, unless you are publishing the class or need to enforce some complicated setup logic.

When you come to update an existing object, in the OOP world you would expect to be calling a method on your object which would modify the private properties in accordance with some business logic, rather than simply setting a data value.

ie

myStudent.MoveIntoAccomadation(myCollege);

rather than

myStudent.Address = myCollege.Address;

if you are just doing the latter then it suggests that you object is really just a data struct. There's nothing wrong with this, you could be apssing it to services as DTO, or just moving it around databases etc

0

As far as I can see, your Student is a composite struct of related fields.

From my preliminary experience with these, I highly recommend trying to make these fully immutable, which is also what you seem to have in mind(?)

As for your concern wrt. Builder Pattern:

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.

You have to give your builder a ctor that takes a Student, then the Builder can copy an existing Student and you can change only the update fields.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.