2010-05-28 66 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