3

I have a class which is centred around lower-level methods, to make this class much more useful it would be great to put some middle or higher level methods (i.e. methods which make a series of calls to the lower-level methods to do something that an end user may want to do).

I could add the methods to the original class, but the class will get very bloated.

I could write a module of just functions, but they would always need that class an argument.

I could inherit and make a new class: MoreSpecificClass.

What do you guys like best and why?

(I code in python)

Will Beauchamp
  • 209
  • 1
  • 2
  • 7
  • @gnat: Just because one of the suggested possibilities in the question violates SRP, that does not mean the question is a duplicate. – Bart van Ingen Schenau Nov 26 '15 at 13:35
  • @BartvanIngenSchenau this question and its answers explain what OP needs to keep in mind when deciding how to design these functions. I think it's as specific guidance as possible given that question doesn't get into much details about the troublesome code – gnat Nov 26 '15 at 13:42
  • @gnat: I agree with Bart that those other question is at least "not enough of a dupe" for my taste. When we start closing more specific questions concerning application of the SRP just because there was already another, very general question about the SRP where the topmost answer says "use your judgement", we are going to kick too much useful stuff out. Said that, what I do not like on the actual question here is that, though more specific as the "false dupe", it should still be much more specific, in the current form the only serious answer will probably still "it depends". – Doc Brown Nov 26 '15 at 15:15
  • 1
    ... so Will, why don't you add an example for what you have in mind? – Doc Brown Nov 26 '15 at 15:23

2 Answers2

5

First thing I would do is figure out which methods your end user code will require. I would then create an abstract class containing all these methods as abstract methods. This means your user code now depends upon an abstract class which is good because it decouples it from how the methods are implemented and allows you to easily stub out these methods for testing.

Then create a class which implements all these methods and also imports the class containing your low-level code. These methods will make calls to the low level ones. Now if your low=level code changes it wont affect your user code directly, it will just mean you need to update the class implementing the abstract interface.

Then when you build your program your user code takes the abstract class in its constructor and makes all calls through it. This is a form of dependency injection and is a useful tool for decoupling your code.

4

SteveChallender's answer is good, and I upvoted it. (Remember, upvoting stands for "this answer is useful".) However, in your case it might represent a bit of over-engineering. You are the one who really knows, and therefore the one who judges whether it is so, I am simply pointing out the possibility that it might be so.

Here is my input on the three possibilities that you listed:

  • I could add the methods to the original class, but the class will get very bloated.

This could very possibly be your best choice. Lately I have been noticing that many programmers are totally frightened by sheer line counts. Someone reviewing my code once called a 250-line class of mine "awfully long". The poor guy has not seen some 2500-line classes that I have. Here is the thing: if the class is really doing just one thing, and if there is no internal structure in it, (no disjoint sets of internal state used by different groups of methods,) if the methods are simply doing stuff invoking other methods, then they truly all belong to the same class. It is just a fact of life. It is a huge mistake to add unnecessary additional structure to your system's design only in order to reduce the number of lines of an otherwise perfectly fine class, just because the number of lines in that class exceeds some blind preconceptions about what a good number of lines should be. Remember, "Things should be as simple as possible, but not simpler." (A. Einstein.) And that's because if you try and make them "simpler than possible" then you are practically guaranteed that you will actually end up making them more complicated.

  • I could write a module of just functions, but they would always need that class an argument.

Yes, that would not be a very smart thing to do. A large number of functions which all accept a specific class as an argument is in fact a large number of functions screaming "put us in that class!" or at worst, "put us in a class, and make that object a member of that class, so we know where to find it!"

  • I could inherit and make a new class: MoreSpecificClass.

Making functionality available to different subsets of code is one of the least legitimate reasons for using inheritance. You should use inheritance if your MoreSpecificClass has an "is a" relationship with your LessSpecificClass. Will it have such a relationship? Will you ever have a function which accepts "LessSpecificClass" as an argument and be in the need to pass a "MoreSpecificClass" instead? I doubt that you are planning to do such a thing, so I doubt that inheritance is suitable here.

Mike Nakis
  • 32,003
  • 7
  • 76
  • 111