How to apply Single Responsibility Principle to a service class
Asked Answered
D

4

8

Suppose we are designing a UserServiceImpl class which does CRUD (Create, Read, Update, and Delete) operations. In my view Create, Read, Update, and Delete are four reasons for a class to change. Does this class violates Single Responsibility Principle? If it violates, then should we have four classes like CreateUserServiceImpl, ReadUserServiceImpl, UpdateUserServiceImpl, and DeleteUserServiceImpl. Isn't it an overkill to have lots of classes?

Suppose I define 4 interfaces each for create, read, update, and delete operations and my service class implements all the four interfaces. Now I can only have a single implementation class but by separating their interfaces I have decoupled the concepts as far as rest of the application is concerned. Is this the right way or you see some problems in it?

Diazotize answered 15/4, 2010 at 7:53 Comment(0)
F
5

That's what I love about patterns and principles - they are a consist way for everyone to disagree on software design as much as agree :-)

My view would be to build the class in whatever way makes it a usable and easy to understand class - depending on the complexity and context within which the class lives. With a simple implementation and context, a single class will do. You could say it does adhere to the SRP because it's responsibility is to manage the CRUD operations. But if the implementation is complex, or there's a lot of shared code that would be suitable for placing in an abstract parent class, then perhaps 4 separate classes, one for each CRUD operation make more sense. it's all about how you look at it.

Patterns and principles are great things, but used incorrectly they can make a simple problem just as complex as not having them.

Fionnula answered 15/4, 2010 at 8:3 Comment(1)
Thanks for the answer. I have updated the question.Is the design better now?Diazotize
I
4

In my view Create, Read, Update, and Delete are four reasons for a class to change.

Why?

If I have a Stack class, are Push and Pop reasons for the class to change?

I don't think so. These are two standard operations people do with a stack. The same with CRUD, it is a simple, established, well-known set of operations over a data storage.

Now your underlying storage technology itself IS a reason for your class to change. That is if your CRUD implementation is hard-coded to only work with a specific instance of an MS SQL 6.0 database, then you violate SRP and the class will not be easily reusable or extandable.

With regards to 4 interfaces, that is closer to another SOLID principle, the ISP, and the need here is determined by the patterns of usage of your data storage. For example, if some classes will only need to Read from the data storage it makes total sense to extract an interface with just the Read method and request that interface as an argument to such methods. By separating this interface you can later on make a separate implementation of it. Who knows, maybe for read-only clients you can issue a better optimized query or use a memory cache, but if not -- you can just pass them the instance of your default data storage implementing this interface.

Inhibitory answered 26/2, 2012 at 0:9 Comment(0)
M
1

It does not violate the single responsibility principle till the service is responsible for the data services of a single type or business info.

Meson answered 15/4, 2010 at 8:0 Comment(0)
W
0

I would think that the Dao classes would target a single entity which in this case is the user. Then the service classes would receive the Dao as a dependency. The service classes would then apply an interface where it has methods as part of its interface and those service methods call Dao methods. Here you have the best of both worlds which is a Dao consisting of all crud operations relating to the user table and then Service classes with specific names e.g UserPointsUpdater which call whatever Dao methods they want. This could be a single Dao method or several Dao methods to get the job done.

This way we adhere to ISP and SRP. Our code is clear in what we are trying to do for each event.

You could always break your Daos into smaller classes which may target a specific column within a table if the entity it targets starts to have multiple complex methods peforming CRUDs on several columns.

The event specific service objects target whatever Dao methods they need for that specific event, but receive the Dao relating to that entity.

If you don’t have Daos and envoke methods directly within the service class (which I wouldn’t recommend for many reasons, such as testing to name just one) then I would make these classes event specific and use inheritance/composition to prevent DRY.

Woodborer answered 27/2 at 3:8 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.