0

Let's say I have a grid with square fields. For the fields I have an abstract Field class. This class has several subclasses, for example EmptyField or RoadField. Some of these fields can be connected to each other, thus I have an interface IConnectable that these classes implement. Now every connectable field should have a Connections object. However interfaces can't have member objects. My idea was that instead of an interface I use another abstract class for that, ConnectableField, which is a subclass of Field and the parent class for all connectable classes. But what do I do if I want to add another such abstract class, say a RotatableField which has a Rotation object. I can't make an interface out of it because of the member object. But I also can't inherit from it because a class can only have one base class. What do I do?

EDIT:

(The following is not actually the reason why I asked this question, it's just an example as to why I don't think I can use interfaces.)

I can't make it an interface because I want to declare an enum, like this:

interface IConnectable {
    public enum Orientation_CW { ZERO, NINETY, ONEEIGHTY, TWOSEVENTY };
}

It won't let me do that with the following error:

Error CS0524 'IConnectable.Orientation_CW': interfaces cannot declare types

15
  • 1
    Can you create interfaces instead? Is there any reason you can't do that? This SO post might be useful.
    – enderland
    Mar 10, 2016 at 14:31
  • 1
    Yes it can? Unless I'm doing it wrong, I just tried it.
    – Bret
    Mar 10, 2016 at 14:43
  • 1
    "However interfaces can't have member objects." Could you show some code to clarify what you mean by this statement, please.
    – David Arno
    Mar 10, 2016 at 14:46
  • 3
    Your question appears to be diverting into something that is much more a "how do I write this code, I'm getting this error" which would tend to be more appropriate to be asked on Stack Overflow as partially evidenced by the code only answers that you are now getting.
    – user40980
    Mar 10, 2016 at 14:57
  • 1
    You asked the question to the wrong place. You have a specific question which should be asked on stackoverflow.com Mar 10, 2016 at 18:23

3 Answers 3

4

Firstly, there is not a single conceivable solution modelled in any OO language using inheritance from a base class, which could not also be modelled effectively using composition.

Inheritance from a base class can occasionally make code more convenient to write when compared with composition, but nothing about the resulting behaviour of the derived class will be any better or different than the alternative solution using composition.

Typically by using inheritance you're just saving yourself from writing a small amount of extra boilerplate code; but in saving that extra boilerplate code you're surrendering a lot of flexibility by forcing your derived class to be entirely dependant on its base class.

So with the above in mind, and to answer your question directly, to solve a problem where you might consider multiple inheritance as a solution, what you're actually seeking is a solution which is more flexible, so you need to rely on composition and accept a bit of additional boilerplate code.

e.g.

// ERROR!
public class MyIllegalClass : MyBaseClass, MyOtherBaseClass 
{
}

Can be represented like this, although you will not get any extra flexibility:

public class MyClass
{
    public MyBaseClass Base { get; private set; }
    public MyOtherBaseClass OtherBase { get; private set; }

    public MyClass()
    {
        // NOT a good solution.  MyClass is still dependent on these. 
        Base = new MyBaseClass();
        OtherBase = new MyOtherBaseClass();
    }
}

For increased flexibility:

// Better - has more flexibility than multiple inheritance
public class MyClass
{
    public MyBaseClass Base { get; private set; }
    public MyOtherBaseClass OtherBase { get; private set; }

    public MyClass(MyBaseClass base, MyOtherBaseClass otherBase)
    {
        // BETTER.  Anything which derives from these will also work.
        Base = base;
        OtherBase = otherBase;
    }
}

In your specific example, the problem you have is not only "What if I want a RotatableField?" but also "What if I want a RotatableConnectableField?" and then later on you might even wonder "what if I want a ColourableRotatableField?" etc.

As the complexity of your Field increases, inheritance will lead you down a very messy pathway, i.e. trying to reconcile Rotatable, Connectable and Colourable behaviours, with whatever else may come in future; which is why other replies have suggested the use of interfaces - Your Field class won't need to worry anything about whether it happens to use a Rotator, A Connector, etc.

