50

I am currently working on a software project that performs compression and indexing on video surveillance footage. The compression works by splitting background and foreground objects, then saving the background as a static image, and the foreground as a sprite.

Recently, I have embarked on reviewing some of the classes that I have designed for the project.

I noticed that there are many classes that only have a single public method. Some of these classes are:

  • VideoCompressor (with a compress method that takes in an input video of type RawVideo and returns an output video of type CompressedVideo).
  • VideoSplitter (with a split method that takes in an input video of type RawVideo and returns a vector of 2 output videos, each of type RawVideo).
  • VideoIndexer (with an index method that takes in an input video of type RawVideo and returns a video index of type VideoIndex).

I find myself instantiating each class just to make calls like VideoCompressor.compress(...), VideoSplitter.split(...), VideoIndexer.index(...).

On the surface, I do think the class names are sufficiently descriptive of their intended function, and they are actually nouns. Correspondingly, their methods are also verbs.

Is this actually a problem?

  • 14
    It depends on the language. In a multi-paradigm language like C++ or Python, these classes have no business existing: Their "methods" should be free functions. – user7043 Jan 29 '14 at 8:35
  • 3
    @delnan: even in C++, you typically use classes for creating modules, even if you don't need the full "OO capabilities". Indeed, there is the alternative of using namespaces instead for grouping "free functions" together to a module, but I don't see any advantages in that. – Doc Brown Jan 29 '14 at 11:52
  • 5
    @DocBrown: C++ has namespaces for that. In fact in modern C++ you often use free functions for methods, because they can be (statically) overloaded for all arguments while methods can only be overloaded for the invocant. – Jan Hudec Jan 29 '14 at 11:58
  • 2
    @DocBrown: It is a very core of the question. Modules using namespaces having just one "external" method are perfectly fine when the function is sufficiently complex. Because namespaces don't pretend to represent anything and don't pretend to be object-oriented. Classes do, but classes like this are really just namespaces. Of course in Java you can't have a function, so this is the result. Shame on Java. – Jan Hudec Jan 29 '14 at 12:11
  • 2
    Related (almost a duplicate): programmers.stackexchange.com/q/175070/33843 – Heinzi Jan 29 '14 at 13:01
85

No, this is not a problem, quite the opposite. It is a sign of modularity and clear responsibility of the class. The lean interface is easy to grasp from the viewpoint of a user of that class, and it will encourage loose coupling. This has many advantages but almost no drawbacks. I wish more components would be designed that way!

  • 6
    This is the correct answer, and I have upvoted it, but you could make it better by explaining some of the advantages. I think what the OP's instinct is telling him is a problem is something else ... that is, that VideoCompressor is really an interface. Mp4VideoCompressor is a class and should be interchangable with another VideoCompressor without copying the code for a VideoSplitter to a new class. – pdr Jan 29 '14 at 17:31
  • 1
    Sorry but you're wrong. A class with a single method should just be a standalone function. – Miles Rout Feb 4 '14 at 23:20
  • 3
    @MilesRout: your comment shows you misunderstood the question - the OP wrote about a class with one public method, not with one method (and he indeed meant a class with multiple private methods, as he told us here in one comment). – Doc Brown Feb 5 '14 at 7:22
  • 2
    "A class with a single method should just be a standalone function. " A gross assumption about what that method is. I have a class with one public method. BEHIND IT are multiple methods in that class plus 5 other classes that have absolutely no idea of the client. Excellent application of SRP will yield clean, simple interface of the layered class structure, with that simplicity manifesting all the way to the top. – radarbob Oct 2 '15 at 23:24
  • 2
    @Andy: the question was "is this a problem" and not "does this conform to a specific OO definition". Moreover, there is absolutely no sign in the question the OP means classes with no state. – Doc Brown Oct 19 '15 at 4:15
26

It is no longer object oriented. Because those classes don't represent anything, they are just vessels for the functions.

That does not mean it's wrong. If the functionality is sufficiently complex or when it's generic (i.e. the arguments are interfaces, not concrete final types), it makes sense to put that functionality in separate module.

From there it depends on your language. If the language has free functions, they should be modules exporting functions. Why pretend it's a class when it isn't. If the language does not have free functions like e.g. Java, then you create classes with single public method. Well, that just shows the limits of object oriented design. Sometimes functional is simply better match.

