Question

In C#, I have a class hierarchy with a couple of abstract base classes near the top and a fair number of derived classes. A few these concrete classes have some common properties and methods that are implemented identically. It strikes me as wasteful and so one solution might be to implement this common behaviour in another abstract base class.

abstract class Control;

abstract class SquareControl: Control
{
    public int SquarishProperty;
    public void SquarishMethod();
};

class Window: SquareControl;
class Button: SquareControl;

However, what if several other classes in the hierarchy shared some other behaviour but also share something in common with one of the controls from another base class? Perhaps there are lots of areas of commonality. It would become impractical to model this with abstract base class implementation wouldn't it?

abstract class FlashableControl: Control
{
    public int FlashyProperty;
    public void FlashMethod();
};

class StatusBar: FlashableControl;  // but it's also a bit square too, hmm...

So how do you go about sharing such implementations across classes without using base classes?

I imagine I want to delegate the implementaion of an interface to another class and have that class implement those properties and methods on behalf of the desired classes, so that to the user, the StatusBar and Window appear to support a standard interface, but under the covers it's something else that implements it.

I can visualise aggregating classes that implement this behaviour, but is this appropriate and are there any pitfalls? What are the alternatives?

Thanks

Was it helpful?

Solution

You can use a pattern like this:

public interface ICommonServices
{
    string SomeProperty { get; set; }

    void SomeMethod(string param);
}

public static class CommonServiceMethods
{
    public static void DoSomething(this ICommonServices services, string param)
    {
        services.SomeMethod(services.SomeProperty + ": " + param + " something extra!");
    }
}

All classes that implement ICommonServices now also get some free behavior via the extension method, which depends solely on those features exposed by all ICommonServices implementers. If you need access to base class functionality, you can put that in its own interface and have ICommonServices implement that interface as well. Now you can create 'default' extension functionality for interfaces without having to use multiple base classes.


EDIT

If you want some of these methods to be internal, you can modify the pattern like this:

public class MyObject : IServices
{
    public string PublicProperty { get; private set; }

    string IServices.SomeProperty { get; set; }

    void IServices.SomeMethod(string param)
    {
        //Do something...
    }
}

public interface IPublicServices
{
    string PublicProperty { get; }
}

internal interface IServices : IPublicServices
{
    string SomeProperty { get; set; }

    void SomeMethod(string param);
}

internal static class ServiceMethods
{
    public static void DoSomething(this IServices services, string param)
    {
        services.SomeMethod(services.SomeProperty + ": " + param + " something extra!");
    }
}

Basically we're exposing both public and internal interfaces. Note that we implement the internal interface methods explicitly, so that the methods are not available for public consumption (since the public client can't get access to the interface type.) In this case, the helper extension methods are internal, relying on the internal interface, though you could also create public helper methods that rely on the public interface.

OTHER TIPS

You could use 'has-a' instead of 'is-a' and delegate to an internal square control

    class Window : Control, ISquareControl
    {
        private SquareControl square;

        public void SquareOperation()
        {
            square.SquareOperation();
        }
    }

    class SquareControl : Control, ISquareControl
    {
        public void SquareOperation()
        {
            // ...
        }
    }

One way is to use Interfaces and Base Classes.

Flashable would make a good Interface instead of a class.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top