-1

I have a couple of derived classes that are generally similar, but don't have a directly shared base class. All these classes implement a common interface. I noticed when I added another (new) derived class, that I copy a couple of private methods from the other classes which have similar content, but the actual implementation differs a bit. They have mostly to do with the internal workings of the class and are not required to be public or internal.

Example:

public class MyButton : Button, ICoolFoo
{
    private void InitializeFoo()
    {
        // Only used from class
    }

    private void UpdateFoo()
    {
        // Only used from class
    }

    public Foo SomeFoo()
    {
        // From ICoolFoo.
    }
}

public class MyLabel : Label, ICoolFoo
{
    private void InitializeFoo()
    {
        // Only used from class
    }

    private void UpdateFoo()
    {
        // Only used from class
    }

    public Foo SomeFoo()
    {
        // From ICoolFoo.
    }
}

The initialize and update methods are only used from inside the class and don't require access from outside. The consumer of these classes doesn't care about them so putting them in an interface would bloat it unnecessarily.

Now, from a developer's perspective I need to document that implementers of ICoolFoo should have a similar structure to keep the details similar and easy to follow, but are irrelevant to the outside. Ideally I would add something like a base class with private virtual members which I can add to any new class with a few keystrokes, but that doesn't work of course.

Is there any pattern or clever architecture to improve this design?

  • Did you take a look on TemplateMethod pattern? Maybe that's helpful in your case. – Emerson Cardoso Aug 28 '17 at 12:06
  • 3
    What's wrong with a base class? And what's wrong with implementors choosing the implementation details? – Goyo Aug 28 '17 at 12:27
  • 1
    pretty hard to say for a generic case. I would just put a comment "copy template example implementation" and an unused example somewhere. But you could add another internal class FooBuilder or something which forced you to call initiate and update, or inject delegates for them or something – Ewan Aug 28 '17 at 12:58
  • Is the question addressed to new implementations of ICoolFoo or are you trying to expand the solution to the existing ones too (something I presume complex and unecessary)? – Laiv Aug 28 '17 at 22:34
  • @Goyo I can't use a base class because I already inherit from framework classes (Button and Label in this case) and C# doesn't support multiple inheritance. – Lennart Aug 29 '17 at 7:57
2

Assuming you cannot modify Button and/or Label, there is not much left regarding derivation, since C# has only single inheritance.

So, you'd have to turn to composition, probably in the form of the proxy pattern. The proxy pattern effectively allows for starting a new inheritance chain.

There is not enough detail in the question to recommend a specific pattern. However, options using a proxy pattern include:

  • use a new abstract base class CoolFoo that implements ICoolFoo, that is subclassed by MyButton (as in class MyButton : CoolFoo) and operates as a proxy for a Button.

  • use a generic class class CoolFoo<T> : ICoolFoo, where T will be passed Button or Label. This will allow capturing of the object that is being delegated to within the generic class, and method implementations in this generic class can refer to that state (so they can be more complete, and perhaps shared).

  • some combination of the above, e.g. subclass the generic class to make MyButton, as in class MyButton: CoolFoo<Button> { ... }

If needed you can also subclass the original Button (without implementing the interface) in case you need Button specialization in addition to the interface.

From a design perspective, I think one of these could be cleaner. It seems like you might have too much going on in a single class (especially for C#), given subclassing and also implementing the interface.

Essentially the above suggestions separate deriving further off your existing base classes, from implementing the interface.

2

It seems to me this problem does not call for a solution in the object model. There are no dependencies on these methods, after all, and they don't warrant an interface. So polluting your inheritance and other object relationships just for that seems inappropriate, especially if there are ever any exceptions. You just want your devs to follow a pattern.

One way to do this is to set them up with a class template. You can certainly write your own templates so that when they choose "Add New Item" it'll show up. See How to I edit the Visual Studio templates?.

Another thing you might consider is setting up an FxCop or StyleCop rule which checks for this pattern and fails the build if it isn't adhered to.

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.