Oop 如何处理;可选接口";?
“可选接口”可能不是一个标准术语,所以让我举个例子。假设我有:Oop 如何处理;可选接口";?,oop,interface,Oop,Interface,“可选接口”可能不是一个标准术语,所以让我举个例子。假设我有: interface Car { start(); honk(); } 现在,我可以有类似于宏达卡尔、普赖斯卡等的实现。耶!但是,如果鸣笛对我或我的用户来说并不那么重要,那么我决定这样做: interface Car { start(); canHonk(); // return true if honking is supported honk(); // undefined behavior of canHo
interface Car {
start();
honk();
}
现在,我可以有类似于宏达卡尔、普赖斯卡等的实现。耶!但是,如果鸣笛对我或我的用户来说并不那么重要,那么我决定这样做:
interface Car {
start();
canHonk(); // return true if honking is supported
honk(); // undefined behavior of canHonk is false
}
这就是我所说的“可选接口”,因为实际上支持喇叭是可选的。它看起来仍然是一个很好的、定义良好的接口,但另一种表达方式是将其分为两个接口:
interface Car {
start();
}
interface Honkable {
honk();
}
现在,如果用户代码真的需要按喇叭,您必须向它传递一个Honkable
。如果它是可选的,则可以接受空指针。如果它根本不在乎鸣叫,它可以完全忽略可鸣叫。然而,这确实增加了用户代码管理这一切的责任
所以,我列出了我看到的一些优点和缺点,但我很好奇其他人怎么想。在哪种情况下,哪种模式更可取?在我看来,两个独立的接口是最好的选择
如果您想按喇叭,请实现接口组合而不是继承,我们这里的主题是一个重要的OOP原则。它告诉我们根据对象的功能来定义对象。也就是说,第二种方法是最佳实践。像这样做:
public class SomeCar: ICar, IHonk {}
public Interface ICar {}
public Interface IHonk {}
为能力而不是身份而设计
正如其他人所提到的,这里单独的接口是更好的解决方案。还值得注意的是,它符合from 但是,另一种方法是使用功能容器:
公共类功能容器{
// ...
公共文件可用(){
// ...
}
公共T getFeatureOrNull(){
// ...
}
}
例如:
公共抽象类Car:FeatureContainer{
// ...
};
公车{
公共汽车
:base(/*实例化受支持接口的所有实现*/)
{}
}
那么你可以:
Car aCar=getSomeCar();
if(aCar.isAvailable()){
可鸣叫h=aCar.getFeatureOrNull();
h、 按喇叭();
}
当然,根据语言和所需的语义,这可能会有许多语法变化。如果您实现了一个接口,那么您必须实现契约的每一种方法。如果您只需要特定实现的部分接口,那么您的抽象性很差,应该将您的接口分为多个接口(类似于您在上文中将
Honkable
和Car
作为两个单独的接口所做的那样)。“但是,如果鸣笛对我或我的用户来说并不那么重要怎么办……”,那就不要实施它。添加bool方法并不能缓解不感兴趣的人对按喇叭的依赖。这只是他们不感兴趣的另一种方法。