There is one case when you may need a class with single public method because it has to implement interface with single public method. Be it for observer pattern or dependency injection or whatever. Here it again depends on the language. In languages that have first class functors (C++ (std::function or template parameter), C# (delegate), Python, Perl, Ruby (proc), Lisp, Haskell, ...) these patterns use function types and don't need classes. Java does not (yet, will in version 8) have function types, so you use single method interfaces and corresponding single method classes.

Of course I am not advocating writing single huge function. It should have private subroutines, but they can be private to the implementation file (file-level static or anonymous namespace in C++) or in a private helper class that is only instantiated inside the public function (To store data or not?).

  • 12
    "Why pretend it's a class when it isn't." Having an object instead of a free function allows state and subtyping. That could prove valuable in a world where requirements change. Sooner or later there's a need to play with video compression settings or to provide alternate compression algorithms. Before that the word "class" simply tells us that this function belongs to an easily extensible and interchangeable software module with a clear responsibility. Isn't that what OO really aims at? – COME FROM Jan 29 '14 at 14:05
  • 1
    Well, if it only has one public method (and kind of implying no protected ones), it can't really be extended. Of course packing compression parameters might make sense in which case it becomes function object (some languages have separate support for those, some don't). – Jan Hudec Jan 29 '14 at 14:11
  • 3
    This is a fundamental connection between objects and functions: a function is isomorphic to an object with a single method and no fields. A closure is isomorphic to an object with a single method and some fields. A selector function returning one of several functions which all close over the same set of variables is isomorphic to an object. (In fact, this is how objects are encoded in JavaScript, except you use a dictionary data structure instead of a selector function.) – Jörg W Mittag Jan 29 '14 at 16:19
  • 4
    "It is no longer object oriented. Because those classes don't represent anything, they are just vessels for the functions." - This is wrong. I would argue this approach is MORE object-oriented. OO does not mean it represents a real-world object. A large amount of programming deals with abstract concepts, but does this mean you cannot apply an OO approach to solve it? Definitely not. It's more about modularity and abstraction. Each object has a single responsibility. This makes it easy to wrap your head around the program and make changes. Not enough space to list the numerous benefits of OOP. – Despertar Jan 30 '14 at 0:03
  • 2
    @Phoshi: Yes, I understand. I never claimed that a functional approach wouldn't work as well. However, that is clearly not the topic. A video compressor or a video transmogrifier or whatever is still a perfectly valid candidate for an object. – COME FROM Jan 30 '14 at 20:29
13

There may be reasons to extract a given method into a dedicated class. One of those reasons is to allow Dependency Injection.

Imagine you have a class called VideoExporter which, eventually, should be able to compress a video. A clean way would be to have an interface:

interface IVideoCompressor
{
    Stream compress(Video video);
}

which would be implemented like this:

class MpegVideoCompressor : IVideoCompressor
{
    // ...
}

class FlashVideoCompressor : IVideoCompressor
{
    // ...
}

and used like this:

class VideoExporter
{
    // ...
    void export(Destination destination, IVideoCompressor compressor)
    {
        // ...
        destination = compressor(this.source);
        // ...
    }
    // ...
}

A bad alternative would be to have a VideoExporter which has plenty of public methods and does all the job, including the compressing. It would quickly become a maintenance nightmare, making it hard to add support for other video formats.

  • 2
    Your answer does not distinguish between public and private methods. It could be understood as a recommendation for putting all code of a class just one method, but I guess that is not what you meant? – Doc Brown Jan 29 '14 at 8:31
  • 2
    @DocBrown: Private methods are not relevant to this question. They can be put on internal helper class or whatever. – Jan Hudec Jan 29 '14 at 12:16
  • 2
    @JanHudec: currently the text is "A bad alternative would be to have a VideoExporter which has plenty of methods" - but it should be "A bad alternative would be to have a VideoExporter which has plenty of public methods". – Doc Brown Jan 29 '14 at 12:20
  • @DocBrown: Agree here. – Jan Hudec Jan 29 '14 at 12:21
  • 2
    @DocBrown: thank you for your remarks. I edited my answer. Originally, I thought that is was assumed that the question (and so my answer) is about public methods only. It appears that it's not as obvious. – Arseni Mourzenko Jan 29 '14 at 13:04
