Click here to Skip to main content
15,891,253 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
I'm designing a project management system, and the WBS structure is one of the core functions.

I define Node as a abstract class, TreeNode class and SensitiveNode class as a subclass of Node. TreeNode reprensets a node of a tree structure, SensitiveNode reprensets a node which can do validate and log when client access it. What if I want a SensitiveTreeNode which share the behavior of both TreeNode and SensitiveNode? How can I design the class SensitiveTreeNode.

Because TreeNode and SensitiveNode is kind of complex, I don't want rewrite code in SensitiveTreeNode, because it would cause maintain disaster.

I think multi inheritation is very common in real world, what do people deal with those kind of scenarious normally.
Posted

If both operations are complex and can't be arranged into a single inheritance hierarchy, you should compose, not inherit. Take out the main features of each part into a provider class, so
class SensitiveTreeNode : SensitiveNode, TreeNode {
 public void SomeSensitiveMethod(string arg) { ... }
 public TreeNode Parent { get; set; }
}


... becomes:
class SensitiveTreeNode : Node, ISensitiveNode, ITreeNode {
 public TreeNodeProvider TreeProvider {get; private set; }
 public SensitivityProvider SensitivityProvider { get; private set; }

 SensitiveTreeNode() {
  TreeProvider = GetTreeNodeProvider();
  SensitivityProvider = GetSensitivityProvider();
 }

 virtual TreeNodeProvider GetTreeNodeProvider() { return new TreeNodeProvider(this); }
 virtual SensitivityProvider GetSensitivityProvider() { return new SensitivityProvider(this); }
}

class TreeNodeProvider {
 ITreeNode host;
 
 public ITreeNode Parent { get; set; }
 
 public TreeNodeProvider(ITreeNode host) { this.host = host; }
}

class SensitivityProvider {
 ISensitiveNode host;
 
 public void SomeSensitiveMethod(string arg) { ... }

 public SensitivityTreeNodeProvider(ISensitiveNode host) { this.host = host; }
}

interface ISensitiveNode {
 SensitivityProvider SensitivityProvider { get; }
}

interface ITreeNode {
 TreeNodeProvider TreeProvider { get; }
}


The providers are by their nature fairly general, as they will provide functionality for any tree or sensitive node. If you want a special implementation for a particular node class, you can create a nested class which inherits from the appropriate base provider class, and assign that to the provider property.

This means that all calls to tree node or sensitive node methods and properties get an extra bit of text in them:
myTreeNode.TreeProvider.Parent = myOtherTreeNode;
... and it's quite a bit of work, so it's not perfect. It is the closest thing that can reasonably be done in C# (or Java or other single-inheritance languages) to inheriting two things, though – SensitiveTreeNode now really does provide two sets of functionality, and it is all inheritable, polymorphic etc (through overriding provider classes and GetXxxProvider methods).

The length of this reply emphasises how, if it is at all reasonable, you should try to make at least your main inheritance hierarchy be arranged so that you don't need multiple inheritance. In the case of your example, nodes are usually expected to be bound to a particular data structure; I would expect that you could make TreeNode be a base class and have sensitivity inherit from it. (Nodes not currently in a tree can simply have a null tree/parent.) But obviously we don't have the details of your problem and that may not be appropriate.
 
Share this answer
 
Comments
Sergey Alexandrovich Kryukov 17-Jun-11 15:16pm    
Right. My 5. Working around lack of multiple inheritance is not trivial.
--SA
Thinking Stone1 19-Jun-11 22:54pm    
Thanks Bob, you've predicted lots of my problems and gave a great solution. Actrually, I used a similar solution as you have gaven, after readed your suggestion, I changed my design to be more flexible. Because TreeNode is much more complex than SensitiveNode, so I created a SensitiveProvider and left TreeNode to be base class. It works good and did not take much of time. The only problem is I'm not sure if this could cause confusion, because It used both inheritance and provider pattern.
In these situations you can follow Interface based design.

TreeNode inherits Node
SensitiveNode inherits Node

Define ITreeNode as the interface for TreeNode and ISensitiveNode as interface for SensitiveNode.

Then, You can define the new class SensitiveTreeNode to derieve rom Node and implement ITreeNode and ISensitiveNode.

I would leave the implementation details of SensitiveTreeNode to you.
One of the option is to use composition of TreeNode and SensitiveNode in SensitiveTreeNode or a clean implementation, which should be driven by your requirement.
 
Share this answer
 
v2
Comments
Sergey Alexandrovich Kryukov 17-Jun-11 15:14pm    
That is correct, but not so trivial. My 5.
--SA
I can feel your pain: like in Java (and opposite to C++), you cannot have multiple inheritance in C# (and many many folks here think it's C# a feature, not a limitation...).
The common escape is probably inheriting from the more complex class and implementing the less complex (that should become an interface).
 
Share this answer
 
Comments
arathi_suresh 17-Jun-11 7:56am    
yes..you should be using interfaces in such cases
Sergey Alexandrovich Kryukov 17-Jun-11 15:19pm    
Of course. What we have in Java and .NET is called "weak form of multiple inheritance". The advice is good, my 5, but it should be combined with using interfaces; and approach demonstrated by Bob (I think you mean something like that). Using multiple inheritance even when it is fully available is not trivial as well. May be that's why it is not used in Java, .NET and other frameworks.

The issue is the whole OOP approach, its inherent problem.
--SA

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900