是将父对象作为引用传递给父对象交互邪恶的做法
本文关键字:对象 邪恶 交互 引用 | 更新日期: 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正确清理父对象和子对象的能力中的世代垃圾收集器吗?
哦,是的,这是一个可怕的反模式。我使用的代码库经常使用这一点,这简直太疯狂了。
最大的进攻?违反了封装和随之而来的类之间的紧密耦合:SomethingService
对ManagerParentClass
了解太多,而ManagerParentClass
将自己的控制权交给了SomethingService
。
两个更好的选择:
- 将
DoSomething()
作为ManagerParentClass
的实例方法,这与面向对象的一个要点更为一致:数据结构携带运算符 - 使
SomethingService
成为一个进行一些计算并返回值的纯方法,然后调用方可以对ManagerParentClass
进行赋值
当然,这两种重构都涉及ManagerParentClass
的最终突变,从函数编程的角度来看,我会尽量避免这种情况。但是,如果没有更多的信息,我不能推荐一门课程。
这实际上是一种很好的将类彼此解耦的方法——您所写的内容看起来很像访问者模式。
您编写的示例根本不会对内存产生太大影响,因为除了方法的长度外,SomethingService不会保留ManagerParentClass。如果我们假设SomethingService会在构造或常规方法期间保存这样的实例,那么它会稍微复杂一些。
让SomethingService保存对ManagerParentClass的引用意味着ManagerParentClass将被保存在引用中1)只要SomethingServices通过一些指向GC根的引用链保存在内存中,2)只要SomehingService保持对MPC的引用。
若SS释放其引用(将其置空),那个么问题就解决了。如果SS本身不再被任何东西引用,那么GC将知道SS可以是GCd,并且如果MPC仅由SS持有,那么MPC可以反过来是GCd。