我对这个策略模式理解正确吗?

本文关键字:模式 策略 | 更新日期: 2023-09-27 18:09:54

在我之前的问题中,我被告知下面的代码是策略模式的一个例子。特别是_player.Draw(spriteBatch, _context);这一行

我看不出这一行和下面一行有什么区别,除了前者是一个额外的方法调用。

有人能解释一下我为什么不直接使用_drawHugeContext的第二个调用权,然后(喘口气)从Player类中删除Draw() ?这个例子是否过于简单,是否存在前者更好的情况?

public class Arena
{
   Player _player;
   IPlayerContext _drawHugeContext;
   public void Draw(SpriteBatch spriteBatch)
   {
      _player.Draw(spriteBatch, _drawHugeContext);
      _drawHugeContext.Draw(spriteBatch, _player);
   }
}
public class Player
{
    public int Percentage { get; private set; }
    [...] //A few more fields
    public void Draw(SpriteBatch spriteBatch, IPlayerContext context)
    {
        context.Draw(spriteBatch, this);
    }
}
public class IPlayerContext
{
    public void Draw(SpriteBatch spriteBatch, Player player)
    {
        spriteBatch.Draw(player.Percentage);
        [...] //A few more fields drawn from player
    }
}

我对这个策略模式理解正确吗?

您正在使用策略模式,但可能还不了解为什么以及如何使用它们。让我给你一个非常简单的例子。

假设你有一组对象,你想对它们排序。问题是:如何指定排序顺序?在。net中,这通常是通过传递一个lambda或一个知道如何比较两个对象的类到"Sort"方法来完成的,例如

var sorted = MyObjects.Sort((a,b) => a.Id > b.Id);

这允许您将如何对列表进行一般排序的逻辑与如何对特定集合中的两个元素排序的逻辑解耦。

在您的例子中,SpriteBatch是在调用中注入的策略,因此您的对象结构不需要确切地知道如何绘制内容。

我认为你可以使用上面的例子来有效地重构你的代码。

我认为这不是一个很好的例子。回答你的问题:

1)这个例子没有说明如何选择策略。因为SpriteBatch已经预先确定。这将有助于使示例更完整。

2)直接对玩家调用draw,增加了不必要的间接性,并且不能立即看出这在哪里/如何更好。

有很多例子,但我已经包括了一个我使用的策略模式的例子,我第一次遇到它是在Steven Metsker(一本优秀的c# GoF模式书籍)的"c#设计模式"中。与wiki或doFactory变体相比,我更喜欢这个,但它们也是很好的替代方案。这可能有助于你理解。

假设您有一个保险包,它依赖于基于客户风险因素生成报价。

保险包将使用报价引擎来完成此操作。

首先,定义一个接口,用一个方法定义所有策略共享的策略操作。

报价引擎策略的公开面由接口表示:

public interface IQuoteEngineStrategy
{
     decimal QuoteMeHappy(int riskDetails) 
}

并给出2个具体实现的例子

public class OnlineQuoteEngineStrategy : IQuoteEngineStrategy
{
    public decimal QuoteMeHappy(Customer c) { // online related retrieval } 
}
public class OfflineQuoteEngineStrategy : IQuoteEngineStrategy
{
   public decimal QuoteMeHappy(Customer c) { // offline related retrieval } 
}

QuoteEngine根据客户的情况决定给出所选的策略。在这里,年龄是决定性因素。

public class QuoteEngine 
{
    public static IQuoteEngineStrategy GetQuotingEngine(Customer c) 
    {
        if (c.Age < 25 )
        {
           return new OnlineQuoteEngineStrategy();
        }
        else
        {
           return new  OfflineQuoteEngineStrategy();
        }
    }

}

最后,InsurancePackage使用QuoteEngine,为QuoteEngine传递一些信息,以选择其策略并调用最初确定的策略操作。

public class InsurancePackage 
{
  public decimal RiskQuote(Customer c)
  {
       return QuoteEngine.GetQuotingEngine(c).QuoteMeHappy(c);
  }
}

策略模式将消费者隐藏在特定策略的实现和选择之外。

它允许战略决策远离消费者。除此之外,每个具体策略都可以作为不同外部依赖关系的适配器。

另一个好处是可以添加额外的策略,而不需要更改InsurancePackage,这意味着QuoteEngine遵循单一责任原则(SRP),而InsurancePackage遵循打开/关闭原则(对扩展开放,对修改关闭)。