2015-02-08 122 views
0

假设我们有一个控制名为Player1的角色的玩家。要在运行时启用切换武器,我有以下代码:嵌套策略设计模式

public interface IWeapon 
{ 
    void Fire(); 
} 

public class Player1Weapon1 : IWeapon 
{ 
    ... 
    void Fire() 
    { 
     //do actions of Weapon1 
    } 
    ... 
} 

public class Player1Weapon2 : IWeapon 
{ 
    ... 
    void Fire() 
    { 
     //do actions of Weapon2 
    } 
    ... 
} 

public class Player1 
{ 
    IWeapon weapon; 
    Player1Weapon1 w1; 
    Player1Weapon2 w2; 

    public Player1() 
    { 
     w1 = new Player1Weapon1(this); 
     w2 = new Player1Weapon2(this); 
     SetWeapon(w1); 
    } 
    void Update() 
    { 
     if(SWITCH_BTN_HELD) 
     { 
      if(weapon.equals(w1)) SetWeapon(w2); 
      if(weapon.equals(w2)) SetWeapon(w1); 
     } 
     if(FIRE_BTN_HELD) 
      weapon.Fire(); 
    } 
    void SetWeapon(w) 
    { 
     weapon = w; 
    } 
} 

完美的工作。

但是现在玩家可以选择另一个名为Player2的角色。请注意,玩家2的武器与玩家1不同。因此,我们可以添加类是这样的:

public class Player2Weapon1 : IWeapon 
{ 
    ... 
    void Fire() 
    { 
     //do actions of Weapon1 
    } 
    ... 
} 
public class Player2Weapon2 : IWeapon 
{ 
    ... 
    void Fire() 
    { 
     //do actions of Weapon2 
    } 
    ... 
} 

public class Player2 
{ 
    IWeapon weapon; 
    Player2Weapon1 w1; 
    Player2Weapon2 w2; 

    public Player2() 
    { 
     w1 = new Player2Weapon1(this); 
     w2 =new Player2Weapon2(this); 
     SetWeapon(w1); 
    } 
    void Update() 
    { 
     if(SWITCH_BTN_HELD) 
     { 
     if(weapon.equals(w1)) SetWeapon(w2); 
     if(weapon.equals(w2)) SetWeapon(w1); 
     } 
     if(FIRE_BTN_HELD) 
     weapon.Fire(); 
    } 
    void SetWeapon(w) 
    { 
     weapon=w; 
    } 
} 

这将再次工作,但它是非常紧张,如果玩家想与Player3玩,我应该addmore类项目。

我想知道如何使战略格局中像下面剥皮用:

interface IPlayer() 
{ 

} 

我不知道哪个方法将被放置在IP层?我如何创建嵌套的策略设计模式?

+3

我觉得你的球员不应该甚至有 “PlayerXWeapon”,只是IWeapons的IEnumerable。 – 2015-02-08 15:59:07

+0

是的,不要在将使用它的玩家之后命名一个项目。想象一下,如果你的游戏允许一个玩家放弃武器,而另一个玩家拿起它。这会让人困惑。武器的存在可以独立于持有它的人。 – MickyD 2015-02-08 17:03:45

+0

@MickyDuncan,是的,但是解决方案是什么? – 2015-02-08 18:19:59

回答

4

不知道如果我得到你问的问题或者你不知道如何/问什么。战略模式并不是你在这里最需要的。我试着给我两分钱。

首先,我不认为在你的球员中有具体的课程是个好主意,比如Player1Weapon。它应该只包含IWeapon s。通过这种方式,您无需专门定义玩家使用哪种武器,也无需为每种变化创建新玩家类。

请考虑以下情况。您在SomeNamespace命名空间中有这些IWeapons

public interface IWeapon 
{ 
    void Fire(); 
} 

public class Shotgun : IWeapon 
{ 
    public void Fire() 
    { 
     Console.WriteLine("Shotgun goes boom"); 
    } 
} 

