1

我正在开发 WPF 应用程序。
我使用StructureMap来注入依赖项。
存在一些服务层类,它们从构造函数中提供参数。
我传递给构造函数的值将改变运行时间。
表示层的类使用服务为用户呈现数据。每当价值发生变化时,我都会再次注入新价值的服务。但是表示层的活动实例返回先前的值。
为了更好地理解,我准备了简单的示例。

// static class that keeps some value
public class ValueKeeper

{
    public static string Value { get; set; }
}

public interface IService
{
    string Value { get; set; }
}
// Service layer class
public class Service : IService
{
    // default constructor
    public Service(string value)
    {
        Value = value;
    }

    #region IService Members

    public string Value { get; set; }

    #endregion
}


public class Program
{
    private readonly IService _service;
    //injecting service class
    public Program(IService service)
    {
        _service = service;
    }
    // structuremap configuration
    private static void Config()
    {
        ObjectFactory.Initialize(x => x.Scan(scanner =>
                                                 {
                                                     scanner.TheCallingAssembly();

                                                     scanner.WithDefaultConventions();
                                                     x.For<IService>().CacheBy(InstanceScope.Hybrid).Use(() =>
                                                                                                             {
                                                                                                                 var service = new Service("value1");
                                                                                                                 return service;
                                                                                                             });
                                                 }));
    }
    // structuremap configuration after value changed.
    private static void ReConfig()
    {
        ObjectFactory.Configure(x => x.Scan(scanner =>
                                                 {
                                                     x.For<IService>().CacheBy(InstanceScope.Hybrid).Use(() =>
                                                                                                             {
                                                                                                                 var service =new Service(ValueKeeper.Value);
                                                                                                                 return service;
                                                                                                             });
                                                 }));
    }


    private string PresentationMethod()
    {
        return _service.Value;
    }

    private static void Main(string[] args)
    {
        Config();  // Firtst time injecting dependencies
        var prog = ObjectFactory.GetInstance<Program>(); 
        Console.WriteLine(prog.PresentationMethod()); // returns "value1"
        ValueKeeper.Value = "value 2"; //changing static property
        ReConfig(); // reconfig  service class with new property
         Console.WriteLine(prog.PresentationMethod()); // it returns value1 but I expect value2 .
        Console.ReadKey();
    }
}

实际应用程序包含许多表示和服务类。
如何使用新对象和值更改实时服务实例?


更新:我看到了这个链接。似乎通过使用 Setter Injection 可以更改现有对象。
二传手注射是我的解决方案吗?

4

1 回答 1

0

您可以使用策略模式在运行时轻松跟踪同一接口的实例并在它们之间切换。这是一个简单的例子:

var container = new Container(x => x.Scan(scan =>
{
    scan.TheCallingAssembly();
    scan.WithDefaultConventions();
    scan.AddAllTypesOf<IDiscountCalculator>();
}));
var strategy = container.GetInstance<IDiscountStrategy>();
Console.WriteLine(strategy.GetDiscount("Regular", 10)); // 0
Console.WriteLine(strategy.GetDiscount("Normal", 10)); // 1
Console.WriteLine(strategy.GetDiscount("Special", 10)); // 5

这取决于以下类型:

public interface IDiscountStrategy 
{
    decimal GetDiscount(string userType, decimal orderTotal);
}

public class DiscountStrategy : IDiscountStrategy
{
    private readonly IDiscountCalculator[] _discountCalculators;

    public DiscountStrategy(IDiscountCalculator[] discountCalculators)
    {
        _discountCalculators = discountCalculators;
    }

    public decimal GetDiscount(string userType, decimal orderTotal)
    {
        var calculator = _discountCalculators.FirstOrDefault(x => x.AppliesTo(userType));
        if (calculator == null) return 0;
        return calculator.CalculateDiscount(orderTotal);
    }
}

public interface IDiscountCalculator
{
    bool AppliesTo(string userType);
    decimal CalculateDiscount(decimal orderTotal);
}

public class NormalUserDiscountCalculator : IDiscountCalculator
{
    public bool AppliesTo(string userType)
    {
        return userType == "Normal";
    }

    public decimal CalculateDiscount(decimal orderTotal)
    {
        return orderTotal * 0.1m;
    }
}

public class SpecialUserDiscountCalculator : IDiscountCalculator
{
    public bool AppliesTo(string userType)
    {
        return userType == "Special";
    }

    public decimal CalculateDiscount(decimal orderTotal)
    {
        return orderTotal * 0.5m;
    }
}

或者,如果您想要立即处理短期依赖项,您应该注入一个抽象工厂来按需创建它们。

public ISomeObjectFactory
{
    ISomeObject Create();
    void Release(ISomeObject someObject);
}

public class SomeObjectFactory
    : ISomeObjectFactory
{
    //private readonly IAclModule aclModule;

    // Inject dependencies at application startup here
    //public SiteMapPluginProviderFactory(
    //    IAclModule aclModule
    //    )
    //{
    //    if (aclModule == null)
    //        throw new ArgumentNullException("aclModule");
    //
    //    this.aclModule = aclModule;
    //}

    public ISomeObject Create(IState state)
    {
        return new SomeObject(state);
        // return new SomeObject(state, this.aclModule);
    }

    pubic void Release(ISomeObject someObject)
    {
        var disposable = someObject as IDisposable;
        if (disposable != null)
        {
            disposable.Dispose();
        }
    }
}

然后像这样使用:

public class Consumer : IConsumer
{
    private readonly ISomeObjectFactory someObjectFactory;

    public Consumer(ISomeObjectFactory someObjectFactory)
    {
        if (someObjectFactory == null)
            throw new ArgumentNullException("someObjectFactory");
        this.someObjectFactory = someObjectFactory; 
    }

    public void DoSomething(IState state)
    {
        var instance = this.someObjectFactory.Create(state);
        try
        {
            // Use the instance here.
        }
        finally
        {
            this.someObjectFactory.Release(instance);
        }
    }
}

尽管此处未显示,但如果需要,工厂可以在不同的类之间切换,或者您可以在创建时将不同的依赖项(本示例中的 IState)传递给相同类型的类。

服务定位器是反模式的,除了最罕见的情况外,应该避免使用。

于 2014-11-29T13:23:52.847 回答