Inheritance newbie...

Published 05 December 03 03:41 PM | MikeD

I am an inheritance newbie.

Right now I have a method that accepts a “Node” parameter, which represents the root node of a tree structure.

The Node class has been inherited by several other classes, AndNode, OrNode, OperatorNode, TermNode, and so on.

The following doesn't work. I'm now looking for the “right“ way of doing this:

public string Process(Node node)
{
    string buf;
    switch (node.GetType())
    {
        case AndNode:
            AndNode andNode = (AndNode)node;
            buf = String.Concat(Process(andNode.left), “ and “, Process(andNode.right));
            break;
        case OrNode:
            OrNode orNode = (orNode)node;
            buf = String.Concat(Process(orNode.left), “ or “, Process(orNode.right));
            break;
        case TermNode:
            TermNode termNode = (TermNode)node;
            buf = termNode.term;
            break;

     .....
     }
     return buf;
}

Mike

Filed under:

Comments

# Johnny Hall said on December 5, 2003 04:47 PM:

AndNode andNode = node as AndNode;
if (andNode != null) {
...
return buf;
}

OrNode orNode = node as OrNode;
if (orNode != null) {
...
return buf;
}

I think. Haven't coded it up.

# Steve said on December 5, 2003 04:52 PM:

You could also do a string compare on the type.

switch(node.GetType().FullName)
{
case "Namespace.AndNode":
...
}

You may also want to think about redesigning your classes. In your current design you'll need to recode that method every time you add a new node which generally isn't a good sign.

# Steve said on December 5, 2003 04:54 PM:

When you add a new node *type* is what I should have said above.

# Johnny Hall said on December 5, 2003 04:54 PM:

I agree, best to implement Process inside each subclass.

# Andrew said on December 5, 2003 05:02 PM:

At simplest level, you could put a "Process" string property in a node.
That prop/method could return your node.left + node.OperatorText + node.right.

The instead of calling Process(node) to get a string, you would just call node.Process

Avoid names like process when you can, they are not clear ;)

# Mike said on December 5, 2003 05:10 PM:

Thanks for the quick feedback folks.

I will consider redesigning this - the Process is supposed to take a query tree and make a big SQL string out of it, based on a bunch of knowledge about column and table names has. I don't know if I want to embed that knowledge into the nodes of the tree or not.

Oh, and the actual method name isn't really Process. I'm removing details that aren't necessary or may be considered proprietary.

# CausticMango said on December 5, 2003 05:21 PM:

Any reason why you don't use the polymorphic behavior of objects and do this:

public string Process(AndNode node)
{
return String.Concat(Process(node.left), “ and “, Process(node.right));
}

public string Process(OrNode node)
{
return String.Concat(Process(node.left), “ or “, Process(node.right));
}

public string Process(TermNode node)
{
return termNode.term;
}

# CausticMango said on December 5, 2003 05:26 PM:

Based on your later description of the problem, maybe you should consider using employing the Interpreter design pattern (GoF) to represent your syntax tree as a set of composite functor classes.

Interpreter
http://www.dofactory.com/Patterns/PatternInterpreter.aspx

Functor
http://www.eli.sdsu.edu/courses/spring98/cs635/notes/command/command.html

# CausticMango said on December 5, 2003 05:33 PM:

One more thing, remember the Single Responsibility Principle (SRP) -- I see you got some advice to place the process behavior in the classes themselves. This may be a good thing, be revisit the intent of those classes first.

A class should only be defined with a single set of consistent responsibilities. If you find moving this behavior causes your Node classes to have behavior that violates there original intent, you are violating the SRP.

http://www.objectmentor.com/mentoring/OOPrinciples

# Scott Mitchell said on December 6, 2003 01:28 AM:

As many others have said, you probably want to move Process into each class. As a more plain-English way of saying what CausticMango said formally, andtime you find yourself with switch statements to determine what type of object you have, best to move that functionality into each individual class...

hth