3

So I'm working on a GUI library and I have 3 classes: UIElement, the base for every UI object, UIContainer, which implements the possibility to hold other child-elements and UIRect which implements position and size for elements. Now I would like to create a class that uses both UIRect and UIContainer. Obviously this is impossible this way, but is there any elegant solution for this problem?

pixartist
  • 1,137
  • 2
  • 18
  • 40

4 Answers4

4

Here is one possibility: inherit from one of the classes (say, UIRect), and embed the other (say, UIContainer). Implement the interface of IUIContainer bu forwarding all calls to the embedded object.

class UIRect {
    ...
}
interface IUIContainer {
    IEnumerable<IUIElement> AllElements {get;}
    void AddElement(IUIElement toAdd);
}
class UIContainer : IUIContainer {
    public IEnumerable<IUIElement> AllElements {
        get {
            ...
        }
    }
    public void AddElement(IUIElement toAdd) {
        ...
    }
}
class Multiple : UIRect, IUIContainer {
    private readonly IUIContainer _cont = new UIContainer();
    ...
    public IEnumerable<IUIElement> AllElements {
        get {
            return _cont.AllElements;
        }
    }
    public void AddElement(IUIElement toAdd) {
        _cont.AddElement(toAdd);
    }
}

Another possibility is to use two interfaces, and share implementation through extension methods.

Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
3

You can create a hybrid class that accepts the instances of the UIElement, UIContainer, UIRect as properties and then have your child class implement the hybrid and take it from there.

 class HybridDerived : Hybrid
 {
 }

 class Hybrid
 {
     public UIElement Element { get; set; }
     public UIContainer Container { get; set; }
     public UIRect Rect { get; set; }
 }

 class UIElement
 {
 }

 class UIContainer
 {
 }

 class UIRect 
 {
 }
Azhar Khorasany
  • 2,712
  • 16
  • 20
2

C# generally favors composition over inheritance and using interfaces to communicate.

Example:

public interface IUIElement
{
}

public interface IUIContainer
{
    ICollection<IUIElement> Children;
}

public interface IUIRect
{
    IPosition Position { get; }
    ISize Size { get; }
}

public abstract class UIElement : IUIElement
{
}

public class Multiple : UIElement, IUIContainer, IUIRect
{
    private readonly ISize _size;
    private readonly IPosition _position;
    private readonly List<UIElement> _children = new List<UIElement>();

    public Multiple()
    {
    }

    public IPosition Position { get { return _position; } }
    public ISize Size { get { return _size; }; }

    public ICollection<IUIElement> Children { get { return _children; } }
}
John Willemse
  • 6,608
  • 7
  • 31
  • 45
Dustin Kingen
  • 20,677
  • 7
  • 52
  • 92
1

The generic answer of "use an interface and composition" seems like an overkill. There is probably no need to use an interface - you are not likely to have a role that can be be played sometimes by an UIRect and sometimes by an UIElement that is not an UIRect. Just add a property rect of type UIRect to your UIContainer.

UPDATE

(after comments) The crux of my answer lies in an advice NOT to follow the pattern of making an interface and delegating calls to a private instance of UIRect object.

UIRect, judging from the name, has all kinds of data and logic that deal with geometry of a rectangular space on screen. This means that:

  • you will probably not have multiple implementations. An euclidean one will suffice;
  • you will likely find that there are many rectangles describing an UIContainer: perhaps a the bounding box, size before and after transformation, insets, etc.

This is just my judgement and I do not have a lot of data. But from what I see, you need a plain composition, not an additional interface describing properties of a rectangle.

fdreger
  • 12,264
  • 1
  • 36
  • 42
  • @NickFreeman: This is what I call "not using interfaces". If you have problems understanding my answer, don't hesitate to ask. – fdreger May 24 '13 at 14:25
  • @NickFreeman: The question was specifically about "an elegant solution to the problem", not "what generally should I look up into when considering multiple inheritance". The crux of my answer lies in an advice NOT to follow the pattern of making an interface and delegating calls to a private instance of UIRect object. I will try to make a small edit to accomodate that. – fdreger May 24 '13 at 14:33
  • @NickFreeman: I have tried to clarify, thank you for your help. – fdreger May 24 '13 at 14:40
  • I think the main idea here is that the answer "Composition over inheritance" in itself has nothing to do with interfaces AND adding more interfaces than are needed is overengineering and makes code less maintainable. Both are very true. – Nick Freeman May 24 '13 at 14:43
  • @NickFreeman I was not making a philosophical statement or trying to discover any deeper truths of programming. Or even share a good practice. I was just trying to give a sound advice to a specific problem. Some time ago I was interested in gui toolkits and scene graphs, and most of them had some idea of a "rectangle". AFAIK, all used a single implementation and not a one required inheriting or implementing anything in context of a rectangle. That is all. – fdreger May 24 '13 at 14:53