2013-04-08 29 views
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(); 
    } 
} 

真正的應用程序包含許多演示文稿和服務類。
如何使用新對象和值更改實時服務實例?


更新: 我看到this鏈接。看來通過使用Setter Injection可以改變現有的對象。
setter注入我的解決方案?

+0

您是否可以不使這個注入值也是界面的一個屬性,以便您不必每次都不斷注入一個類的新實例?如果只有構造函數參數每次都在變化,那麼重新注入依賴關係似乎是一種可怕的做法。 – 2013-04-08 00:56:05

+0

@SimonWhitehead我不能。因爲我的exampled服務類實際上是.NET庫中的一個類。 (的DbContext)。我必須將連接字符串傳遞給它的構造函數。 – Shahin 2013-04-08 01:07:43

+1

@shaahin沒有IoC跟蹤它創建的實例(除非是它的單例)AFAIK。所以,簡短的回答是,沒有辦法與容器做到這一點。你可以做的是將GetInstance()方法封裝在一個你控制的方法中,並且跟蹤自己創建的實例,這樣你就可以隨時改變它們的依賴關係。不過,我建議你不要這樣做,因爲在整個應用程序中跟蹤實例並非易事。您應該重新考慮您的理由並重新考慮解決方案。 – tucaz 2013-04-08 13:52:59

回答

0

您可以使用strategy pattern在運行時輕鬆跟蹤和切換同一接口的實例。下面是一個簡單的例子:

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; 
    } 
} 

或者,如果你有,你要馬上處理的短暫依賴,你應該注入一個abstract factory到按需創建它們。

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

雖然這裏沒有顯示,該工廠可以,如果需要不同類別之間進行切換,或者你可以通過不同的相關性(在即將狀態置在這個例子中)到相同類型的類創建時。

Service Locator is Anti-Pattern除了最稀罕的情況外,應該儘量避免。