e.g. using constructor dependency injection, and treating Rotate/Connect separately:

public class Field
{
    private IRotator _rotator;
    private IConnector _connector;

    public Field(IRotator rotator, IConnector connector)
    {
        _rotator = rotator;
        _connector = connector;
    }
}

public class Program
{
    public static void Main(string[] args)
    {
        var myField = new Field(new NinetyDegreeRotator(), new FieldConnector());
    }
}

or instead of injecting Rotate and Connect as separate concerns, you might rationalise them into a single interface:

public class Field
{
    public void AddModifier(IFieldModifier modifier)
    {
        modifier.Modify(this);
    }
}

public class Program
{
    public static void Main(string[] args)
    {
        var myField = new Field();

        myField.AddModifier(new NinetyDegreeRotator());
        myField.AddModifier(new FieldConnector());
        myField.AddModifier(new BorderColour(Colour.Red));

        // etc.
    }
}

In both cases, Field would remain independent of the behaviour which rotates or connects. The interface(s) will give you more extensibility in future when you decide you want need to change that behaviour in some other way.

1
  • That's a way I didn't think of, thanks a lot! Mar 11, 2016 at 7:44
3

Define the enumeration separately, then include it as a member in the interface. You cannot define an enumeration in the definition of an interface, but the defined enumeration can be a member in the interface.

You can do this in the same file as the interface if you want, as I've done here:

namespace YourNamespace
{
    public enum MyEnum
    {
        A,B,C
    }
    public interface IEnumInterface
    {
        MyEnum SelectedEnum { get; set; }
    }
}

BUT TO ANSWER YOUR QUESTION: I would add interfaces for your classes to implement with appropriate enumerations. From there, your classes would then implement IRotatable, IConnectable, etc.

2
  • 1
    Programmers is about conceptual questions and answers are expected to explain things. Throwing code dumps instead of explanation is like copying code from IDE to whiteboard: it may look familiar and even sometimes be understandable, but it feels weird... just weird. Whiteboard doesn't have compiler
    – gnat
    Mar 10, 2016 at 14:59
  • 1
    My bad, I'll add an explanation.
    – Bret
    Mar 10, 2016 at 14:59
1

You have 2.5 choices:

Solution #1 You have a class that implement IConnectableField and IRotatableField where specific functions could be virtual and derived classes that do not require any of those functions could override with no behavior.

Solution #2 Use interface and have a hierarchy with only one (the preferred*) of the 2: IConnectableField or IRotatableField as a based class and the other as an interface. You could make a class implementing both interface which will let you one problem for any derived class that do not required the preferred* interface functions. You can then derive from an upper base class like 'Field' and implement manually with duplicate code (drawback of single inheritance), your expected behavior.

Solution #2.5 Use solution #2 and to prevent duplicate code, put your code in a helper static class that would know how to rotate or connect a field.

5
  • I think #1 and #2 have a lot of duplicate code if I add new properties, like IMovableField and so on. #2.5 doesn't sound very object orientated to me. Mar 10, 2016 at 15:23
  • There is no behavior in interface. Then you need hierarchy. If you have so distinctive behaviors with some in common, then use interface and create specific functionalities in specific classes. If some behaviors are the same between specific classes, you could define a general behavior in only one place and call that behavior from any specific class in order to manage less duplicate. If you have better idea, tell them... Mar 10, 2016 at 18:12
  • You are missing an important information: shared behaviors (for example rotate) is the same code for any kind of field of each field has its own specific behavior? Mar 10, 2016 at 18:17
  • There is one thing that I learn from your question... Open question seems to always let place to interpretation and are very difficult to answers. Mainly to understand the real intention of the author... The real goal... Mar 10, 2016 at 18:19
  • I should have clarified that I want to reuse behavior for several subclasses. So the rotate behavior would be the same for all rotatable fields and the connect behavior would be the same for all connectable fields. I will ask on SO next time. Mar 11, 2016 at 7:39

Not the answer you're looking for? Browse other questions tagged or ask your own question.