2010-08-10 19 views
16

Voici ce que j'ai jusqu'à présent:Comment utiliser le modèle de stratégie avec C#?

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!"); 
     } 
    } 
} 

Maintenant, si j'ai une superclasse Character.cs. Comment cette super-classe peut-elle implémenter un comportement d'arme afin que les classes enfants puissent être plus spécifiques?

namespace Strategy 
{ 
    class Character 
    { 
     public IWeaponBehavior weapon; 

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

namespace Strategy 
{ 
    class Thief : Character 
    { 

    } 
} 

Comment puis-je implémenter cela? Je suis très confus sur ce que le code doit être.

Je sais que cela pourrait être trop demander, mais si vous pouviez écrire le code réel afin que je puisse l'étudier, ce serait très gentil de votre part. J'apprends en voyant du code. : P Beaucoup de gens pourraient bénéficier de cette question.

+9

Le "SLASH SLASH!" règles de partie :) – thelost

+1

En fonction de l'autre caractéristique de 'Character' vous pouvez supprimer les classes héritées et utiliser une fabrique qui mettrait en place les traits de caractère et les stratégies nécessaires. –

Répondre

26

Utiliser l'injection de dépendance en classe 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 

Édité selon les besoins.

+0

hmm j'aime le tien meilleur que le mien je pense. –

+0

bien que hmm, l'intention peut être sémantiquement plus claire dans le mien. –

+3

@Joshua - Mais vous supposez que toutes les princesses vont utiliser un Pan, et si vous avez une princesse maléfique qui aime utiliser un couteau ... – SwDevMan81

5

Il y a quelques possibilités. Ce que vous demandez vraiment, c'est "comment un personnage spécifique devrait-il savoir quelle arme utiliser?". Vous pouvez avoir une fabrique de personnage qui créerait et injecterait le bon type d'arme dans le personnage (qui sonnait mal :)), ou laisser le constructeur d'un personnage spécifique s'occuper de créer l'arme.

+1

Ok, mais ce serait plus flexible si l'arme d'un personnage pouvait être changée à tout moment. Peut-être que le voleur qui perd son couteau peut ramasser une poêle et improviser. En d'autres termes, peu importe comment vous l'initialisez, il n'y a aucune raison de le rendre immuable. –

+0

@Steven: vous supposez que ce niveau de flexibilité est nécessaire: il n'est pas nécessaire de le rendre mutable non plus. Vous devriez faire la chose la plus simple qui satisfasse les exigences réelles (quelles qu'elles soient!). –

+0

@Dan: D'après ce que je comprends du domaine du problème, cette flexibilité est très probablement une bonne idée. En fin de compte, c'est le choix de Sergio; mon travail est de l'offrir. –

3
class Character 
    { 
    private IWeaponBehavior _weapon; 

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

    public void WeaponInterface() 
    { 
     _weapon.UseWeapon(); 
    } 
    } 
+2

Votre constructeur doit être 'Character' et non' Context'. –

+0

Mis à jour merci. – SwDevMan81

+0

Note secondaire: Si vous utilisez un trait de soulignement principal pour désambiguïser les champs des locaux, le "ceci". est entièrement redondant. –

1
 
public class Character 
{ 
    IWeaponBehavior Weapon; 
} 

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

public class Thief : Character 
{ 
    Weapon = new Knife(); 
} 
+5

vous devriez marquer votre code explicitement comme «pseudo-code»! –

0

Si vos personnages ont tous leur propre arme spécifique, vous n'avez pas réellement besoin d'utiliser le modèle de stratégie. Vous pourriez utiliser le polymorphisme simple. Mais le schéma de stratégie pourrait être plus propre de toute façon.

Vous avez juste besoin Initialisez l'arme:

public class Character 
{ 
    IWeapenBehavior weapon; 

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


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

Dans le code qui contrôle vos personnages, vous pouvez appeler la méthode Attack().

1

Jetez un coup d'œil à l'injection de dépendances & puis regardez également dans Inversion de contrôle.

TekPub a un super épisode gratuit sur ces deux idées en utilisant un échantillon très similaire au vôtre. Cela devrait vous aider avec un échantillon concret. :-)

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

Exemple de code de la vidéo:

class Samurai { 
    IWeapon _weapon; 

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

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

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

Ce qui précède est DI (avec constructeur IWeapon). Maintenant, en ajoutant Inversion of Control, vous gagnez encore plus de contrôle. En utilisant un conteneur IOC, vous serez en mesure de contrôler l'Iweapon par injection plutôt que dans la classe elle-même.La vidéo utilise NInject comme IOC et montre comment vous pouvez éliminer le constructeur IWeapon et prendre le contrôle de la classe et de toutes les classes ayant besoin d'utiliser IWeapon pour utiliser ce que vous voulez dans un emplacement/zone de configuration.

Echantillon de la vidéo:

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

La configuration ci-dessus indique que Ninject chaque fois qu'il rencontre un iWarrior à utiliser Samouraï et chaque fois qu'il encourters un IWeapon d'utiliser l'épée.

La vidéo continue pour expliquer comment ce petit changement augmente votre flexibilité. Il ajoute un autre module pour une samourie qui utilise une arme à distance, etc ....

Vous pouvez les modifier au besoin.