想象一下这些关系:
相反:
要在DB中建模这种关系,我们有:
TableA
a_id
TableB
b_id
a_id (fk to TableA)
TableC
c_id
b_id (fk to TableB)
要在OO中建模这种关系,我们有:
objA
objB
objC
和... - objB引用了objA - objC引用了objB
如果objC有一个需要调用objA方法的方法,你会怎么做?
选项1。
b.getA().runMethodX()
我知道很多人会这样做,但我也知道这不好,因为getA()不是纯粹OO意义上的B行为。这样做就像进行程序编程一样。同意/不同意?
选项2。
让objC通过构造函数注入/设置器直接引用objA和objB
这是个好主意吗?但是objC参考的objB也引用了objA。这个可以吗?或者只要它不是循环对象引用的情况,它是可以接受的吗?
选项3。
将有问题的方法移至objA,并通过参数传递objC。
我不确定这是否是一种选择。我认为它并不适用于所有情况。将objC中的方法减少到仅适用于其状态的最小值,并让objA执行objA之前或之后需要执行的操作。
选项4。(代表团)
将runMethodXinA()添加到B,调用
a.runMethodX()
C来电
b.runMethodXinA()
之前我尝试过这种方法,但B很可能最终拥有与A一样多的方法,并且B和A中没有1种方法违反了DRY?
你有什么打算?还有其他选择吗?评论?建议
答案 0 :(得分:2)
选项2是一个相当危险的信息重复,除了根据您的环境可能来自参考图形状的任何问题。
如果方法在某种意义上取决于objA的类型,那么选项3可能是有意义的,作为一种双重调度。
选项1违反了得墨忒耳法,但听起来它是最不具侵入性的选择。
您可能还想在objB上考虑将调用传递给objA的转发方法。
答案 1 :(得分:0)
从您的选择列表中,选项是选项4,因为它服从Law of Demeter
留下选项4
可能有选项5,但这超出了原始问题的范围; - )
答案 2 :(得分:0)
我认为问题是你想要什么样的模特。如果你想要一个关系模型,你提前知道整个结构并且它不会改变,那么选项1是可以接受的。也就是说,C中需要A 中特定组织模式中的数据/方法。
选项2似乎是一个好主意。但实际上你保存了对同一个对象的两个引用。现在,如果B被映射到不同的A,则B必须通知C也改变其引用。不好。
然而,选项4似乎是采用真正的OO方法的正确方法。关键是A可以改变它的结构,你只需要适应B - 直接的孩子。 C不知道也不关心A是如何实现的,只要A存在就足够了,B知道如何处理它。
答案 3 :(得分:0)
你真的需要从C到B到A的后向指针,或者你只有它们才能从C访问A?也许A应该负责创建B和C以及管理他们的关系。在这种情况下,A可以在创建C时将自身插入到C中(例如,C可能有一个带有A的构造函数)。
您也可以隔离C所需的A上的功能并为其创建接口。接口(而不是A)将在构造时传递给C.这将使C与A分离。
答案 4 :(得分:0)
没有。 1或4号视情况而定。在我的金属切割软件中,我们有许多实例需要知道对象的父/源。例如,我们在Fitting上有一个Path Collection,每个Path都有一个Fitting属性,返回创建它的拟合。
然而,如果连接对象只是因为它有助于原始对象实现其目的(如数学支持),那么委派可能是更好的方法。
如果连接的对象修改了原始对象,那么最好使用访问者模式。
唯一需要注意的是,在大多数OOP中,您必须小心双重链接的对象。对于具有相互连接的父子链接的对象,垃圾收集通常会失败。忘记清理父子链接是一个常见的错误。
使用支持创建和使用事件的OOP,您可以解决此问题。通过使用代理。父对象将向子进行代理对象而不是自身。当孩子需要父母时,它将从代理对象获得引用。代理对象反过来引发一个导致父进程返回的事件。没有硬链接,因此减轻了程序员或垃圾收集器未清理的问题。