4

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.

  • 1
    The way I understand it, no matter how object-oriented your model is, you'll still need to have a procedural facade on top. Because Something has to instantiate all those objects and ask them do things. Such facade is called "Application Service Layer" in the context of DDD. – astreltsov May 14 '15 at 7:16
  • 1
    The design is different, because it has a different meaning: The SqlConnection.Open() command is like asking the connection object to open- the connection. It is the objects responsibility to do just that. But it is not the Users responsibility to persist itself, it is the responsibility of an additional object - in this case UserService. It is not like User.Add(). – Thomas Junk May 14 '15 at 16:31
5

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.

  • 1
    It's sometimes called "persistence ignorance." – Robert Harvey May 14 '15 at 4:59
  • @JackScott Thanks for the answer. I added a code sample from the .NET framework in the question - would appreciate your thoughts on that. – OJ Raqueño May 14 '15 at 13:16
  • Thomas' comment on your question is exactly what I would have said. – Jack Scott May 18 '15 at 0:14
2

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.

  • »It requires the repository to be able to read and write internal state of the entity it's responsible for, breaking encapsulation.« I have to admit, my objection is rather philosophical: There is no need to break encapsulation and no need to retrieve the objects state. You do not need to persist the objects state, you need to persist a representation of that. And vice versa: the object needs a way of generating state from a representation of state. Of course it's easier and faster to use reflection to peek - but it is not necessary ;) – Thomas Junk May 14 '15 at 11:14
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.

0

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?

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.