Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Best way to switch behavior based on type [duplicate]

Possible Duplicate:
C# - Is there a better alternative than this to ‘switch on type’?

Consider the classic:

class Widget { }
class RedWidget : Widget { }
class BlueWidget : Widget { }

For the most part, in my UI, I can treat all Widgets the same. However, there are minor differences, which I need to if or switch through.

Possible approaches:

Enum Indicator - set by constructor

enum WidgetVariety { Red, Blue }

class Widget {
    public WidgetVariety Variety { get; protected set; }
}

class RedWidget : Widget {
    public RedWidget() {
        Variety = Red;
    }
}

// Likewise for BlueWidget...

switch (mywidget.Variety) {
case WidgetVariety.Red:
    // Red specific GUI stuff

case WidgetVariety.Blue:
    // Blue specific GUI stuff
}

Use is

Widget w = ...;
if (w is RedWidget) {
    (RedWidget)w ...
}
else if (w is BlueWidget) {
    (BlueWidget)w ...
}

The reason I've resorted to this is 1) Most of the code is already somewhat written this way, but much uglier. 2) 90% of the code is identical - basically just one column in a GridView needs to be handled differently depending on the type.

Which would you recommend? (Or anyone have a better solution?)


Edit I know I'll probably be recommended to the Visitor Pattern, but that simply seems to complicated for sparse, minor differences in this case.

Edit 2 So one particular difference I was having a hard time sorting out is this column that is different between the two types. In one case, it retrieves a bool value, and assigns that to the grid cell. In the other case, it gets a string value.

I suppose in this case, it should be obvious that I could define:

public object virtual GetColumn4Data();

public override GetColumn4Data() { return m_boolval; }

public override GetColumn4Data() { return m_mystring; }

This felt wrong to me initially, due to the use of object. However, that is the type of the property that I am assigning to in the cell, so of course this makes sense!

Too long at the office today it seems...

like image 411
Jonathon Reinhart Avatar asked Apr 11 '12 22:04

Jonathon Reinhart


2 Answers

There's another possibility. Use virtual dispatch:

class Widget
{
    public virtual void GuiStuff() { }
} 
class RedWidget : Widget
{
    public override void GuiStuff()
    {
        //... red-specific GUI stuff
        base.GuiStuff();
    }
} 
class BlueWidget : Widget
{
    public override void GuiStuff()
    {
        //... blue-specific GUI stuff
        base.GuiStuff();
    }
} 
like image 168
phoog Avatar answered Sep 19 '22 01:09

phoog


Subtype polymorphism is the best solution, avoiding this kind of checks is one of the main reasons OO was created.

Widget might have a method DoSomething() (abstract probably) and then RedWidget and BlueWidget would override it.

Also see Martin Fowler's Replace Conditional with Polymorphism:

Seen: You have a conditional that chooses different behavior depending on the type of an object.

Refactor: Move each leg of the conditional to an overriding method in a subclass. Make the original method abstract.

like image 44
jorgehmv Avatar answered Sep 17 '22 01:09

jorgehmv