Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/oop/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何解决OOP中的交叉引用问题?_Oop - Fatal编程技术网

如何解决OOP中的交叉引用问题?

如何解决OOP中的交叉引用问题?,oop,Oop,我现在已经遇到过几次了,我想知道解决循环引用的OO方法是什么。我的意思是A类有B类作为成员,B类又有A类作为成员 Person jack = new Person("Jack"); Person jill = new Person("Jill"); jack.setSpouse(jill); jill.setSpouse(jack); 其中一个例子是有个人配偶作为成员的类人 Person jack = new Person("Jack"); Person jill = new Person("

我现在已经遇到过几次了,我想知道解决循环引用的OO方法是什么。我的意思是A类有B类作为成员,B类又有A类作为成员

Person jack = new Person("Jack");
Person jill = new Person("Jill");
jack.setSpouse(jill);
jill.setSpouse(jack);
其中一个例子是有个人配偶作为成员的类人

Person jack = new Person("Jack");
Person jill = new Person("Jill");
jack.setSpouse(jill);
jill.setSpouse(jack);
另一个例子是产品类,其中包含一些其他产品的集合作为成员。例如,该集合可能是对该产品感兴趣的人也可能感兴趣的产品,我们希望在每个产品基础上维护该列表,而不是在相同的共享属性上(例如,我们不希望只显示同一类别中的所有其他产品)

(这些产品只是为了说明一点,问题不在于产品是否相互关联)

在面向对象编程中,这是一个糟糕的设计吗?所有OOP语言都会/应该允许这样做,还是仅仅是不好的做法?如果这是一种不好的做法,那么解决这个问题的最佳方法是什么?

您给出的示例(对我来说)是合理的OO设计示例

您描述的交叉引用问题不是任何设计过程的产物,而是您表示为对象的事物的真实特征,因此我认为没有问题

您遇到过什么让您觉得这种方法是一种糟糕的设计?

3月11日更新:

在缺乏垃圾收集的系统中,内存管理是显式管理的,一种常见的方法是要求所有对象都有一个所有者,即负责管理该对象生命周期的其他对象

一个例子是Delphi的TComponent类,它提供了级联支持—销毁父组件,所有拥有的组件也都会销毁

如果您在这样一个系统上工作,那么这个问题中描述的引用循环可能会被认为是糟糕的设计,因为没有明确的所有者,没有一个对象负责管理生命周期


我在一些系统中看到的处理方法是保留引用(因为它们正确地捕获了业务关注点),并添加一个显式TransactionContext对象,该对象拥有从数据库加载到业务域中的所有内容。此上下文对象负责知道需要保存哪些对象,并在处理完成时清理所有内容。

这是一个问题,主要是如果它变得太混乱而无法处理或维护,因为它可能会成为一种意大利面代码

然而,要触及你的例子

如果这是您在代码中需要的功能,那么See也是完全有效的——它是指向用户可能感兴趣的其他项目的指针(或引用)的简单列表

同样,添加配偶也是非常有效的,因为这是一种简单的现实关系,不会让维护代码的人感到困惑

我一直认为这是一种潜在的代码气味,或者可能是一种警告,让我后退一步,让我的工作合理化


对于一些在代码中查找递归关系的系统(在上面的注释中提到),无论这种设计如何,都可能出现这些关系。我最近开发了一个元数据捕获系统,该系统具有递归的“类型”关系,即列与其他列在逻辑上相关。它需要由试图解析系统的代码来处理。

解决此问题的一种方法是通过id引用其他对象

e、 g


我并不是说这是一个完美的解决方案,但它会阻止循环引用。您正在使用对象而不是对象引用来建模关系。

这不是OO设计中的基本问题。一个可能成为问题的时间示例是在图遍历中,例如,找到两个对象之间的最短路径-您可能会进入无限循环。然而,这是你必须根据个案考虑的问题。如果您知道在这种情况下可能存在交叉引用,那么请编写一些检查代码以避免无限循环(例如,维护一组已访问的节点以避免重新访问)。但如果没有理由认为这可能是一个问题(比如你在问题中给出的例子),那么有这样的交叉引用也不错。在许多情况下,正如您所描述的,这是解决当前问题的一个很好的方法。

我认为循环引用本身并不是一个问题


但是,将所有这些关系放在对象中可能会增加太多的混乱,因此您可能希望在外部表示它们。例如,您可以使用哈希表存储产品之间的关系。

我认为这不是交叉引用的示例

交叉引用通常适用于这种情况:

class A
{
    public void MethodA(B objectB)
    {
       objectB.SomeMethodInB();
    }
}

class B
{
    public void MethodB(A objectA)
    {
        objectA.SomeMethodInA();
    }
}
在这种情况下,每一种物体都相互“接触”;A调用B,B调用A,它们紧密耦合。如果A和B在不同的包/名称空间/程序集中,情况会更糟;在许多情况下,当程序集以线性方式编译时,会产生编译时错误

解决这个问题的方法是让任意一个对象使用所需的方法实现一个接口

在您的情况下,您只有一个“进入”级别:


我不认为这是不合理的,甚至是交叉引用/循环引用的情况。

引用其他对象并不是一个真正糟糕的OO设计。这是在每个对象中管理状态的方式


德米特定律是一条很好的经验法则。看看这张完美的LoD文件(报童和钱包):

对我来说也像是现实生活,我只是在想虚拟机不会因为追逐对象而感到困惑。。。加载一个人,加载那个人的配偶,再次加载那个人的配偶。。。这是一个永恒的循环。只是想知道是否所有虚拟机都能正确处理这个问题?你是说跑步时间?Ref仅计数系统(COM或滚动您自己的智能指针,例如
class A
{
    public void MethodA(B objectB)
    {
       objectB.SomeMethodInB();
    }
}

class B
{
    public void MethodB(A objectA)
    {
        objectA.SomeMethodInA();
    }
}
public Class Person
{
    public void setSpouse(Person person)
    { ... }
}