.net - 如何将策略模式与依赖注入(inject)(autofac)一起使用

标签 .net design-patterns dependency-injection autofac strategy-pattern

我想加入策略模式和 DI 的使用。

class A : IBase
{
    public void Do();
}

class B : IBase
{
    public void Do();
}

interface IBase
{
    void Do();
}

class Context()
{
    private _usedClass;
    void SetClass(IBase usedClass)
    {
        _usedClass = usedClass;
    }

    public void Do()
    {
        _usedClass.Do();
    }
}

void Main()
{
    var context = new Context();
    var someEnum = SomeMethod();

    //how to use here DI resolve to get appropriate class instead of if/else?
    if (someEnum == MyEnum.A)
        context.SetClass(new A());
    else if (someEnum == MyEnum.B)
        context.SetClass(new B());

    context.Do();
}

如何在这里使用 DI 解析来获得适当的类而不是 if/else?
谢谢

最佳答案

我肯定会使用 Delegate Factories避免依赖于 IoC 容器本身。通过使用 Keyed Service Lookup,您的代码/工厂将与 Autofac 紧密耦合。

这是一个干净整洁的示例,对 Autofac 没有任何依赖:

策略:

    public interface IStrategy { void Do(); }
    public class ConcreteStrategyA : IStrategy { public void Do() { Console.WriteLine("Called ConcreteStrategyA.Do()"); } };
    public class ConcreteStrategyB : IStrategy { public void Do() { Console.WriteLine("Called ConcreteStrategyB.Do()"); } };

您要打开的枚举:
public enum ESomeEnum
{
    UseStrategyA,
    UseStrategyB,
}

使用策略的上下文:
private readonly Func<ESomeEnum, IStrategy> _strategyFactory;

public Context(Func<ESomeEnum, IStrategy> strategyFactory)
{
    _strategyFactory = strategyFactory;
}

public void DoSomething()
{
    _strategyFactory(ESomeEnum.UseStrategyB).Do();
    _strategyFactory(ESomeEnum.UseStrategyA).Do();
}

最后是容器配置:
    var builder = new ContainerBuilder();

    builder.RegisterType<Context>().AsSelf().SingleInstance();

    builder.RegisterAssemblyTypes(Assembly.GetAssembly(typeof(IStrategy)))
           .Where(t => typeof(IStrategy).IsAssignableFrom(t))
           .AsSelf();

    builder.Register<Func<ESomeEnum, IStrategy>>(c =>
    {
        var cc = c.Resolve<IComponentContext>();
        return (someEnum) =>
        {
            switch (someEnum)
            {
                case ESomeEnum.UseStrategyA:
                    return cc.Resolve<ConcreteStrategyA>();
                case ESomeEnum.UseStrategyB:
                    return cc.Resolve<ConcreteStrategyB>();
                default:
                    throw new ArgumentException();
            }
        };
    });

    var container = builder.Build();

    container.Resolve<Context>().DoSomething();

如果策略不消耗在容器中注册的任何依赖项,您可以自己新建它们,并像这样简化配置:
var builder = new ContainerBuilder();

builder.RegisterType<Context>().AsSelf().SingleInstance();
builder.Register<Func<ESomeEnum, IStrategy>>(c => StrategyFactory.GetStrategy);

var container = builder.Build();

container.Resolve<Context>().DoSomething();

并将开关盒放在一个单独的类中:
public static class StrategyFactory
    {
        internal static IStrategy GetStrategy(ESomeEnum someEnum)
        {
            switch (someEnum)
            {
                case ESomeEnum.UseStrategyA:
                    return new ConcreteStrategyA();
                case ESomeEnum.UseStrategyB:
                    return new ConcreteStrategyB();
                default:
                    throw new ArgumentException();
            }
        }
    }

完整运行代码示例 - check in .NET Fiddle :
using Autofac;
using System;
using System.Reflection;

namespace Samples.Autofac.StrategyPattern
{
    public interface IStrategy { void Do(); }

    public class ConcreteStrategyA : IStrategy { public void Do() { Console.WriteLine("Called ConcreteStrategyA.Do()"); } };
    public class ConcreteStrategyB : IStrategy { public void Do() { Console.WriteLine("Called ConcreteStrategyB.Do()"); } };

    public enum ESomeEnum
    {
        UseStrategyA, UseStrategyB,
    }

    public class Context
    {
        private readonly Func<ESomeEnum, IStrategy> _strategyFactory;

        public Context(Func<ESomeEnum, IStrategy> strategyFactory)
        {
            _strategyFactory = strategyFactory;
        }

        public void DoSomething()
        {
            _strategyFactory(ESomeEnum.UseStrategyB).Do();
            _strategyFactory(ESomeEnum.UseStrategyA).Do();
        }
    }

    public class AutofacExample
    {
        public static void Main()
        {
            var builder = new ContainerBuilder();

            builder.RegisterType<Context>().AsSelf().SingleInstance();
            builder.RegisterAssemblyTypes(Assembly.GetAssembly(typeof(IStrategy)))
                   .Where(t => typeof(IStrategy).IsAssignableFrom(t))
                   .AsSelf();
            builder.Register<Func<ESomeEnum, IStrategy>>(c =>
            {
                var cc = c.Resolve<IComponentContext>();
                return (someEnum) =>
                {
                    switch (someEnum)
                    {
                        case ESomeEnum.UseStrategyA:
                            return cc.Resolve<ConcreteStrategyA>();
                        case ESomeEnum.UseStrategyB:
                            return cc.Resolve<ConcreteStrategyB>();
                        default:
                            throw new ArgumentException();
                    }
                };
            });

            var container = builder.Build();

            container.Resolve<Context>().DoSomething();
        }
    }
}

关于.net - 如何将策略模式与依赖注入(inject)(autofac)一起使用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34359432/

相关文章:

.net - MySqlCommand 参数不起作用

c# - 如何隐藏和显示窗体上的面板并调整其大小以占用空间?

java - 级联/嵌套异步调用的模式

dependency-injection - 我的 Unity DI 容器中所有对象的列表

c# - container.RegisterWebApiControllers(GlobalConfiguration.Configuration) 导致 InvalidOperationException

java - 在方法之前和之后执行代码?

c# - 在不阻塞 ui UWP 的情况下调用数据库异步方法的最佳实践

c# - 如何在模拟 ClaimsPrincipal 中添加声明

algorithm - 确定一组日期的事件重复模式

java - Android 设计模式,Realm 中用于组合的单例对象类?