Sebastian Zeki
Sebastian Zeki

Reputation: 6874

How to define a class whos only role is to perform an action

This is a question about the definition of a class. Of course I have read the endless examples on the Internet of what should be called a class. I have read that it is all the verbs and nouns that make up a thing. I understand the concept of a car class with properties like size, colour, and methods like drive

I also understand the idea that a class should have only one responsibility and adhere to the other SOLID principles

My problem relates to a program I have developed.

The responsibility of the program is to extract all the similar words from a document. It is therefore not a 'noun' like a car or animal but a verb type class I suppose.

In order to do this the program iterates through a folder of text files, extracts all the text, splits the text up by line and then 20 characters, compares each of the chunks in one file to all of the others by similarity, keeps only the words that are similar between two files, cleans the words to get rid of various characters and then added the words to a text file and repeats this for all the files in the folder.

So I have one responsibility for the class and I have written methods for each of the phrases between the commas.

Having read more about class design then it could to me that some of these methods might be classes in their own right. If a class is defined by having a single responsibility then presumably I could define more classes instead of these methods. E.g. why don't I have a class to find word similarity with only one method....

So my question is how do I define a class on a single responsbility basis if a method also has a single responsibility and the class doesn't define a thing but more of an action. What are the boundaries of what defines a class?

Please no...'Have you read'...because I have read them all. A simple explanation with a well illustrated example (conceptual example is fine)

Upvotes: 1

Views: 81

Answers (2)

progmatico
progmatico

Reputation: 4964

Let's think a little about both your problem, problems in general, and SRP.

SRP states that a class should be concerned with one thing. This doesn't mean exactly to have a single method that does only one thing.

Actually this can be applied outside OOP too: a function should do only a single thing.

Now imagine your program has to implement 200 features. Imagine they are so simple that a single function is enough to implement any feature. And suppose you are using only functions. By the same principle you have to write (at least) 200 functions. Now this is not so great as it looks. First you program structure looks like an endless list of micro-sized pieces of code. Second if they are micro-sized, they can't do much by themselves (this is not bad per see). As you suspected a feature doesn't usually map to a single function in real world. Third if they do almost nothing, they have to ask everything to someone else. Or someone is doing that somewhere else. So there is some place where a function, or a class, is calling all the others. That place centralizes a lot of knowledge about the system. It has to know about everything to be able to call everyone. This is not good for an architecture.

The alternative is to distribute the knowledge. If you allow those functions or classes to do a little more, they ask less things to others, some of those things are solved locally. Let me guess. As all this classes are in the same application, some of them are related to each other. They can form a group and collaborate. Maybe they can be the same class, or inherit from others. This reduces communication paths. Communication becomes more local.

Comunication paths matter. Imagine there are 125 persons in your company, and the company needs to take collective decisions. Would you do a 125 people meeting, or you group people say in 5 groups, each with 5 teams of 5 people and have small meetings instead, and then the team and group leaders meet themselves? This is a form of hierarchy or structure that helps things.

Can you imagine the fan-in and fan-out in the new structure? 5/5/5 is much better than 1/125.

So this is about a trade-off. You are exchanging communication paths by responsabilities. What you want in the end to have a reasonable architecture, with knowledge distributed evenly.

Upvotes: 1

Robert Bräutigam
Robert Bräutigam

Reputation: 7744

The term "single responsibility" is very nebulous. I find it much easier to think of it in terms of cohesion and coupling. In short, we have to get things that tend to change together (i.e. are strongly cohesive) into one class and things that don't (i.e. are loosely coupled) into separate classes.

In practice that means things that tend to work with the same "data" belong to the same class. This can be easily enforced if data does not leave the object. Even more pragmatically that means avoiding "getter" methods that return data from an object.

Regarding your problem. You're saying it's not a noun, but only because you don't think of it that way. What is your "business logic"? To collect SimilarWords from a Document. Both are nouns. Your phrases are all about what steps should be taken. Rethink your application in terms of what things are involved and what actions those things would be able to do for you.

Here is a short/incomplete design for the things you describe:

public interface Folder {
   public SimilarWords extract();
}

Meaning: I want to extract SimilarWords from a Folder.

public interface TextFile {
   public void chunk(Consumer<Chunk> chunkConsumer);
}

Meaning: TextFile chunks the text.

public class Comparison {
   public Comparison(TextFile file1, TextFile file2);

   public SimilarWords extract();
}

Meaning: Two TextFiles are compared where the SimilarWords come from. You didn't use the word "Comparison" explicitly, I made that up.

And of course SimilarWords need to be added together for all file pairs (?) and then written to some output:

public interface SimilarWords {
   public SimilarWords add(SimilarWords other);

   public void writeTo(OutputStream output);
}

So that would be a proper OO design. I didn't catch all the details of your domain, so this model may be not exactly what you want, but I think you get the point.

Upvotes: 4

Related Questions