Is there a better way to call an overridden method of a derived class from its abstract base class?

I have an abstract base class from which many classes are derived. I want derived classes to be able to override the virtual method defined in the base class, but there is complex logic in the base class that determines if the overridden method is included at any given moment.

Consider this code - one possible solution - for example:

public abstract class AbstractBaseClass { public bool IsMethodEnabled { get; set; } public virtual void DerivedMethod() { } public void Method() { if (IsMethodEnabled) DerivedMethod(); } } public class DerivedClass : AbstractBaseClass { public override void DerivedMethod() { Console.WriteLine("DerivedMethod() was called."); } } 

In the above example, IsMethodEnabled is a shorthand for more complex logic that determines whether DerivedMethod should be called - this is the code I want to encapsulate in a base class so that I don't have to reproduce it in every derived class.

The project works as intended. If I ran this sample code:

 AbstractBaseClass a1 = new DerivedClass() { IsMethodEnabled = false }; AbstractBaseClass a2 = new DerivedClass() { IsMethodEnabled = true }; a1.Method(); a2.Method(); 

... I see exactly one DerivedMethod call, as expected.

But something spoils me wrong in this implementation. I feel that there should be a more elegant way to handle this. Is there a better way to selectively invoke a method implementation of a derived class from its abstract base class? Is there a design template that would serve me better here?

In other words, does the code above smell?

+6
source share
6 answers

This is a very reasonable implementation.

The main changes that I would suggest are as follows:

  • Make a virtual method that implements protected functionality instead of public
  • Use a more appropriate name for this. Maybe something like public void Method() and protected virtual void OnMethod()
+4
source

I agree with Reed that this is a reasonable implementation.

However, I would think about the following: who are you trying to protect here? I am well versed in base classes so that they can be easily and safely expanded, but I also think that a developer who writes a derived class knows more than a developer who wrote a base class. They may know better than you, regardless of whether this method is enabled or not.

+4
source

It doesn't smell anymore than other Template Methods that some people don’t like. I tend to agree with some points made here . Especially these two:

  • It is difficult to understand the flow of the program - in my experience there are very few levels of template and inheritance methods for debugging or to understand the complexity of the sequence of method calls (only 2 or 3). When the template methods are really pressed (many abstract methods at several levels), it can become painful to debug this type of system.

  • Difficult to maintain - By supporting a couple of pieces of code that make extensive use of the template method, this can be challenging. Such a system can quickly become fragile. Changes at any level can disrupt work above or below this level in the template methods. Often there is a sense of unpredictability when adding new functionality, because it is difficult to predict how behavior will change in all cases. You are often also inclined to create finer and finer settings separating the algorithmic parts of the template class and inserting more layers, thereby exacerbating the problem.

In general, I think you should be very careful with the Template Method and keep things simple and focused.

+1
source

It seems you are trying to separate the decision to call a method from the method itself. If the only reason to have a base class is to encapsulate this solution and make its code reusable, I think you could use a more loosely coupled design that would make it easier to test each behavior separately:

 public interface IDoSomething { void Method(); } public class ConditionallyDoSomething : IDoSomething { private IDoSomething _wrapped; public ConditionallyDoSomething(IDoSomething wrapped) { _wrapped = wrapped; } public bool IsMethodEnabled { get; set; } // could be quite complex... public void Method() { if (IsMethodEnabled) { _wrapped.Method(); } } } public class DoSomething : IDoSomething { public void Method() { // do something... } } 

Thus, you can mock IDoSomething and test each part (decision making and functionality) separately. But it is justified if you really have complex logic in both behaviors that benefit from this separation. I'm just trying to give an alternative to other great answers here. Ultimately, it depends on your specific scenario.

+1
source

You can simply mark all methods that should be redefined as abstract, and those methods that can be further redefined as virtual. See Abstract C # Classes

0
source

It depends on how expensive IsMethodEnabled is (really), assuming that it is not a compiler generated, as shown in the figure, and whether IsMethodEnabled will change frequently and whether there are hundreds of methods with a small bit of logic “included” there, and whether method () the critical way is actually performance.

0
source

Source: https://habr.com/ru/post/897274/


All Articles