![]() |
1
17
你看到的是违反
Liskov Substitution Principle
使之很难有一个工作的,逻辑的面向对象的结构。
|
![]() |
2
6
然而,可能发生的情况是两栖飞行器目标知道它目前是在水上还是在陆地上,并且做了正确的事情。 |
![]() |
3
6
在你的例子中,
什么时候?
所以当混凝土
如果您需要“移动”的契约来体现表面的概念,请不要将其定义为不模拟此概念的类型:
(类比:
或者重构通用接口以添加概念:
我在实现多个接口时看到的唯一问题是,来自完全无关接口的两个方法发生冲突:
但那不是钻石。更像一个倒三角形。 |
![]() |
4
5
是的,因为您在D中控制接口的实现。两个接口(B/C)之间的方法签名是相同的,并且认为接口没有实现——没有问题。 |
![]() |
5
4
我不知道Java,但是如果接口B和C从接口A继承,D类实现接口B和C,那么D类只实现一次移动方法,它是它应该实现的一个动作。正如您所说,编译器对此没有问题。 从两栖车辆实施地面车辆和水上车辆的实例中,可以很容易地解决这一问题,例如,通过存储环境参考,以及暴露两栖车辆移动方法将要检查的环境表面特性。不需要将此作为参数传递。 从某种意义上说,这是程序员要解决的问题,但至少它是编译的,不应该是“问题”。 |
![]() |
6
4
基于接口的继承没有菱形问题。 使用基于类的继承,多个扩展类可以有一个方法的不同实现,因此对于运行时实际使用的方法存在不确定性。 对于基于接口的继承,该方法只有一个实现,因此没有歧义。 编辑:实际上,对于在超类中声明为抽象的方法,基于类的继承也同样适用。 |
![]() |
7
3
您将提供适合
如果A
如果是由于糟糕的类设计,那么需要由程序员来解决,因为编译器不知道如何解决。 |
![]() |
8
2
您在学生/教师示例中看到的问题只是您的数据模型错误,或者至少不充分。 学生班和教师班用同一个名字把“系”的两个不同概念混为一谈。如果你想使用这种继承,你应该在教师中定义“getteachingdepartment”,在学生中定义“getresearchdepartment”。你的研究生既是老师又是学生,两者兼备。 当然,考虑到研究生院的实际情况,即使是这种模式也可能是不够的。 |
![]() |
9
1
我不认为阻止具体的多重继承将问题从编译器转移到程序员身上。在您给出的示例中,程序员仍然需要向编译器指定要使用的实现。编译器无法猜测哪个是正确的。 对于您的两栖类,您可以添加一个方法来确定车辆是在水上还是在陆地上,并使用这个方法来决定要使用的移动方法。这将保留无参数接口。
|
![]() |
10
1
在这种情况下,将两栖车辆作为车辆的一个子类(水上车辆和陆上车辆的兄弟)可能是最有利的,以便在第一时间完全避免这一问题。不管怎样,这可能更正确,因为两栖车辆不是水上车辆或陆上车辆,它是完全不同的东西。 |
![]() |
11
1
如果move()基于它是地下水或水(而不是地面车辆和水上车辆接口本身扩展了具有move()签名的通用车辆接口),但预期您将混合和匹配地下水和水的实现者,那么您的示例之一实际上是一个设计不良的API。 真正的问题是名称冲突实际上是意外的。 例如( 非常 合成):
如果你有一件夹克,你希望它既是一件衣服,又容易毁坏,你将有一个名称冲突(合法命名)的穿着方法。 Java对此没有解决办法(对于其他静态类型语言也是如此)。动态编程语言也会有类似的问题,即使没有菱形或继承,也只是名称冲突(duck类型固有的潜在问题)。 .NET的概念是 explicit interface implementations 一个类可以定义两个具有相同名称和签名的方法,只要这两个方法都标记到两个不同的接口上。要调用的相关方法的确定基于变量的编译时已知接口(或者如果通过反射由被调用方的显式选择) 这种合理的、可能的名称冲突是很难得到的,Java没有被嘲笑为无法提供明确的接口实现,这表明这个问题对于现实世界的使用来说不是一个重要的问题。 |
![]() |
12
0
我知道这是一个特定的实例,不是一般的解决方案,但听起来您需要一个额外的系统来确定状态并决定车辆将执行哪种移动()。 在两栖车辆的情况下,呼叫者(我们称为“油门”)可能不知道水/地面的状态,但是一个中间决定对象(如“变速箱”)和“牵引力控制”可能会解决这个问题,然后用适当的参数move(车轮)或move(道具)调用move()。 |
![]() |
13
0
问题确实存在。在这个例子中,两栖类需要另一个信息——水面。我的首选解决方案是在AmpibianVehicle类上添加getter/setter方法来更改表面成员(枚举)。实现现在可以做正确的事情,类保持封装状态。 |
![]() |
14
0
您可以在C++中有菱形问题(允许多重继承),但不能在Java或C语言中使用。无法从两个类继承。在这种情况下,使用相同的方法声明实现两个接口并不意味着,因为具体的方法实现只能在类中进行。 |
![]() |
15
0
C++中的菱形问题已经解决了:使用虚拟继承。或者更好的是,在不必要(或不可避免)的时候,不要懒惰和继承遗产。对于您给出的示例,可以通过重新定义能够在地面或水中驾驶的含义来解决这一问题。在水中移动的能力真的定义了一辆水上汽车,还是仅仅是它能做的事情?我宁愿认为您描述的move()函数背后有某种逻辑,它会询问“我在哪里,实际上我可以移动到这里吗?”相当于
|
![]() |
16
0
实际上,如果
但是,正如评论中指出的,这并不能解决
没关系
|
![]() |
17
0
接口A { 空格加法(); } 接口B扩展A { 空格加法(); } 接口C扩展了 { 空格加法(); } D类实现B、C { } 这不是钻石问题吗? |