oopdesign-patternsarchitectureconceptual

How to make interface implementors that are not sub classes of its abstract class behave like abstract class of that interface?


I want to explain my question with an example. Lets say that i have an interface:

interface IActionPerformer
{
    bool IsReadyToExecuteAction();
    void Action();
    IActionImplementor GetImplementor();
}

And an implementor for Action() method. I don't know if it is the right or wrong way to do so, but anyways, keep reading i will explain my purpose. Implementor:

interface IActionImplementor
{
   void Action();
}

And an abstract class that implements IActionPerformer:

abstract class ActionPerformerBase: IActionPerformer
{
   private IActionImplementor _implementor;
   public abstract bool IsReadyToExecuteAction();
   public IActionImplementor GetImplementor()
   {
      return _implementor;
   }
   public void Action()
   {
      if (IsReadyToExecuteAction())
      {
         GetImplementor().Action();
      }
   }

   protected ActionPerformerBase(IActionImplementor implementor)
   {
      this._implementor = implementor;
   }
}

Now sub classes which inherit from this abstract class, execute the actual action only if it is ready to execute.

But let's say that i have an object in my software, that inherits from a different super class. But at the same time, this object must behave like an IActionPerformer. I mean this object must implement IActionPerformer interface, like:

class SomeOtherSubClass : SomeOtherSuperClass, IActionPerformer

At this point, i want to execute Action() method with controlling if it is ready to execute.

I thought invoking method with another object might be a solution. I mean, a controller or handler object gets interface as a parameter and invokes method the way i want. Like:

IActionInvoker.Invoke(IActionPerformer performer)
{
   if (performer.IsReadyToExecuteAction())
   {
      performer.Action();
   }
}

Or every IActionPerformer implementor has a IActionPerformer or ActionPerformerBase(it feels better) object which handles the real control like:

class SomeOtherSubClass : SomeOtherSuperClass, IActionPerformer
{
   ActionPerformerBase _realHandler;
   public bool IsReadyToExecuteAction()
   {
      return _realHandler.IsReadyToExecuteAction();
   }
   public void Action()
   {
      _realHandler.Action();
   }
   .
   .
   .
}

//This is the one get the job done actually.
class RealHandlerOfSomething : ActionPerformerBase

I might not be that clear trying to explain my question. I'm new to concepts like abstraction, design patterns and sort of stuff like that. And trying to figure out them. This one looks like a decorator, it is a IActionPerformerand it has a IActionPerformer. But when i study decorator pattern, i saw it is like going from shell to the core, i mean every object executes its method and the wrapped objects method. It is a bit different in my example, i mean question. Is this what we call as "encapsulation"? Or do i have big issues understanding the concepts?

I hope i explained myself clearly. Thanks for everyone reading, trying to help.

Have a nice day/night.


Solution

  • As Design Patterns states in chapter one:

    Favor object composition over class inheritance

    This was in 1994. Inheritance makes things complicated. The OP is another example.

    In the following, I'll keep IActionPerformer and ActionPerformerBase as is. Since inheritance is isomorphic to composition, everything you can do with inheritance, you can also do with composition - and more, such as emulating multiple inheritance.

    Here's how you can implement the IActionPerformer interface from another subclass, and still reuse ActionPerformerBase:

    public class SomeOtherSubClass : SomeOtherSuperClass, IActionPerformer
    {
        private readonly ActionPerformerBase @base;
    
        public SomeOtherSubClass(ActionPerformerBase @base)
        {
            this.@base = @base;
        }
    
        public void Action()
        {
            // Perhaps do something before calling @base...
            @base.Action();
            // Perhaps do something else after calling @base...
        }
    
        // Other methods of IActionPerformer go here, possibly following the same pattern...
    }
    

    SomeOtherSubClass composes with any ActionPerformerBase, and since ActionPerformerBase has the desired functionality, that functionality is effectively reused.

    Once you've figured out how to use composition for reuse instead of inheritance, do yourself a favour and eliminate inheritance from your code base. Trust me, you don't need it. I've been designing and writing production code for more than a decade without inheritance.