The most common way I’ve seen of saving an entity into a database is through a class in a business / service layer. For example, when adding a new entity called User
:
User user = new User();
user.Name = "Foo";
UserService userService = new UserService();
userService.Add(user);
This works, and objects are being used, but I feel that the style leans toward the procedural side. Usually, the UserService
class mostly contains methods for interacting with the database. You could almost make the UserService
class static, and then it won’t really be considered as an object anymore.
In a purely object-oriented manner, I feel that the code would look like this:
User user = new User();
user.Name = "Foo";
user.Add();
My question is not about specific implementation details but about object-oriented design in general. Does using classes like the example UserService
indicate a procedural way of coding? If so, what could be a better object-oriented approach?
An example from the .NET framework that I feel is more object-oriented is SqlConnection
. How do we open a connection? Is there a SqlService
class from which you can call sqlService.Open(sqlConnection)
? No, but it is done from the SqlConnection
object itself: sqlConnection.Open()
.
Now the Open
method may use other classes in turn, but what’s interesting to me is that it is exposed on the SqlConnection
class itself, much like how the Add
method is exposed in the User
class in the second snippet above.
2
One of the principles of object-oriented design is that each object (class) should do only one thing. The User
class should know everything about being a user, but that doesn’t include knowing where users are stored – that responsibility is for another class (your UserService
class).
The UserService
class should know all about storing users, but it doesn’t need to know anything about the internals of what a User
is – only that it needs to store it. When you look at it from this perspective, it makes sense to pass the user
object to the userService
, because in the other scenario a User
would have to know how to store itself.
3
What you are describing is called an Active Record pattern.
As Jack points out, there are multiple problems with this pattern, especially in relation to separation of concerns, domain modeling, and testing. If you are using active record, you are assuming the classes are exactly the same as tables and rows in your relational database. This limits your modeling options. The object also becomes tightly couples to persistence library, making it hard to test it in isolation.
But the Repository pattern has it’s problems too. It requires the repository to be able to read and write internal state of the entity it’s responsible for, breaking encapsulation. It also doesn’t really fit when using ORM, where the changes that are made to the object should be transparently persisted, removing need for any Save/Update methods.
1
I do not see any problem.
You have two distinct objects: User
and UserService
. Both of these have two distinct roles / responsibilities.
1) The User
object represents the User in your domain. It responds to questions / messages like age? or firstName?. It is its duty to answer these types of questions.
2) The UserService
is distinct from the User
. It answers not to the above questions, but to a different set like: userCount?, countOfUKUsers?. The responsibility is quite different. The User
doesn’t care of any numbers, nor does it have to know anything about persisting. UserService
consumes so to say a User
or produces new instances, when returning data from the database.
UserService userService = new UserService();
userService.Add(user);
This is perfectly object oriented – though usually you would inject
the Service (which makes it look to you procedural):
The UserService
is sent a message Add
and the message has a payload, which is a User
.
But your 2nd example code above has no clear semantics
user.Add();
You are sending the Add()
message to the User
. But what does this mean? It is like asking yourself to listen. It is grammatically correct, but doesn’t make any sense. Besides: you would mix in knowledge about persisting with actual knowledge of the User
itself, which violates the single responsibility pattern.
Does using classes like the example UserService indicate a procedural way of coding?
NO. It is perfectly OOP: Passing messages to independent objects.
A question very close to my heart! (see my OOP vs ADM question)
Yes I believe that it IS procedural, but only if your UserService Modifies User.
for example, consider an Order which has many Items
Order.AddItem(Item item)
would be OOP surely?
but
Order.SetItemPrice(Item item, decimal price)
where Item has Item.Price, breaks the encapsulation principle. you would expect
Item.SetPrice(decimal price)
Now, there is potentially an additional factor that because you are writing to a database you’ll be needing to see all the private data fields on User. but, really in these days of ORMs and serialisers using reflection over objects anyway. Unless your pattern forces you to make all the otherwise private fields public I don’t think you can consider it ‘not OOP’
Also you might have
User.SerialiseToXML() or something which would not break encapsulation
Now your second question “What would be a better OOP way” begs the question. Is an OOP way always better?