views:

127

answers:

4

Suppose I developed a wrestling game where all wrestlers fight with each-other.

So I designed the classes and interfaces like the following:

public interface IWrestler
{
    void Attack();
}

public class Sumo : IWrestler
{
    public Sumo()
    {
    }

    public void Attack()
    {
        Console.Write("Sumo attacked the opponent...");
    }
}

public class Shaolin : IWrestler
{
     //------ etc.
}

This year I want the wrestlers to carry weapons (which was not thought earlier).

Suppose I have already created a large number of classes.

What design pattern can be used now to solve this problem? Or, How should I solve this problem now?

What design pattern could be used initially to avoid this problem?

A: 

What design pattern could be used initially to avoid this problem?

Have a look at Visitor. It allows you to add new operations to existing object structures without modifying those structures

Ralph
+2  A: 

What design pattern can be used now to solve this problem? Or, How should I solve this problem now?

For the already designed classes there's no design pattern that can be magically applied in a static language except AOP that can help you solving this problem. You will have to add another interface IWeapon and a reference to a list of weapons to every wrestler.

What design pattern could be used initially to avoid this problem?

Don't bother yourself this way. You had done a good job designing your classes. It's important to recognize a pattern of change and to support it in your desing. Otherwise it would be just a waste of time to think of all possible cases.

Boris Pavlović
+3  A: 

I would not dive too deeply into design patterns for this issue, I believe. On the design problem at hand, I would spontaneously say that a wrestler that is carrying a weapon is not a wrestler, but a warrior, which should be represented by a new interface. For backwards compatibility, we can require all warriors to also be wrestlers:

public interface IWrestler
{
    void Attack();
}    
public interface IWarrior : IWrestler
{
    void WeaponedAttack();
}
// let's assume that Sumo's don't carry weapons
public class Sumo : IWrestler
{
    public void Attack()
    {
        Console.Write("Sumo attacked the opponent...");
    }
}
//..but Shaolin do:
public class Shaolin : IWarrior
{
    public void Attack()
    {
        Console.Write("Shaolin attacked the opponent as a wrestler...");
    }

    public void WeaponedAttack()
    {
        Console.Write("Shaolin attacked the opponent as a warrior...");
    }
}

Regarding the comment with if Sumo is armed with a stick: I guess that Sumo with a stick may also be considered a warrior; so have it implement IWarrior instead, and attack with the stick using WeaponedAttack. Unless the stick is exclusively for defense (but that does not seem to be part of the interfaces yet; I can't see how the attacker will "see" the opponent or vice versa).

Perhaps you should have the interfaces on another scale: IAttacker and IDefender, where you have IAttacker.Attack(IDefender) and IDefender.BeingAttacked(IAttacker) and have each class implement both? That way there can problably be some sort of scoring mechanism deciding who wins the battle. (just tossing ideas..)

Fredrik Mörk
How can I arm a sumo with a stick (suppose)?
@JMSA: I misread your question and remove the answer... see updated answer instead.
Fredrik Mörk
Could I incorporate any abstract class with this?
A: 

The question I'd ask is whether or not you really want a Sumo class to begin with, or an IWrestler interface.

It seems like a IWrestler will have to be responsible for a ton of things - resolving attacks, determining some internal statistics, etc. This kind of violates the Single Responsibility Principle.

I'd also bet that by the time you're done, IWrestler will have a large number of methods, some of which will have almost nothing to do with each other. That's another sign that you're drifting into the Big Ball of Mud anti-pattern.

The fact that attacking and defending will probably be interrelated suggests that there may be another class (or more!) hiding there with the responsibility of arbitrating between the two.

As a final suggestion, it may be worthwhile to consider this not from a data-structure-based standpoint, but from the point of interaction with the user. Modeling the flow of data from the user input to the eventual result may suggest some possible designs that aren't apparent at first glance. It's when looking at things from this view that a lot of the classic design patterns really start to shine.

kyoryu