Assistant class (s) versus functional inheritance. Best practice

I have command classes that implement the ICommand {Execute} interface. Several commands have repeating snippets of code. I have several DRY options:

  • Create a static helper class and move the duplicated code there.
  • Creating command inheritance using protected helper methods

What do you suggest and why?

ADDED Thanks to everyone who answered, many of the answers were the same and helpful!

+6
language-agnostic inheritance
source share
8 answers

It completely depends on the nature of your duplicated code.

What are the inputs / outputs of the auxiliary functions? Do they work with a logically related set of variables? Then - yes, it is better to create a base class with these variables as members and the associated set of helper functions.

Otherwise, if the parameters in your auxiliary functions are not consistent, you will still implement these functions as static functions, right? I see no reason to complicate things with inheritance in this case, and I would only do this with helper functions (or, if your language does not handle functions as first-class citizens, use a static helper class).

+3
source share

Instead of static classes, another option is to put the generic code in a new class and use dependency injection to inject the helper class into commands. This also applies to composition over the concept of inheritance.

+5
source share

If it is likely that duplicate logic might be needed by other classes outside the hierarchy, I would put it in static helper classes. Otherwise, in a base class with protected inheritance.

+3
source share

In my opinion, I would put the duplicated code in the base class if it applies only to this class hierarchy and will not be used outside it. If it is likely that the code will be used in different classes, move it to a helper class as part of a common project.

Enjoy it!

+2
source share

There is probably no right / wrong answer here, although I suggest that you could certainly implement it poorly. It probably depends a lot on your actual requirements and how your teams relate to each other. Actually, I would probably go with the implementation of the base class and the inheritance hierarchy, considering that these commands are connected, and the code is directly connected to the commands themselves, and not to some external object, which should be a class in its own right. Of course, they are connected by the fact that they are teams, and the base class can reflect this.

If you have code that is common to subsets of unrelated commands, however, and creating an inheritance hierarchy would force relationships that don't exist, and then adding a helper to the class (non-static, if possible, to improve testability) would be a completely natural way to solve this problem. You may find that you can group the "helper" methods naturally into your own classes. For example, if several methods need to interact with your authentication subsystem, you may have AuthenticationMediator for these methods. I also do not see conflicts with some of them.

+1
source share

Using helpers inside your own code is bad practice that comes from laziness.

The only possible situation in which you really need helpers is to extend the behavior of private classes from third-party libraries such as selenium, etc.

What is an assistant? This is a static method that sits from the class itself.

What problems do we get?

  • static method. Has problems with unit tests. For example, our developers added caching to helpers. As a result, it was not possible to simply mock these methods, while I had to add to many logics just for a simple mockery. Yes, there is the likelihood of using the static method incorrectly ... but at the beginning no one expected the state to be added to the helper.
  • a place. The method is in another class, far from the core logic. This is the wrong code design concept.

When to use the assistant? When you need to expand a third-party library without the possibility of its inheritance. Otherwise, just inherit the lib.

When not using helpers? Reduce duplicate code. You need to move this code to another service. Read about DDD to improve your refactoring skills and know how to make the best use of the service.

+1
source share

If the logic works with interface elements and not with implementation elements, it is recommended to write an auxiliary method [or extension method].

public IRandom { byte NextByte (); } public static class IRandomExtensions { // logic that acts against public interface IRandom // may be applied to all implementations public static int GetNextUnbiasedInteger (this IRandom random) { } public static IEnumerable<T> Shuffle<T> ( this IRandom random, IEnumerable<T> items) { } } 

If business logic works against implementation members,

 public class SomeCommand : ICommand { // an implementation-specific member, NOT a member // of ICommand public int SomeControlCount { get; set; } } // a method that references implementation-speciic // details. where should this go? public void DoSomething () { SomeCommand command; int count = command.SomeControlCount; } 

then, most likely, we should more rigidly bind this to the implementation class. If this is a fairly common occurrence, then the base class may make sense.

Personally complex hierarchies are more problems than they are worth it, use your own opinion regarding maintainability, legibility and reuse, and you should be fine!

Hope this helps! :)

0
source share

Use helpers without code.

A state-dependent code with several methods uses inheritance. For example, when several methods use a common member variable and thus maintain a shared state.

The goal is to reduce the amount of duplicated code, and it depends on what code it is. However, I really hate it when people overdo it and make super-abstract classes or helper functions that make 7 jumps with another abstract strangulation code called "Executor" "Invoker" "DataConveyer" "DataManager" "SharedCode". And something at the end of all these jumps actually managed to do the work that she had expected, but so interconnected with each that you do not know where to make new changes to this new function. Should I do this DataConveyer, or should I do this in the DataManager?

So the golden goal should be, let it be simple.

0
source share

All Articles