3

I have a class called Process, which is extended by some different process types called ProcessA, ProcessB, etc.

class Process{}

class ProcessA extends Process{}
class ProcessB extends Process{}
//...
class ProcessN extends Process{}

There is also another class related to the data of A, but not the Process. I call it TempA

Now ProcessA has a method called calculate(), and TempA needs to be calculated in the same way as ProcessA. As ProcessA extends Process (and Java doesn't allow multiple inheritance), I can't make an abstract class like AbstractA, and use the calculate() method to make these two classes (ProcessA and TempA) have same calculation method.

So how do I make these two classes have the same calculation behaviour/method without copy/paste-duplication of methods?

6

Favour composition over inheritance. If ProcessA and TempA have common behaviour, abstract that behaviour out into a separate class and have both ProcessA and TempA contain a member of that class. This is also good from a testing point of view, as it means you can separately unit test the common behaviour, and (if necessary) mock it out when testing ProcessA and TempA.

  • Is there a working live example from the real world that we can see its source code any example like this? Whenever I try to understand the "patterns", I can see only the main idea from the examples which doesn't have any details. If you know that there is an example code (like from github) or someone put some code for this, can you please share a bit more detail? – Yasin Okumuş May 12 '17 at 11:05
5

If two unrelated classes have the same behavior, you'll be probably better extracting this behavior on some external, isolated class.

In the times of old, this was done quite often in Utilities classes. Almost every project out there had a "Utils" or "Tools" class that had some of miscellaneous stuff for string operations, some number stuff and who knows what else. This wasn't exactly the best way to do this, but it worked fine.

Nowadays is common to segregate non-trivial logic and behaviors on different classes, and them composing them together to achieve the desired effect. This can be done in several different forms of different complexities, with different flavors that will suit different needs. Each one of them has some pros and cons, and a few of them aren't that good if you are thinking in changing stuff in the near future, but you could:

  • Use a static class to provide the needed behavior as a static method; (Fast and simple to do, but unless your "Calculate" method is a pure function, avoid this one.)
  • Create a external class with the needed behavior and make the classes that need it instantiate it on their own; (good, but easy to break if changes are needed in the future)
  • Inject the needed behavior on the constructor of the classes that need it (manually or using some dependency injection framework, if you are already using those). (I recommend this one, personally. I don't like DI frameworks that much but even hand-made DI can make a huge difference).

and so on.

There isn't a single correct way of doing this in a macro level. That said, most of the solutions will require that you isolate this needed behavior somewhere else, out of those classes, so you have there a start!

Just don't copy-paste code around!

-1

Now, ProcessA has a method called calculate(), TempA needs to be calculated in the same way as ProcessA as well.

That indicates to me that ProcessA and TempA have same/similar data.

So how do I make these two classes have the same calculation behaviour/method without copy/paste-duplication of methods?

Gather all the data from ProcessA and TempA for the calculation.
Use a helper class, call it Calculator, to do the real computation by using the common data of ProcessA and TempA.

  • This is good until the last line - global functions obviously ruin all encapsulation, and make unit testing really hard. – Philip Kendall May 10 '17 at 15:41
  • @PhilipKendall, it's not too hard to refactor the notion of a global function into the member function of a functor-like class. – R Sahu May 10 '17 at 15:50
  • Absolutely. So why were you recommending using a global function? – Philip Kendall May 10 '17 at 15:54
  • @PhilipKendall, I wasn't aware of testability problems of global functions. Thanks for the LOTD :) – R Sahu May 10 '17 at 15:55
  • @PhilipKendall They aren't that bad if they are pure functions (no collateral effects), however! – T. Sar - Reinstate Monica May 10 '17 at 17:00

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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