What is one class, one principle of responsibility?

I would like to learn about the principle of one class, one responsibility. I found several articles about this, but without examples. This would help me if you could give me an example of a class that violates the principle.

I am familiar with the idea that a method should do only one thing, for example, get and set methods. It should not be the same as One Class, One Responsibility, because the set and get methods are implemented inside the class. Does this mean that the class breaks the rule because the class has responsibilities for both setting and receiving?

What is the principle of one class, one principle of responsibility?

+6
source share
5 answers

I am not 100% expert in this design pattern, but here is how I think about it - if I create an object, it is responsible for only one thing. If you need to do something else, but connected with another object, depending on the situation, I would use inheritance or interfaces.

This is a concept that seems pretty simple; make sure that a specific object (or method, for that matter) processes one piece of logic. If it processes more, you need another object (or method).

+1
source

A principle is exactly what he says, but not much more. One class should have only one responsibility. Although it can be difficult to determine. An example would be the DatabaseHandler class, which handles all database queries in an application.

Further reading: cohesion .

0
source

On the fundamental aspect of non-compliance with obligations.

If you have an InvoiceProcessor class that processes invoices, calculates business rules, creates a PDF code using invoices, processes the database with additional bonus points registered to the seller, then you have a clear case of the need to separate the problems. In this case, a clear separation or even delegation to other classes is required.

But one class - one responsibility is even more subtle and disgusting. If you need to provide a solution for processing invoices and have several goals for fulfilling such bonus points, you can have a violation function that fulfills several goals: calculate bonus points for the seller and a discount for the client.

On a smaller scale: if you have a class with its data structures, for example, a priority queue or something else, and at the same time mix it with data structures to cache part, using, say, a list and map, then you are in in some places, manipulating data for various problems, perhaps even accessing the cache list, so that data structures are intertwined. If you have a function that changes the priority and changes the cache state, it will be difficult to understand the processes in the future.

I often come across violations when it is necessary to fulfill some different aspects, and they are executed in one class. Then the API has calls with different levels of abstraction or complex semantics.

0
source

Let's say you write your own Logger utility, and since it starts with a simple one (singleton with methods that write to stdout), you decide to put all your functions in one class. Since you are using this, you are thinking of additional features to add to it:

  • you want to be able to register for different things (in stderr, in a file, in the queue, whatever)

  • Do you want to change message formatting

  • you want separate registrars for different categories

  • you want to be able to filter messages for a category by log level

  • you want to be able to change logging levels on the fly

  • add new logging levels (ERROR, WARN, INFO, DEBUG, etc.)

etc., and you add an implementation for each function to the same class you started with. Each change you make means returning to one class, sorting by it to see what is important, and then make changes. Since the whole code is overflowing with one class, and the methods contain code that implements various functions, it can be difficult to track all the relevant parts for your change, and there is always the possibility that the change may inadvertently affect some other functions, so some previously existing functions may stop working in some circumstances. Therefore, you need to check all the functions in the class and, even worse, all the combinations of all the functions in order to catch these errors. This means that testing will be incomplete and errors may sneak.

Now let's see how a real project works, for example log4j. There, the separation of concerns, when different classes handle formatting, convey how the output is written, providing a registrar for the category, and the interaction between all these elements is well defined, as a result of which, when you mess around or replace one part, it does not affect the other parts. Users can create their own classes that add the functionality they need (where they don’t need to know everything about the structure of the magazine, they only need to know the contract for this specific part that they want to add) and connect it, and users can mix and match different plugins. If the plugin is damaged, this gap does not extend beyond this plugin, and changes to individual parts do not threaten the integrity of the entire project. To the extent that contracts govern the interaction of parts, you do not need to check all the various combinations of specific functions.

With a single-class approach, you can never do this, every bit of new functionality added by someone would be a fork of the project. The point of principle of shared responsibility and other SOLID rules is a common strategy that allows you to change software in a controlled way without breaking anything.

0
source

Every thing in the class should be related to what the class should be responsible for.

If it is a class called MailSender, it only needs to know how to send mail. The code that creates the email content should not be inside it.

0
source

Source: https://habr.com/ru/post/913817/


All Articles