I\'ve run into a bit of a problem with my class hierarchy, in a WPF application. It\'s one of those issues where you have two inheritance trees merging together, and you can
One approach is to use extension methods with an interface to provide your "derived class" implementation, much like System.Linq.Queryable:
interface ICustomizableObject
{
string SomeProperty { get; }
}
public static class CustomizableObject
{
public static string GetXamlHeader(this ICustomizableObject obj)
{
return DoSomethingWith(obj.SomeProperty);
}
// etc
}
public class CustomizableControl : System.Windows.Controls.UserControl, ICustomizableObject
{
public string SomeProperty { get { return "Whatever"; } }
}
Usage: As long as you have a using directive for (or are in the same namespace as) the namespace where your extension methods are defined:
var cc = new CustomizableControl();
var header = cc.GetXamlHeader();
I use mixins in such a case. mixins are a powerful concept used in many languages to add functionality to a class at runtime. mixins are well known in many languages. The re-mix framework is a framework that brings the mixin technology to .NET.
The idea is simple: Decorate your class with a class attribute that represents a mixin. At runtime this functionality will be added to your class. So you can emulate multiple inheritance.
The solution to your problem could be to make CustomizableObject to a mixin. You will need the re-mix framework for this.
[Uses(CustomizableObjectMixin)] CustomizableControl : UserControl
Please check out remix.codeplex.com for more details.
I'm looking at this, and CustomizableObject
is just screaming to be made into an interface (and since every concrete type is convertable to object, that part of the name is redundant). The problem you're running into is that you're not sure how to preserve some basic logic that will be shared or only vary slightly by implementation, and you want to store this logic in the tree itself so that it will work polymorphically (is that a word?).
You can achieve this through delegates. I'm not sure exactly which members are giving you trouble, but perhaps something more like this:
____________________________________ _____________________________________
| ICustomizable | | System.Windows.Controls.UserControl |
| | |_____________________________________|
| Func<string> XAMLHeader; | ▲
| Func<string> XAMLFooter |◄--┐ |
| ICustomizabl LoadObject() | \ |
| <Possible other implementations> | \ |
|____________________________________| \ |
▲ ▲ \ |
| | \ |
| | \ |
_________________ ______________________ \ _____________________
| SpriteAnimation | | SpriteAnimationFrame | └---| CustomizableControl |
|_________________| |______________________| |_____________________|
▲ ▲
| |
| |
________ _____________
| Sprite | | SpriteFrame |
|________| |_____________|
Additionally, you likely have some logic that is genuinely static that you feel really belongs with your CustomizableObject type. But this is probably false: you built the type with the intent of using that type in a specific situation. For example, from the context it looks like you'll create these controls and animations and use them on a Windows Form. The thing to do is have your own form that inherits from the base System.Windows.Form, and this new form type should know about ICustomizableObject and how to use it. That's where your static logic will go.
This seems a little awkward, but it's proven accurate when you decide to change presentation engines. What happens if you port this code to WPF or Silverlight? They'll likely need to use your implementation code a little differently than Windows Forms would, and you'll still likely need to change your CustomizableControl implementations. But your static logic is now all in exactly the right place.
Finally, the LoadObject() method you're using stands out to me as in the wrong place as well. You're saying you that you want every Customizable type to provide a method you can call that knows how to load/construct itself. But this is really something different. You might want yet another interface named IConstructable<T>
and have your ICustomizable type implement that (IConstructable<ICustomizable>
).
You have two options here; use interfaces, or use composition. Honestly, interfaces are very powerful, and after reading this line
The interface solution doesn't make any sense to me. (Interfaces have never really made much sense to me, to be honest...)
I think that you should learn how to use them properly. That said, if there is simply some logic that multiple class need, but it does not make sense for these classes to inherit from the same base class, just create a class to encapsulate that logic and add a member variable of that class to your classes that are giving you problems. This way all of the classes contain the logic but can be separate in their inheritance hierarchies. If the classes should implement a common interface(s), then use interfaces.
Looks like you'll have to resort to interfaces and object composition.
I think is a one of solution.
public interface IClassA
{
void Foo1();
void Foo2();
}
public interface IClassB
{
void Foo3();
void Foo4();
}
public class ClassA :IClassA
{
#region IClassA Members
public void Foo1()
{
}
public void Foo2()
{
}
#endregion
}
public class ClassB :IClassB
{
#region IClassB Members
public void Foo3()
{
}
public void Foo4()
{
}
#endregion
}
public class MultipleInheritance :IClassA, IClassB
{
private IClassA _classA;
private IClassB _classB;
public MultipleInheritance(IClassA classA, IClassB classB)
{
_classA = classA;
_classB = classB;
}
public void Foo1()
{
_classA.Foo1();
}
public void Foo2()
{
_classA.Foo2();
AddedBehavior1();
}
public void Foo3()
{
_classB.Foo3();
AddedBehavior2();
}
public void Foo4()
{
_classB.Foo4();
}
private void AddedBehavior1()
{
}
private void AddedBehavior2()
{
}
}
Class MultipleInheritance add new behavior to two different object without affecting the behavior of this objects. MultipleInheritance have the same behaviors as delivered objects (Inherits both behaviors).