【问题标题】:How to use the Strategy Pattern with C#?如何在 C# 中使用策略模式?
【发布时间】:2010-08-10 13:51:02
【问题描述】:

这是我目前所拥有的:

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

现在,如果我有一个 Character.cs 超类。该超类如何实现武器行为,以便子类可以更具体。

namespace Strategy
{
    class Character
    {
        public IWeaponBehavior weapon;

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

namespace Strategy
{
    class Thief : Character
    {

    }
}

我该如何实现呢?我对实际代码需要是什么感到非常困惑。

我知道这可能要求太多,但如果您能编写实际代码以便我研究它,那对你们非常好。我通过看代码来学习。 :P 许多人可以从这个问题中受益。

【问题讨论】:

  • “斜线斜线!”部分规则:)
  • 根据Character 的其他特征,您可以删除继承的类并使用工厂来设置所需的 Characters 特征和策略。

标签: c# strategy-pattern


【解决方案1】:

在类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

按要求编辑。

【讨论】:

  • 嗯,我比我更喜欢你的。
  • 虽然嗯,我的意图可能在语义上更清晰。
  • @Joshua - 但是你假设所有的公主都会使用平底锅,如果你有一个喜欢用刀的邪恶公主怎么办......
  • 是的,但我想它有点风格选择。你也可以有一个默认的,然后是一个重载的构造函数,你可以在其中专门设置不同的武器。
  • @SwDevMan81:我认识的大多数公主都用小酒杯。
【解决方案2】:

有几种可能性。您真正要问的是,“特定角色应该如何知道使用哪种武器?”。

您可以拥有一个角色工厂来创建并将正确类型的武器注入角色(这听起来不对:)),或者让特定角色的构造函数负责创建武器。

【讨论】:

  • 好的,但是如果角色的武器可以在任何时候更换,那就更灵活了。或许丢了刀的小偷可以拿起煎锅即兴发挥。换句话说,无论你如何初始化它,都没有理由让它不可变。
  • @Steven:您假设需要这种级别的灵活性:也没有特别需要使其可变。您应该做满足实际要求的最简单的事情(无论它们是什么!)。
  • @Dan:根据我对问题域的理解,这种灵活性很可能是个好主意。最终,这是塞尔吉奥的选择;我的工作就是提供它。
  • 我同意史蒂文的观点,但写这个答案时有点着急:) 我认为小偷应该用平底锅(或多个 IWeapon)初始化,然后让小偷类、GameManager 类或 PowerUpCrate 类根据需求动态更改武器。但是,我不想把这些东西放在我的答案中,因为我认为这不是问题所在:)
  • 我很喜欢用多种武器初始化的想法,可以根据规则使用,例如从投掷匕首开始,然后切换到短剑,同时在所有情况下只使用隐藏的刀其他武器被禁用或丢失。然而,煎锅并不是小偷一开始就会配备的武器。相反,如果情况需要,这将是小偷可以利用的环境选择。你可以自己做例子,但我的观点是锁定武器列表可能不明智。
【解决方案3】:
  class Character
  {
    private IWeaponBehavior _weapon;

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

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

【讨论】:

  • 你的构造函数必须是Character 而不是Context
  • 旁注:如果您使用前导下划线来消除本地字段的歧义,则“this”。完全是多余的。
  • 是的,这就是示例中的操作方式。但是,这并不是做某事的真正理由。例如,我发现许多 C# 专家——包括编译器团队的 MS 员工——已经存在了足够长的时间,以至于他们保持了他们的旧习惯,导致了非惯用的 C#。
  • 是的,它的风格选择。编码标准可能会有所不同,因此有时最好是明确的。明确地将成员变量设为私有也可以这样说。这也是多余的。
【解决方案4】:
公共类人物 { IWeaponBehavior 武器; } 公共课公主:性格 { 武器 = new Pan(); } 公共类小偷:角色 { 武器 = 新刀(); }

【讨论】:

    【解决方案5】:

    看看依赖注入,然后看看控制反转。

    TekPub 有一个关于这两个想法的精彩免费插曲,使用的示例与您的非常相似。这应该可以帮助您获得具体的样本。 :-)

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

    视频中的示例代码:

    class Samurai {
      IWeapon _weapon;
    
      public Samurai() {
       _weapon = new Sword();
      }
    
      public Samurai(IWeapon weapon) {
       _weapon = weapon;
      }
    
      public void Attack(string target) {
        _weapon.Hit(target);
      }
    }
    

    上面是DI(带有IWeapon构造函数)。现在添加控制反转,您可以获得更多控制权。

    使用 IOC 容器,您将能够通过注入而不是在类本身中控制 IWeapon。

    该视频使用 NInject 作为 IOC,并展示了如何消除 IWeapon 构造函数并获得对类和所有需要使用 IWeapon 的类的控制,以便在一个位置/配置区域使用你想要的东西。

    视频示例:

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

    上面的配置告诉 NInject 每当它遇到一个 IWarrior 使用 Samurai 并且每当它鼓励一个 IWeapon 使用 Sword 时。

    该视频继续解释了这一微小的变化如何提高您的灵活性。它为使用远程武器等的 Samuria 添加了另一个模块......

    您可以根据需要/想要更改这些。

    【讨论】:

      【解决方案6】:

      这是一篇关于在 C# 中使用此模式的重点文章:http://www.lowendahl.net/showShout.aspx?id=115

      【讨论】:

        【解决方案7】:

        如果你的角色都有自己的特定武器,你实际上不需要使用策略模式。你可以使用普通的多态性。但无论如何,策略模式可能会更清晰。

        你只需要初始化武器:

        public class Character
        {
             IWeapenBehavior weapon;
        
             public Attack()
             {
                  weapon.UseWeapon();
             }
        }
        
        
        public class Thief : Character
        {
              Thief()
              {
                   weapon = new Knife();
              }
        }
        

        在控制角色的代码中,您可以调用Attack() 方法。

        【讨论】:

          猜你喜欢
          • 2023-03-07
          • 2015-05-15
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多