让我们从维基百科给出的循环依赖概述开始
循环依赖在许多域模型中是很自然的,其中同一域的某些对象相互依赖。然而,在软件设计中,较大的软件模块之间的循环依赖被认为是一种反模式,因为它们的负面影响......
让我们打破它:
- 循环依赖在许多域模型中是很自然的,其中同一域的某些对象相互依赖。
它说自然。以下是来自 的示例Ado.Net
。DataTable
和DataRow
对象
DataTable t = new DataTable("MyNewTable");
DataRow r = t.NewRow();
t.Rows.Add(r);
// Lets inspect it
Debug.WriteLine(r.Table.TableName);
// This will print - MyNewTable
在这个例子中,你有一个 CD 所在的子系统,正如他们所说 - 自然。例如,您知道汽车的每个主要部件上都有 VIN 号。让我们用伪代码实现它
class Car{
string Vin { get; set; }
void AddDoor(Door.Position pos){
Door d = new Door();
d.DoorPosition = pos;
d.Car = this; // notice this - door knows about a car!!
_doors.Add(d);
}
}
class Door{
Car CarAttachedTo;
Position DoorPosition;
public enum Position {
DriverFront
DriverRear
PassangerFront
PassangerRear
}
}
让我们想象一下,有人把你的门关掉了,警察把它找回来了,你需要确定它是你的门还是别人的 - 然后你做:
if (myDoor.CarAttachedTo.Vin == "MY_CAR_VIN_NUMBER")
MessageBox.Show("The door is stolen off my car");
理念:在紧密协作和组织在一起的子系统中,CD 有时还可以
- 较大的软件模块之间的循环依赖被认为是一种反模式
您的应用程序可以在物理上位于同一个程序集(dll、exe)中,而在逻辑上它可以具有单独的逻辑层。例如,您可以在同一个程序集中编写您的 UI、BLL 和 IO。因此很容易在你的 UI 和 BLL 之间创建循环依赖。如果每一层都存在于一个单独的程序集中,这将更加困难。
CD 经常与紧耦合相混淆。虽然在上面的示例中我们看到了 CD 有时是多么有用,但紧密耦合通常意味着一个具体对象知道另一个具体对象,并且没有可重用性、可扩展性和可测试性的空间。让我们回到车上。让我们详细了解汽车上的吊门 - 你的汽车经过装配线,它来到了门贴机
class DoorHandler{
private Car _car;
private MitsubishiDoorAlignmentMachine _doorMachine;
void HangDoors(){
foreach (Door d in _car.Doors){
// hang the door using
_doorMachine.Hang(d)
}
}
}
但是现在我们遇到了一个问题——我们的 Door 处理程序只适用于MitsubishiDoorAlignmentMachine
. 如果我想用 替换它FujitomoHeavyIndustriesDoorAlignmentMachine
怎么办?然后我需要做这样的事情:
class DoorHandler{
private Car _car;
private IDoorAlignmentMachine _doorMachine;
void HangDoors(){
foreach (Door d in _car.Doors){
// hang the door using
_doorMachine.Hang(d)
}
}
}
// And when I crate my DoorHandler - I tell it which machine to use
new DoorHandler(new FujitomoHeavyIndustriesDoorAlignmentMachine());
这种方式我DoorHandler
不依赖于任何特定的机器
现在,让我们回到您的情况 -A
和B
. 可能有多个答案。如果您正在创建需要在对象之间进行交互但可能有多个实现的子系统 - 只需使用接口。这样,您A
将B
知道签名而不是具体对象。如果只有一个实现并且对象是同一个程序集中的同一个子系统的一部分 - 相互了解可能就可以了。