A design problem with sorting types with many different subclasses

The main problem that I encounter quite often, but have ever found a clean solution, is where you want to code the behavior for the interaction between different objects of a common base class or interface. To make this a little concrete, I will give an example:

Bob coded a strategy game that supports "cool geographic effects." They are rounded to simple limits, for example, if troops go in the water, they slow down by 25%. If they walk along the grass, they slow down by 5%, and if they walk along the sidewalk, they slow down by 0%.

Now the leadership told Bob that they needed new types of troops. There will be jeeps, boats, as well as hovercraft. In addition, they wanted the jeeps to do damage if they went into the water, and all three types of terrain were ignored by the hovercraft. Rumor has it that they can add another type of terrain with even more features than unit slowdown and damage.

The following is an example of very crude pseudo-codes:

public interface ITerrain
{
    void AffectUnit(IUnit unit);
}

public class Water : ITerrain
{
    public void AffectUnit(IUnit unit)
    {
        if (unit is HoverCraft)
        {
            // Don't affect it anyhow
        }
        if (unit is FootSoldier)
        {
            unit.SpeedMultiplier = 0.75f;
        }
        if (unit is Jeep)
        {
            unit.SpeedMultiplier = 0.70f;
            unit.Health -= 5.0f;
        }
        if (unit is Boat)
        {
            // Don't affect it anyhow
        }
        /*
         * List grows larger each day...
         */
    }
}
public class Grass : ITerrain
{
    public void AffectUnit(IUnit unit)
    {
        if (unit is HoverCraft)
        {
            // Don't affect it anyhow
        }
        if (unit is FootSoldier)
        {
            unit.SpeedMultiplier = 0.95f;
        }
        if (unit is Jeep)
        {
            unit.SpeedMultiplier = 0.85f;
        }
        if (unit is Boat)
        {
            unit.SpeedMultiplier = 0.0f;
            unit.Health = 0.0f;
            Boat boat = unit as Boat;
            boat.DamagePropeller();
            // Perhaps throw in an explosion aswell?
        }
        /*
         * List grows larger each day...
         */
    }
}

, , - . , . , , , , , . , , IUnit.

, , . , , , . , . , , . .

, , , . 100 IUnit ITerrain, .

. , ?

+3
5

.

- .

Propulsion Terrain.

Terrain Propulsion . .

.

. , . propuslion .

+1

, , , #, , .

, :

public class Base
{
    public virtual void Go() { Console.WriteLine("in Base"); }
}

public class Derived : Base
{
    public virtual void Go() { Console.WriteLine("in Derived"); }
}

:

public void Test()
{
    Base obj = new Derived();
    obj.Go();
}

" ", "obj" Base. , # Go() .

, # , " ", "this" OOP. , :

public class TestClass
{
    public void Go(Base b)
    {
        Console.WriteLine("Base arg");
    }

    public void Go(Derived d)
    {
        Console.WriteLine("Derived arg");
    }

    public void Test()
    {
        Base obj = new Derived();
        Go(obj);
    }
}

"Base arg", "this" , , . , , ( "Base obj" ), , Go (Base b) one.

, - :

public class Dispatcher
{
    public void Dispatch(IUnit unit, ITerrain terrain)
    {
        Type unitType = unit.GetType();
        Type terrainType = terrain.GetType();

        // go through the list and find the action that corresponds to the
        // most-derived IUnit and ITerrain types that are in the ancestor
        // chain for unitType and terrainType.
        Action<IUnit, ITerrain> action = /* left as exercise for reader ;) */

        action(unit, terrain);
    }

    // add functions to this
    public List<Action<IUnit, ITerrain>> Actions = new List<Action<IUnit, ITerrain>>();
}

, , , , . , Actions, , .

, , .

+1

Unit Terrain; . , - , , "" , .

, -

, switch

, , , , MSIL,

+1

:

1)
2)
3)

/ . , , .

, , , , .

, . Unit- > AffectUnit (myTerrainType), , .

+1

:

iTerrain iUnit, ,

:

  boat = new
iUnit("watercraft") field = new
iTerrain("grass")
field.effects(boat)

ok , :

:


public class hovercraft : unit {
    #You make a base class for defaults and redefine as necessary
    speed_multiplier.water = 1
}

public class boat : unit {
    speed_multiplier.land = 0
}
0

Source: https://habr.com/ru/post/1696915/


All Articles