views:

207

answers:

8

Here's what I have so far:

namespace Strategy
{
    interface IWeaponBehavior
    {
        void UseWeapon();
    }
}

namespace Strategy
{
    class Knife : IWeaponBehavior
    {
        public void UseWeapon()
        {
            Console.WriteLine("You used the knife to slash the enemy! SLASH SLASH!");
        }
    }
}

namespace Strategy
{
    class Pan : IWeaponBehavior
    {
        public void UseWeapon()
        {
            Console.WriteLine("You use the pan! 100% Adamantium power! BONG!");
        }
    }
}

Now if I have a Character.cs superclass. how can that superclass implement a weaponbehavior so that children classes can be more specific.

namespace Strategy
{
    class Character
    {
        public IWeaponBehavior weapon;

        public Character(IWeaponBehavior specificWeapon)
        {
            weapon = specificWeapon;
        }        
    }
}

namespace Strategy
{
    class Thief : Character
    {

    }
}

How can I implement this? I'm very confused on what the actual code needs to be.

I know this might be asking too much, but if you could write the actual code so I could study it, that would be very nice of you guys. I learn by seeing code. :P Many people could benefit from this question.

A: 

Here's a very focused article on using this pattern in C#: http://www.lowendahl.net/showShout.aspx?id=115

marr75
+10  A: 

Use dependency injection in class Character?

public class Character
{
    public Character(IWeaponBehavior weapon) 
    {
        this.weapon = weapon;
    }

    public void Attack()
    {
        weapon.UseWeapon();
    }

    IWeaponBehavior weapon;
}

public class Princess: Character
{
    public Princess() : base(new Pan()) { }
}

public class Thief: Character
{
    public Thief() : base(new Knife()) { }
}

...

Princess p = new Princess();
Thief t = new Thief();

p.Attack(); // pan
t.Attack(); // knife

Edited as requested.

Grozz
hmm i like yours better than mine i think.
Joshua Evensen
although hmm, the intent may be semantically clearer in mine.
Joshua Evensen
@Joshua - But you assuming all Princesses will use a Pan, what if you have an evil Princess who likes to use a Knife...
SwDevMan81
true, but i guess its kinda a stylistic choice. You could also have the default and then an overloaded constructor where you can set a different weapon specifically.
Joshua Evensen
Can you please see my edit? I understand the concept, but I don't know what the final codewould look like. Can you write it so other people could benefit?
Sergio Tapia
@SwDevMan81: Most princesses I know use a shot glass.
Jimmy Hoffa
+5  A: 

There's a few possibilities. What you're really asking is, "how should a specific character know which weapon to use?".

You could either have a Character factory that would create and inject the right type of weapon into the character (That sounded wrong :) ), or let the constructor of a specific character take care of creating the weapon.

cwap
Ok, but it would be more flexible if a character's weapon could be changed at any point. Perhaps the thief who loses their knife can pick up a frying pan and improvise. In other words, no matter how you initialize it, there's no reason to make it immutable.
Steven Sudit
@Steven: you're assuming that this level of flexibility is needed: there's no specific need to make it mutable, either. You should do the simplest thing that satisfies the actual requirements (whatever they may be!).
Dan Puzey
@Dan: From what I understand of the problem domain, this flexibility is quite likely a good idea. Ultimately, it's Sergio's choice; my job is to offer it.
Steven Sudit
I agree with Steven, but was in a bit of a hurry when writing this answer :) I think that a thief should be initialized with a pan (or more than one IWeapon), and let the Thief class, a GameManager class or a PowerUpCrate class change the weapons according to the requirements dynamically. However, I wouldn't want put this stuff into my answer, as I didn't think that was what the question was about :)
cwap
I do like the idea of initializing with multiple weapons, which can be used based on rules, such as starting with a thrown dagger, then switching to a short sword, while only using the concealed knife when all other weapons are disabled or lost. However, the frying pan is not a weapon that a thief would be equipped with at the start. Rather, it would be an environmental option that the thief can take advantage of if the situation calls for it. You can make up your own examples, but my point is that locking down the weapon list is probably not wise.
Steven Sudit
+3  A: 
  class Character
  {
    private IWeaponBehavior _weapon;

    // Constructor
    public Character(IWeaponBehavior strategy)
    {
      this._weapon = strategy;
    }

    public void WeaponInterface()
    {
      _weapon.UseWeapon();
    }
  }
SwDevMan81
Your constructor needs to be `Character` not `Context`.
Jerod Houghtelling
Updated thanks.
SwDevMan81
Side note: If you're using a leading underscore to disambiguate fields from locals, the "this." is entirely redundant.
Steven Sudit
@Steven - Just following the big guys example: http://dofactory.com/Patterns/PatternStrategy.aspx#_self1
SwDevMan81
Yes, that's how it's done in the sample. However, that's not really a great reason to do something. I've found, for example, that a number of C# experts -- including MS employees on the compiler team -- have been around long enough that they've kept their old habits, leading to non-idiomatic C#.
Steven Sudit
Yeah, its stylistic choice. Coding standards could be different, so its sometimes better to be explicit. Same thing can be said about explicitly making the member variable private. That is also redundant.
SwDevMan81
I'm not a fan of marking members private, for exactly that reason.
Steven Sudit
+1  A: 
public class Character
{
    IWeaponBehavior Weapon;
}

public class Princess : Character
{
    Weapon = new Pan();
}

public class Thief : Character
{
    Weapon = new Knife();
}
Joshua Evensen
you should flag your code explicitely as `pseudo-code`!
Andreas Niedermair
A: 

If your characters all have their own specific weapon, you don't actually need to use the strategy pattern. You could use plain polymorphism. But the strategy pattern could be cleaner anyway.

You just need to intitialize the weapon:

public class Character
{
     IWeapenBehavior weapon;

     public Attack()
     {
          weapon.UseWeapon();
     }
}


public class Thief : Character
{
      Thief()
      {
           weapon = new Knife();
      }
}

In the code that controls your Characters, you can call the Attack() method.

jdv
A: 

i would make Character an abstract class, and force some abstract overriding of a property, method... but there's still the issue with what if you have got an evil princess...

Andreas Niedermair
A: 

Take a look at dependency injection & then also look into Inversion of Control.

TekPub has a great free episode on these two ideas using a sample very similar to yours. This should help you with a concrete sample. :-)

http://tekpub.com/view/concepts/1

Sample code from video:

class Samurai {
  IWeapon _weapon;

  public Samurai() {
   _weapon = new Sword();
  }

  public Samurai(IWeapon weapon) {
   _weapon = weapon;
  }

  public void Attack(string target) {
    _weapon.Hit(target);
  }
}

The above is DI (with IWeapon constructor). Now adding Inversion of Control you gain even more control.

Using an IOC container you will be able to control the IWeapon via injection instead of in the class itself.

The video uses NInject as it's IOC and shows how you can eliminate the IWeapon Constructor and gain control over the class and all classes needing to use IWeapon to use what you want in one location/configuration area.

Sample from video:

class WarriorModule: NinjectModule {
  public override void Load() {
   Bind<IWarrior>().To<Samurai>();
   Bind<IWeapon>().To<Sword>();
}

The above configuration tells NInject that whenever it encounters an IWarrior to use Samurai and whenever it encourters an IWeapon to use Sword.

The video goes on to explain how this little change increases your flexibility. It adds another Module for a Samuria who uses a ranged weapon, etc....

You can change these as needed/wanted.

klabranche