public class Knife : IWeapon 
{ 
    public void Fire() 
    { 
     Console.WriteLine("Stabbed teh sucker"); 
    } 
} 

public class NuclearBomb : IWeapon 
{ 
    public void Fire() 
    { 
     Console.WriteLine("Game over for everyone!!1"); 
    } 
} 

现在您的Player类可能如下所示。只需添加你可能需要的任何抽象级别,这里我假设你不需要。

public class Player 
{ 
    private IWeapon _wielded; 

    public Player(string name) 
     :this(name, null, null) 
    {} 

    public Player(string name, IWeapon primary, IWeapon secondary) 
    { 
     Name = name; 
     Primary = _wielded = primary; 
     Secondary = secondary; 

     Console.WriteLine(string.Format("Player '{0}' spawned", Name)); 
    } 

    public void Switch() 
    { 
     _wielded = _wielded != Primary ? Primary : Secondary; 
    } 

    public void Fire() 
    { 
     if (_wielded != null) 
      _wielded.Fire(); 
    } 

    public string Name { get; set; } 

    public IWeapon Primary { get; set; } 

    public IWeapon Secondary { get; set; } 
} 

要创建“任何球员”,你可以有一个简单的工厂“产卵”他们采取必要的属性作为参数。

public class PlayerFactory 
{ 
    // key = player name, value = weapons 
    public Player Create(KeyValuePair<string, string[]> args) 
    { 
     var primary = Activator.CreateInstance(Type.GetType(args.Value[0])) as IWeapon; 
     var secondary = Activator.CreateInstance(Type.GetType(args.Value[1])) as IWeapon; 

     var player = new Player(args.Key, primary, secondary); 
     return player; 
    } 
} 

现在,如果你运行下面的 “初始化” ......

// this would come from config file or similar 
var config = new List<KeyValuePair<string, string[]>> 
    { 
     new KeyValuePair<string,string[]>(
      "Player1", new[] { "SomeNamespace.Shotgun", "SomeNamespace.Knife" }), 
     new KeyValuePair<string,string[]>(
      "Player2", new[] { "SomeNamespace.NuclearBomb", "SomeNamespace.Knife" }) 
    }; 

var factory = new PlayerFactory(); 
foreach (var entry in config) 
{ 
    var player = factory.Create(entry); 
    player.Fire(); 
    player.Switch(); 
    player.Fire(); 
} 

...你结束了以下控制台日志

球员 'PLAYER1' 催生
猎枪狂潮
刺伤的吸盘

球员“Player2”催生
比赛结束了大家!! 1
刺伤德吸盘

+0

谢谢,很好的答案,但我应该分析这一点。 – 2015-02-08 18:19:14

0

当使用Strategy模式,您的设计可能看起来像下面 UML图。

Player1代表执行Fire()操作不同的武器类Weapon1Weapon2之一,...

如需进一步讨论,请参见战略设计模式 在http://w3sdesign.com

public interface IWeapon 
{ 
    void Fire(); 
} 

public class Weapon1 : IWeapon 
{ 
    ... 
    void Fire() 
    { 
     //do actions of Weapon1 
    } 
    ... 
} 

public class Weapon2 : IWeapon 
{ 
    ... 
    void Fire() 
    { 
     //do actions of Weapon2 
    } 
    ... 
} 

public interface IPlayer 
{ 
    void Update(); 
} 

public class Player1 : IPlayer 
{ 
    private IWeapon weapon; 
    private IWeapon w1; 
    private IWeapon w2; 

    public Player1() 
    { 
     w1 = new Weapon1(); 
     w2 = new Weapon2(); 
     SetWeapon(w1); 
    } 

    void Update() 
    { 
     if(SWITCH_BTN_HELD) 
     { 
      if(weapon.equals(w1)) SetWeapon(w2); 
      if(weapon.equals(w2)) SetWeapon(w1); 
     } 
     if(FIRE_BTN_HELD) 
      weapon.Fire(); 
    } 
    void SetWeapon(w) 
    { 
     weapon = w; 
    } 
}