对接口进行编码被认为是一种很好的做法,允许以后更改对象而不影响程序行为的可能性,但是如果它没有效果,为什么我们需要更改一些东西呢?我理解这种做法提供的灵活性,我只是不理解定义。
2 回答
它们意味着您可以更改该类的实现,并且您将 100% 确定更改后程序的其余部分没有损坏。因为您不会更改该类实现之外的任何一行。当然,您可以中断实现。
使用接口不仅允许您更改类的实现。它还允许您更改类本身。休息后的细节。
接口还有助于减少开发(和理解)复杂代码所需的脑力劳动。如果您可以清楚地定义程序的两个部分之间的交互,则可以在这两个部分上进行工作,而无需知道另一个部分如何实现接口。这种愉快的情况可以一直持续到两个部分都准备好组合在一起,这时称为“集成测试”的事情就会发生。
在上面描述的意义上,接口是一个相当抽象的概念。例如,函数的签名是“接口”。
其他形式的接口是使用interface
关键字的构造(例如在 Java 或 C# 中)或具有纯虚拟方法的类(在 C++ 中)。当人们说“对接口编程”时,他们通常指的是这些结构。
不是世界上最好的例子,但假设我们有这个:
interface ICooking
{
void Chop();
void Grill();
// other cooking functions
}
这是由这个类实现的:
class Chef implements ICooking
{
void Chop()
{
...
}
void Grill()
{
...
}
// other cooking functions
}
现在你想编写一个制作牛排的函数。您将需要有人来操作厨房(即实施 ICooking 的人)。
你可以这样写函数:
void MakeASteak( Chef ThePersonWhoCooks )
{
...
}
并将其称为:
Chef Joe;
MakeASteak( Joe );
或者你可以这样写:
void MakeASteak( ICooking ThePersonWhoCooks )
{
...
}
并将其称为:
Chef Joe;
MakeASteak( Joe );
您应注意以下事项:
你在两种情况下都调用
MakeASteak
完全相同您可以更改的实现
Chef::Grill
,只要它仍然“烧烤”(例如,您从中等稀有到中等),您就不需要更改代码MakeASteak
这是使用明确定义的接口的好处之一。只要该Grill
方法完成了它应该做的事情,它的调用者就不需要知道它是如何做到的。
第二个版本完全不同。这是人们在说“接口编程”时想到的。它允许添加以下内容:
class HomeCook implements ICooking
{
void Chop()
{
...
}
void Grill()
{
...
}
// other cooking functions
}
并打电话
HomeCook AverageJoe;
MakeASteak( AverageJoe );
所以,如果MakeASteak
函数只使用ICooking
then 中定义的方法,它不仅不关心函数是如何实现的ICooking
,也不关心什么对象实现了接口。
然后,您还可以使用复杂对象:
Class ComplicatedPerson implements ICooking, IWriting, IActing, ISwimming
{
}
并像以前一样使用它:
ComplicatedPerson person;
MakeASteak( person );
另一个例子是std
使用迭代器的算法。库编写者只需要知道迭代器“迭代”并且可以专注于算法本身。负责为 avector
或 a编写迭代器代码的程序员set
可以专注于他的代码,而不必担心binary search
算法细节。如果两个程序员都正确地完成了他们的工作,那么无论哪个容器提供迭代器,算法都将可用。