首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >依赖注入策略模式?

依赖注入策略模式?
EN

Stack Overflow用户
提问于 2022-07-01 15:51:05
回答 3查看 274关注 0票数 1

是否有一种优雅的方法来处理策略模式的依赖注入?

例如,我有我的依赖注入器,我用它注册了一些不同的策略,如下所示:

代码语言:javascript
复制
container.Register<IMakeCoffee, MakeLatte>();
container.Register<IMakeCoffee, MakeEspresso>();
container.Register<IMakeCoffee, MakeCappuccino>();

然后,当我想访问这些策略之一时,我将其插入构造函数中,例如:

代码语言:javascript
复制
public Barista(IEnumerable<IMakeCoffee> coffeeStrategies) {}

但是一旦我有了所有策略的清单,我怎么能说我想要这个特定的策略呢?我现在所做的是强迫IMakeCoffee的每个实例都有一个CoffeeType枚举,我可以通过这个枚举来确定策略的类型。

代码语言:javascript
复制
public Coffee MakeCoffee(CoffeeType coffeeType)
{
    var strat = coffeeStrategies.FirstOrDefault(s => s.CoffeeType == coffeeType);
    return strat.MakeCoffee();
}

是否有一种更优雅的方法来唯一地识别策略?这件事似乎很麻烦。

作为参考,我正在使用Prism作为一个Xamarin表单应用程序,但是我觉得这个问题是框架独立的。

EN

回答 3

Stack Overflow用户

发布于 2022-07-01 16:15:16

选择一个具有“咖啡类型”枚举的策略是有意义的,但是选择器查询具有侵扰性,因为它需要知道各种实现细节才能做出选择,而且没有什么可以说这种咖啡类型永远是任何给定策略的唯一鉴别器。

我会对细节进行封装,并让策略接口公开一个bool IsApplicable(CoffeeMakerStrategyContext context)方法,每个策略都可以根据需要以不同的方式实现该方法。该方法可以将CoffeeType枚举作为参数,但如果出现了新策略,但需要更多数据来作出决定,则签名将需要更改;通过传递“策略上下文”对象,签名不需要更改(类似于为什么我们对事件参数使用EventArgs ):

代码语言:javascript
复制
public interface IStrategy<TContext>
{
    bool IsApplicable(TContext context);
}

public interface ICoffeeMakerStrategy : IStrategy<CoffeeMakerStrategyContext>
{
    Coffee MakeCoffee();
}

选择器代码变成:

代码语言:javascript
复制
var context = new CoffeeMakerStrategyContext { CoffeeType = coffeeType };
var strategy = _strategies.FirstOrDefault(e => e.IsApplicable(context));
if (strategy is null)
{
    throw new NotSupportedException("No applicable strategy was found for the specified context");
}

return strategy.MakeCoffee();
票数 1
EN

Stack Overflow用户

发布于 2022-07-01 16:21:16

我的第一个想法是,缺乏受歧视的工会使得这在类型层面上更加令人沮丧。为了方便和获得免费的try get模式,我很想做这样的事情:

代码语言:javascript
复制
Dictionary<CoffeeType, IMakeCoffee> m_CoffeeMakers;

public Barista(IEnumerable<IMakeCoffee> coffeeStrategies)
{
    m_CoffeeMakers = coffeeStrategies.ToDictionary(x => x.HandledCoffeeType, x => x);
}

public Coffee MakeCoffee(CoffeeType coffeeType)
{
    if (!m_CoffeeMakers.TryGet(coffeeType, out var coffeeMaker)
    {
        throw new InvalidOperationException($"unsupported coffee type {coffeeType}");
    }

    return coffeeMaker.MakeCoffee();
}

我认为您也许可以使用DI'd装饰器,但这有点混乱,因为链的底部必须返回null,这使得它变得更加混乱。

票数 0
EN

Stack Overflow用户

发布于 2022-07-01 16:31:03

您可以创建某种策略选择器:

代码语言:javascript
复制
public interface IStrategySelector<TKey, TStrategy>
{
    TStrategy Select(TKey key);
}

然后,您可以将选择逻辑放入实现中:

代码语言:javascript
复制
public sealed class CoffeeStrategySelector : IStrategySelector<CoffeeType, IMakeCoffee>
{
    public IMakeCoffee Select(CoffeeType coffeeType)
    {
        // Place your selection logic here.
    }
}

您可以从选择器的构造函数中要求您的IEnumerable<IMakeCoffee>,或者使用任何其他技术方法来实现您的选择逻辑。

你的咖啡师会很高兴的

代码语言:javascript
复制
private readonly IStrategySelector<CoffeeType, IMakeCoffee> _coffeeSelector;

public Barista(IStrategySelector<CoffeeType, IMakeCoffee> coffeeSelector)
{
    _coffeeSelector = coffeeSelector;
}

public Coffee MakeCoffee(CoffeeType coffeeType)
{
    IMakeCoffee strat = _coffeeSelector.Select(coffeeType);
    return strat.MakeCoffee();
}
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/72831784

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档