6

This is a sign that you want to pass functions as arguments to other functions. I'm guessing your language (Java?) doesn't support it; if that's the case, it's not so much a failing in your design as it is a shortcoming in your language of choice. This is one of the biggest problems with languages that insist that everything must be a class.

If you aren't actually passing these faux-functions around then you just want a free/static function.

  • 1
    Since Java 8, you have lambdas, so you pretty much can pass functions. – Silviu Burcea Jan 30 '14 at 8:49
  • Fair point, but that won't be officially released for a little while longer, and some workplaces are slow to move to newer versions. – Doval Jan 30 '14 at 17:43
  • Release date is in March. Also, EAP builds were very popular for JDK 8 :) – Silviu Burcea Jan 30 '14 at 18:45
  • Although, as Java 8 lambdas are simply a shorthand way for defining objects with only one public method, other than saving a little bit of boilerplate code, they make no difference at all here. – Jules Feb 19 '16 at 21:32
5

I know I'm late to the party but as every one seems to have missed to point this out:

This is a well known design pattern called: Strategy Pattern.

Strategy pattern is used when there are several possible strategies to solve a sub-problem. Typically you define an interface that enforces a contract on all implementations and then use some form of Dependency Injection to provide the concrete strategy for you.

For example in this case you could have interface VideoCompressor and then have several alternative implementations for example class H264Compressor implements VideoCompressor and class XVidCompressor implements VideoCompressor. It is not clear from OP that there is an interface involved, even if there is not, it may simply be that the original author left the door open to implement strategy pattern if needed. Which in and of itself is good design too.

The problem that OP constantly finds herself instantiating the classes to call a method is a problem with her not using dependency injection and the strategy pattern correctly. Instead of instantiating it where you need it, the containing class should have a member with the strategy object. And this member should be injected, for example in the constructor.

In many cases the strategy pattern results in interface classes (as you are showing) with just a single doStuff(...) method.

1
public interface IVideoProcessor
{
   void Split();

   void Compress();

   void Index();
}

What you've got is modular and that's good, but if you were to group these responsibilities into IVideoProcessor, that would probably make more sense from DDD point of view.

On the other hand, if splitting, compressing and indexing wasn't related in any way, than I'd keep them as separate components.

  • As the reason for each of these functions needing to change is somewhat different, I'd argue that putting them together like this violates SRP. – Jules Feb 19 '16 at 21:35
0

It is a problem - you are working from the functional aspect of the design, rather than the data. What you actually have are 3 standalone functions that have been OO-ified.

For example, you have a VideoCompressor class. Why are you working with a class designed to compress video - why do you not have a Video class with methods on it to compress the (video) data that each object of this type contains?

When designing OO systems, its best to create classes that represent objects, rather than classes that represent activities that you can apply. In the old days, classes were called types - OO was a way to extend a language with support for new data types. If you think of OO like this, you get a better way of designing your classes.

EDIT:

let me try to explain myself a little better, imagine a string class that has a concat method. You can implement such a thing where each object instantiated from the class contains the string data, so you can say

string mystring("Hello"); 
mystring.concat("World");

but the OP wants it to work like this:

string mystring();
string result = mystring.concat("Hello", "World");

now there are places where a class can be used to hold a collection of related functions, but that is not OO, its a handy way of using the OO features of a language to help manage your codebase better, but it is no way any kind of "OO Design". The object in such cases is totally artificial, simply used like this because the language does not offer anything better to manage this kind of problem. eg. In languages such as C# you would use a static class to provide this functionality - it reuses the class mechanism, but you no longer need to instantiate a object just to call the methods on it. You do end up with methods like string.IsNullOrEmpty(mystring) which I think is poor compared to mystring.isNullOrEmpty().

