2010-08-10 12 views
16

Oto co mam do tej pory:Jak używać wzorca strategii za pomocą 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!"); 
     } 
    } 
} 

Teraz jeśli mam superklasę Character.cs. w jaki sposób ta superklasa może zaimplementować broń, dzięki czemu zajęcia dla dzieci mogą być bardziej szczegółowe.

namespace Strategy 
{ 
    class Character 
    { 
     public IWeaponBehavior weapon; 

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

namespace Strategy 
{ 
    class Thief : Character 
    { 

    } 
} 

Jak mogę to wdrożyć? Jestem bardzo zdezorientowany tym, jaki powinien być rzeczywisty kod.

Wiem, że to może wymagać zbyt wiele, ale jeśli mógłbyś napisać właściwy kod, abym mógł go studiować, byłoby to bardzo miłe z twojej strony. Uczę się, widząc kod. : P Wiele osób mogłoby skorzystać z tego pytania.

+9

"SLASH SLASH!" zasady części :) – thelost

+1

W zależności od innych cech charakterystycznych 'Character' możesz być w stanie usunąć odziedziczone klasy i użyć fabryki, która skonfiguruje potrzebne cechy i strategie. –

Odpowiedz

26

Używaj iniekcji zależność w klasie 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 

Edytowany zgodnie z życzeniem.

+0

hmm podoba mi się twoja lepiej niż moja myślę. –

+0

chociaż hmm, intencja może być semantycznie czystsza w moim. –

+3

@Joshua - Ale zakładasz, że wszystkie Księżniczki będą używać Patelni, a jeśli masz złego Księżniczkę, która lubi używać Noża ... – SwDevMan81

5

Istnieje kilka możliwości. Naprawdę pytasz: "w jaki sposób konkretna postać powinna wiedzieć, której broni użyć?".

Możesz mieć fabrykę postaci, która stworzy i wstrzyknie odpowiedni rodzaj broni do postaci (To brzmi nie tak :)) lub niech konstruktor określonej postaci zajmie się tworzeniem broni.

+1

OK, ale byłaby bardziej elastyczna, gdyby broń postaci mogła zostać zmieniona w dowolnym momencie. Być może złodziej, który straci nóż, może podnieść patelnię i improwizować. Innymi słowy, bez względu na to, jak go zainicjujesz, nie ma powodu, aby go uniezależnić. –

+0

@Steven: zakładasz, że ten poziom elastyczności jest potrzebny: nie ma żadnej konkretnej potrzeby, aby to zmienić. Powinieneś zrobić najprostszą rzecz, która spełnia rzeczywiste wymagania (czymkolwiek by one nie były!). –

+0

@Dan: Z tego, co rozumiem w dziedzinie problemu, ta elastyczność jest raczej dobrym pomysłem. Ostatecznie to wybór Sergio; moim zadaniem jest to zaoferować. –

3
class Character 
    { 
    private IWeaponBehavior _weapon; 

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

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

Twój konstruktor musi mieć postać 'Character', a nie' Context'. –

+0

Zaktualizowane podziękowania. – SwDevMan81

+0

Uwaga boczna: jeśli używasz wiodącego podkreślnika do disambiguacji pól od lokalnych, "to". jest całkowicie zbędny. –

1
 
public class Character 
{ 
    IWeaponBehavior Weapon; 
} 

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

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

powinieneś oznaczyć swój kod jako "pseudo-kod"! –

0

Jeśli wszystkie postacie mają swój specyficzny broń, nie faktycznie trzeba użyć wzoru strategii. Możesz użyć zwykłego polimorfizmu. Ale strategia może i tak być czystsza.

Wystarczy intitialize broń:

public class Character 
{ 
    IWeapenBehavior weapon; 

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


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

W kodzie, który kontroluje swoje postacie, można wywołać metodę Attack().

1

Zobacz iniekcję zależności &, a następnie zajrzyj do Inversion of Control.

TekPub ma świetny darmowy odcinek na temat tych dwóch pomysłów, używając próbki bardzo podobnej do twojej. To powinno ci pomóc z konkretną próbką. :-)

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

Kod próbki z filmu:

class Samurai { 
    IWeapon _weapon; 

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

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

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

Powyższe di (z konstruktora IWeapon). Teraz dodając Inversion of Control zyskujesz jeszcze większą kontrolę.

Za pomocą kontenera IOC możesz kontrolować IWeapon przez wstrzyknięcie zamiast w samej klasie.

Wideo używa NInject jako IOC i pokazuje, w jaki sposób można wyeliminować Konstruktor IWeapon i uzyskać kontrolę nad klasą i wszystkimi klasami wymagającymi użycia IWeapon do użycia tego, czego potrzebujesz w jednym miejscu/obszarze konfiguracji.

Próbka z filmu:

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

Powyższa konfiguracja mówi NInject że gdy napotka IWarrior używać Samurai i ilekroć encourters IWeapon użyć Sword.

Film wideo wyjaśnia, w jaki sposób ta niewielka zmiana zwiększa elastyczność. Dodaje kolejny moduł dla Samurii, który używa broni dystansowej, itp.

Możesz zmienić te w razie potrzeby/chciał.

Powiązane problemy