0

We have a tree of objects of different types derive from a common tree node and We want to write a method to render complete tree. We are using different renderer based on UI selected Eg.. text Renderer, 2d renderer, 3d renderer. Our tree is our model and we don't want to put in rendering code inside it. so, we decided to create separate rendering code. Our renderer have a method RenderNode(TreeNode node) that takes reference of base class TreeNode. Since, we need to work with various different kind of node, we are type checking for each tree node type and rendering it.

void RenderNode(TreeNode node) { 
    if(node is NoEditNode){
        // call Derive class RenderEditNode
        RenderEditNode(node);
    }
    else if (node is PersonNode){
        // call Derive class RenderPersonNode
        RenderPersonNode(node);
    }
    else if (node is AssetNode){
        // call Derive class RenderAssetNode
        RenderAssetNode(node);
    }
    .
    .
    .
}

Even though this is done in base class and derived Renderer will just implement specific rendering code, this is not a good OO design. In case I add a new Tree node I'll need to change all renderer and to avoid this situation we need to add render code to tree node itself which will again need to be sync when a new renderer is introduced. So we have multiple kind of tree node and multiple kind of renderer. How can we design this to avoid type checking and avoid change one class if a new kind of another class.

2 Answers2

0

You can solve this if you're willing to create multiple rendering methods with the same name but different type parameters:

public void RenderNode(TreeNode node) { 
    RenderNodeInternal(node as dynamic);
}

private void RenderNodeInternal(AssetNode node) {
    .
    .
    .
}

private void RenderNodeInternal(NoEditNode node) {
    .
    .
    .
}

private void RenderNodeInternal(PersonNode node) {
    .
    .
    .
}

This leverages the dynamic mechanism to pick the correct overload based on the runtime type of node in RenderNode.

(Overall, this is doing something very similar to the original code - except you don't have to write all of the type checking code yourself)

Damien_The_Unbeliever
  • 234,701
  • 27
  • 340
  • 448
  • learned about dynamic keyword but, sorry I was looking for some pattern. –  Jun 09 '17 at 07:52
0

Take a look at the visitor pattern. The visitor design pattern is a way of separating an algorithm from an object structure on which it operates.

Bacisly you create a seperate class for each implentetion of a render alogritm and inject that class into the TreeNode derived classes.

Here is an example of an implementation:

public interface IRenderer
{
    void Render(TreeNode node);
}

class NoEditNode : TreeNode
{
    IRenderer renderer = new RenderEditNode();
    public void Render()
    {
        renderer.Render(this);
    }
}

class RenderEditNode :  IRenderer
{
    public void Render(TreeNode node)
    {
    /*  
    ...
    */
    }
}


class PersonNode : TreeNode
{
    IRenderer renderer;

    public PersonNode(IRenderer renderer)
    {
        this.renderer = renderer;
    }

    public void Render()
    {
        renderer.Render(this);
    }
}

class RenderPersonNode :  IRenderer
{
    public void Render(TreeNode node)
    {
        /*  
        ...
        */
    }
}
  • I was trying to create Renderer as a visitor only. Your example look more like Strategy pattern. BTW how can I handle multiple renderer when my node can store only one renderer reference? –  Jun 09 '17 at 07:50
  • It is like I have multiple windows where I want to represent my model in a different view. –  Jun 09 '17 at 07:56
  • The strategy and visitor pattern are very simular see [link](https://stackoverflow.com/questions/8665295/what-is-the-difference-between-strategy-pattern-and-visitor-pattern). When the model must surve multiple windows you have to add one awarenis of the view type. The chain of responsebilty pattern could help. – Piet Vredeveld Jun 09 '17 at 21:09