So, if anyone is asking "how do I design my classes", I recommend thinking of the data the class will contain rather than the functions it contains. If you go for the "a class is a bunch of methods", then you end up writing "better C" style code. (which isn't necessarily a bad thing if you are improving C code) but it is not going to give you the best OO designed program.

  • 9
    -1, I totally disagree. Beginners OO design works only with data objects like a Video and tends to overblow such classes with functionality, which often ends in messy code with >10K LOC per class. Advanced OO design breaks functionality down to smaller units like a VideoCompressor (and lets a Video class just be a data class or a facade for the VideoCompressor). – Doc Brown Jan 29 '14 at 11:44
  • 5
    @DocBrown: At which point it however is no longer an object oriented design, because the VideoCompressor does not represent an object. There's nothing wrong with that, just shows the limit of object oriented design. – Jan Hudec Jan 29 '14 at 11:56
  • 3
    ah but beginners OO where 1 function gets turned into a class isn't really OO at all, and only encourages the massive decoupling that ends up in a thousand files of classes no-one can maintain. I think its best to think of a class as a "data-wrapper" not a "functionality wrapper", that'll give a beginner a better understanding of how to think about OO programs. – gbjbaanb Jan 29 '14 at 11:57
  • 4
    @DocBrown actually accurately highlighted my concern; I indeed do have a Video class, but the compression methodology is in no way trivial, so I would actually break down the compress method into multiple other private methods. This is part of the reason of my question, after having read Don't create verb classes – yjwong Jan 29 '14 at 12:08
  • 2
    I think it might be ok to have a Video class, but it would be composed of a VideoCompressor, a VideoSplitter, and other related classes, which should, in good OO form, be highly cohesive individual classes. – Eric King Jan 29 '14 at 15:20
-1

The ISP (interface segregation principle) says that no client should be forced to depend on methods it does not use. The benefits are multiple and clear. Your approach totally respects the ISP, and that's good.

A different approach also respecting the ISP is, for example, create an interface per each method (or set of methods with a high cohesion) and then have a single class implementing all those interfaces. Whether this is or not a better solution depends on the scenario. The benefit of this is, when using dependency injection, you could have a client with diferent collaborators (one per each interface) but in the end all the collaborators will point to the same object instance.

By the way, you said

I find myself instantiating each class

, these classes seem to be services (and thus stateless). Have you thought about making them singletons?

  • 1
    Singletons are, usually, antipattern. See Singletons: Solving problems you didn't know you didn't have since 1995. – Jan Hudec Jan 29 '14 at 14:48
  • 3
    For the rest while interface separation principle is a good pattern, this question is about the implementations, not the interfaces, so I'm not sure it's relevant. – Jan Hudec Jan 29 '14 at 14:50
  • 3
    I'm not gonna enter to discuss whether the singleton is a pattern or an antipattern. I suggested a possible solution (it has even a name) to its problem, it's up to him to decide whether it fits or not. – diegomtassis Jan 29 '14 at 15:48
  • Regarding whether the ISP is relevant or not, well, the subject of the question is "are classes with only a single method a problem?", the opposite of that is a class with many methods, which becomes a problem the moment you make a client depend directly on it... exactly the Robert Martin's xerox example it took him to formulate the ISP. – diegomtassis Jan 29 '14 at 15:57
-1

Yes, there is a problem. But not severe. I mean you can structure your code like this and nothing bad will happen, it is maintainable. But there are some weaknesses to that kind of structuring. For example consider if representation of your video (in your case it is grouped in RawVideo class) changes, you will need to update all your operation classes. Or consider that you might have multiple representations of video that vary in runtime. Then you will have to match representation to particular "operation" class. Also subjectively it is annoying to drag around a dependency for each operation you want to do on smth. and to update list of dependencies passed around every time you decide that operation is no longer needed or you need new operation.

Also that's actually a violation of SRP. Some people just treat SRP as a guide for splitting responsibilities (and take it to far by treating each operation a distinct responsibility) but they forget that SRP is also a guide to grouping responsibilities. And according to SRP responsibilities that change for same reason should be grouped together so that if change happens it is localized to as little classes/modules as possible. As for big classes it is not a problem having multiple algorithms in same class as long as those algorithms are related (i.e. share some knowledge that should not be known outside of that class). The problem are big classes that have algorithms that are not related in any way and change/vary for different reasons.

protected by gnat Dec 14 '17 at 17:24

Thank you for your interest in this question. Because it has attracted low-quality or spam answers that had to be removed, posting an answer now requires 10 reputation on this site (the association bonus does not count).

Would you like to answer one of these unanswered questions instead?

Not the answer you're looking for? Browse other questions tagged or ask your own question.