是将父对象作为引用传递给父对象交互邪恶的做法

本文关键字:对象 邪恶 交互 引用 | 更新日期: 2023-09-27 18:20:37

在我最近对遗留c#代码进行的一些代码审查中,我看到了许多这样的例子:

class ManagerParentClass
{
    public string CustomProperty{get;set;}
    public void Log(string message);
    void DoABunchOfTasks()
    {
       new SomethingService().DoSomething(this);
    }
}

具有以下内容:

public class SomethingService
{
    ManagerParentClass _manager;
    void DoSomething(ManagerParentClass manager)
    {
        _manager = manager;
        // do something
        _manager.CustomProperty = "hello world";
        _manager.Log("said hello world");
    }
}

虽然这在表面上很好,但我担心这是一种反模式,可能会在垃圾收集方面造成不良影响。

这会破坏.Net正确清理父对象和子对象的能力中的世代垃圾收集器吗?

是将父对象作为引用传递给父对象交互邪恶的做法

哦,是的,这是一个可怕的反模式。我使用的代码库经常使用这一点,这简直太疯狂了。

最大的进攻?违反了封装和随之而来的类之间的紧密耦合:SomethingServiceManagerParentClass了解太多,而ManagerParentClass将自己的控制权交给了SomethingService

两个更好的选择:

  1. DoSomething()作为ManagerParentClass的实例方法,这与面向对象的一个要点更为一致:数据结构携带运算符
  2. 使SomethingService成为一个进行一些计算并返回值的方法,然后调用方可以对ManagerParentClass进行赋值

当然,这两种重构都涉及ManagerParentClass的最终突变,从函数编程的角度来看,我会尽量避免这种情况。但是,如果没有更多的信息,我不能推荐一门课程。

这实际上是一种很好的将类彼此解耦的方法——您所写的内容看起来很像访问者模式。

您编写的示例根本不会对内存产生太大影响,因为除了方法的长度外,SomethingService不会保留ManagerParentClass。如果我们假设SomethingService会在构造或常规方法期间保存这样的实例,那么它会稍微复杂一些。

让SomethingService保存对ManagerParentClass的引用意味着ManagerParentClass将被保存在引用中1)只要SomethingServices通过一些指向GC根的引用链保存在内存中,2)只要SomehingService保持对MPC的引用。

若SS释放其引用(将其置空),那个么问题就解决了。如果SS本身不再被任何东西引用,那么GC将知道SS可以是GCd,并且如果MPC仅由SS持有,那么MPC可以反过来是GCd。