可以做些什么来修复其根类需要装饰器实例的装饰器?

时间:2013-02-12 11:31:20

标签: c# design-patterns decorator

我正在重构一个软件,试图让它更易于测试/ DI友好,并使其更具可扩展性。原始代码依赖于继承,但我认为装饰器将是一个更灵活的设计,因为我希望组件的最终用户能够在我正在创建的某些层下面插入图层。

但是,我遇到了问题,因为基类中的一些代码会将this传递给某些方法。使用继承这不会是一个问题,因为this将引用顶层类型,但我无法尝试解决如何使用装饰器进行此操作。这是一个例子:

public interface INode
{
    bool IsReadOnly { get; }
    void DoSomething();
}

public class Node : INode
{
    public Node(ISomeFactory someFactory)
    {
        if (someFactory == null)
            throw new ArgumentNullException("someFactory");
        this.someFactory = someFactory;
    }

    private readonly ISomeFactory someFactory;


    public bool IsReadOnly { get { return false; } }

    public void DoSomething()
    {
        // Some implementation code here

        // This factory doesn't get an instance of the decorator type
        // when it is in use - this is a problem
        var someInstance = someFactory.Create(this);

        // More code here...
    }
}

public class LockableNode : INode
{
    public LockableNode(INode node, ILockingService lockingService)
    {
        if (node == null)
            throw new ArgumentNullException("node");
        if (lockingService == null)
            throw new ArgumentNullException("lockingService");

        this.innerNode = node;
        this.lockingService = lockingService
    }

    private readonly INode innerNode;
    private readonly ILockingService lockingService;

    public bool IsReadOnly { get { return lockingService.IsReadOnly; } }

    public void DoSomething()
    {
       if (this.IsReadOnly)
           throw new InvalidOperationException("Node is read-only");

       this.innerNode.DoSomething();
    }
}

然后我的工厂做了这样的事情:

var someFactory = new SomeConcreteFactory();
var lockingService = new LockingService();

var node = new Node(someFactory);
var lockableNode = new LockableNode(node, lockingService);
return lockableNode;

我的评论所概述的问题是我试图装饰的代码中的一些地方,当前对象作为参数传递给其他方法,我需要一个装饰器对象的实例在使用时而不是当前的对象。如果没有重新实现将this传递到装饰器类中的工厂的代码,是否可以采取一些措施来解决这个问题?

2 个答案:

答案 0 :(得分:0)

使实际的doSomething方法需要将装饰对象作为参数:

<强>节点

public void DoSomething()
{
    this.DoSomethingWith(this)
}
public void DoSomethingWith(INode it)
{
    // ...

    var someInstance = someFactory.Create(it);

    // ...
}

<强> LockableNode

public void DoSomething()
{
    this.innerNode.DoSomethingWith(this);
}
public void DoSomethingWith(INode it)
{
    this.innerNode.DoSomethingWith(it);
}

编辑:当然,您也必须更改界面。

public interface INode
{
    bool IsReadOnly { get; }
    void DoSomething();
    void DoSomethingWith(INode it);
}

答案 1 :(得分:0)

总之,在我的情况下,答案是使用继承。我确信装饰器模式在某个地方有用,但是向一个域对象添加功能,使得跨成员调用并将对自身的引用传递给其他对象不是这样,特别是如果你无法控制何时或如何其他引用或跨成员调用将来会插入到代码中。

我发现这篇文章还有其他一些我没想过的想法:

A problem when using the decorator design pattern