jeudi 1 avril 2021

Is there a good C# pattern for composition with interfaces?

Suppose that I have a base interface, IBase, that describes some minimal behavior that I care about. Additionally, there are some specific functionality interfaces, IFunctionalityA and IFunctionalityB, that provide some specialized algorithms. Also, I have some actor, Actor, that performs some operation on IBase objects. Finally, I want to wrap an IBase in a class that keeps the same interface implementations. Is there a good pattern/code structure to help me do this?

The Desired Effect

Here's the setup:

interface IBase {}
interface IFunctionalityA : IBase
{
  int DoSomethingA();
}
interface IFunctionalityB : IBase
{
  int DoSomethingB();
}

// This class is the main implementation problem.
class Wrapper
{
  IBase wrapped;
  Wrapper(IBase obj) { wrapped = obj } 
}

class Actor
{
  void Act(IBase obj)
  {
    int result;
    if (obj is IFunctionalityA objA)
      result = objA.DoSomethingA();
    if (obj is IFunctionalityB objB)
      result = objB.DoSomethingB();
  }
}

Then, if you created a wrapper with an IFunctionalityA object,

IFunctionalityA objA;
var wrapper = new Wrapper(objA);

the wrapper would act like it implemented IFunctionalityA

// ACTS LIKE
class Wrapper : IFunctionalityA
{
  IFunctionalityA wrapped;
  int DoSomethingA() => wrapper.DoSomethingA();
}

and similarly

IFunctionalityB objB;
var wrapper = new Wrapper(objB);

would act like it implemented IFunctionalityB

// ACTS LIKE
class Wrapper : IFunctionalityB
{
  IFunctionalityB wrapped;
  int DoSomethingB() => wrapper.DoSomethingB();
}

Obviously the code can't work exactly like this. I'm looking for a pattern that helps me achieve the same effect.

Restrictions

  1. I can't use generics in the obvious way. I can't just have
    class Wrapper<T> where T : IBase { /*...*/ }
    
    because I just have a collection of IBase objects.
  2. I can't use a property like so
    class Wrapper
    {
      IBase wrapped;
      bool ImplementFunctionalityA => wrapped is IFunctionalityA;
      bool ImplementFunctionalityB => wrapped is IFunctionalityB;
    }
    
    because I'd lose a lot of flexibility that I gain from inheritance in the first place and I have many functionality interfaces.

Possible Solution

I could try to implement a service provider-style design.

interface IBase
{
  T GetFunctionality<T>() where T : IFunctionality;
}
interface IFunctionality { }
interface IFunctionalityA : IFunctionality { int DoSomethingA() { /*...*/ }
interface IFunctionalityB : IFunctionality { int DoSomethingB() { /*...*/ }

class Wrapper : IBase
{
  IBase wrapped;
  T GetFunctionality<T>() where T : IFunctionality
  {
    return wrapped.GetFunctionality<T>();
  }
}

This seems like it would work fine but it seems like it might fragment the connection between the base behavior and specific functionalities. Perhaps that's okay or even better. I'm not sure but any suggestions for patterns, principles, or design would be greatly appreciated. Thanks!

Aucun commentaire:

Enregistrer un commentaire