2010-05-28 63 views
1

看看下面的例子之間的過渡成分:城堡,共享一個裝飾和裝飾部件

public interface ITask 
{ 
    void Execute(); 
} 

public class LoggingTaskRunner : ITask 
{ 
    private readonly ITask _taskToDecorate; 
    private readonly MessageBuffer _messageBuffer; 

    public LoggingTaskRunner(ITask taskToDecorate, MessageBuffer messageBuffer) 
    { 
     _taskToDecorate = taskToDecorate; 
     _messageBuffer = messageBuffer; 
    } 

    public void Execute() 
    { 
     _taskToDecorate.Execute(); 
     Log(_messageBuffer); 
    } 

    private void Log(MessageBuffer messageBuffer) 
    {} 
} 

public class TaskRunner : ITask 
{ 
    public TaskRunner(MessageBuffer messageBuffer) 
    { 

    } 

    public void Execute() 
    { 
    } 
} 

public class MessageBuffer 
{ 

} 


public class Configuration 
{ 
    public void Configure() 
    { 
     IWindsorContainer container = null; 

     container.Register(
      Component.For<MessageBuffer>() 
       .LifeStyle.Transient); 

     container.Register(
      Component.For<ITask>() 
       .ImplementedBy<LoggingTaskRunner>() 
       .ServiceOverrides(ServiceOverride.ForKey("taskToDecorate").Eq("task.to.decorate"))); 

     container.Register(
      Component.For<ITask>() 
      .ImplementedBy<TaskRunner>() 
      .Named("task.to.decorate")); 

    } 

} 

我怎樣才能讓溫莎實例「共享」短暫的組件,這樣既「裝飾」和「裝飾」獲取相同的實例?

編輯:由於設計正受到批評,我發佈了一些更接近應用中正在進行的工作。也許有人可以提出一個更好的解決方案(如共享一個記錄器和真正的任務之間的瞬時資源被認爲是一種糟糕的設計)

EDIT2:Castle3通過引入了「綁定」的生活方式增加了對這個(http://docs.castleproject.org/Windsor.Whats-New-In-Windsor-3.ashx)支持

+0

根據您的編輯,根本不需要TaskRunner中的MessageBuffer,因爲它沒有被使用。我懷疑我們仍在尋找一些遠離實際問題的東西?我知道提取問題可能很困難,因此可以很容易地進行通信而不會使其歪曲,但基於手頭的信息,您可以通過從TaskRunner中刪除MessageBuffer依賴項來解決問題。 – 2010-05-28 11:32:00

+0

我剛剛刪除使用簡潔:-)裝飾的任務將消息放入消息緩衝區,裝飾日誌將把緩衝區中的消息放入記錄器(log4net,控制檯輸出,不管) – Marius 2010-05-28 12:40:58

回答

1

'瞬態'明確意味着'非共享',所以你所要求的在概念上是錯誤的。該正確解決方案是註冊Shared作爲一個單身的,而不是短暫:(辛格爾頓是在溫莎默認壽命)

container.Register(Component.For<Shared>()); 

然而,我懷疑陳述問題的背後卻是一個更復雜的問題。我猜你需要Shared是暫時的,因爲你需要這種生活方式來處理很多其他情況,但是到了裝飾者和裝飾之間的關係時,你需要分享它們。

我仍然認爲這聽起來像是一種設計氣味,但至少有兩種方法可以達到這個效果。

第一個選項包括過早地解決Shared,並明確提供解決實例兩個的IFoo註冊的配置:

container.Register(Component.For<Shared>().LifeStyle.Transient); 

var r = container.Resolve<Shared>(); 

container.Register(Component 
    .For<IFoo>() 
    .ImplementedBy<Decorator>() 
    .DependsOn(new { resource = r })); 
container.Register(Component 
    .For<IFoo>() 
    .ImplementedBy<Decorated>() 
    .DependsOn(new { resource = r })); 

第二個選擇是做一個專門的,名爲登記Shared即只使用由IFoo註冊:

container.Register(Component.For<Shared>().LifeStyle.Transient); 
container.Register(Component.For<Shared>().Named("shared")); 
container.Register(Component 
    .For<IFoo>() 
    .ImplementedBy<Decorator>() 
    .ServiceOverrides(new { resource = "shared" })); 
container.Register(Component 
    .For<IFoo>() 
    .ImplementedBy<Decorated>() 
    .ServiceOverrides(new { resource = "shared" })); 
+1

我不想讓「Shared」非 - 因爲它具有狀態而變化。我也不想將它作爲構造函數依賴項去除,因爲它的一個必須滿足的不變量,將它變成一個屬性而不是ctor依賴項,將會改進類設計以適應IoC容器的工作。 – Marius 2010-05-28 10:46:36

+0

對狀態的關注是你不想共享實例的一個非常有道理的原因,但'Shared' *在Decorator和Decorated之間共享,所以你已經違反了這個原則。您目前的實施可能表現得「很好」,並且沒有腐敗狀態,但其他合作者可能不太好。換句話說,如果注入不同的依賴關係,實現可能會中斷。這表明違反了Liskov替代原則。 – 2010-05-28 11:36:01

+0

您錯誤地使用該用法。它適用於任何引用消息緩衝區來利用其合約的類,我的意思是增加消息。我沒有假設消息緩衝區的用法,因此我沒有打破Liskov。 – Marius 2010-05-28 12:46:54