如何修复根类需要decorator实例的decorator

本文关键字:decorator 实例 何修复 | 更新日期: 2023-09-27 17:58:58

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

然而,我遇到了麻烦,因为基类中的一些代码将this传递到了一些方法中。使用继承这不会是一个问题,因为this会引用顶层类型,但我在尝试如何使用decorator来实现这一点时遇到了困难。这里有一个例子:

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;

正如我的评论所概述的问题是,在我试图装饰的代码中的一些地方,当前对象作为参数传递给其他方法,当它在使用时,我需要一个装饰器对象的实例,当它不在使用时我需要当前对象的实例。除了在decorator类中重新实现将this传递到工厂的代码之外,还有什么可以解决的吗?

如何修复根类需要decorator实例的decorator

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

节点

public void DoSomething()
{
    this.DoSomethingWith(this)
}
public void DoSomethingWith(INode it)
{
    // ...
    var someInstance = someFactory.Create(it);
    // ...
}

可锁定节点

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

总之,在我的案例中,答案是使用继承。我确信decorator模式在某些地方有它的用途,但向域对象添加功能,使其进行跨成员调用,并将对自身的引用传递给其他对象,这不是它的目的,尤其是如果您无法控制将来何时或如何将其他引用或跨成员调用插入到代码中。

我发现另一篇帖子有几个我没有尝试过的想法:

使用装饰器设计模式时的问题