从我所看到的,似乎可以与界面进行交互?
例如。让我说我有一个空方法接口“吃()”
然后有2个子类正在实现这个接口。
我的控制器可以只与界面交互并使用它的eat()方法吗?
查看此链接strategy
中的图片答案 0 :(得分:15)
除了访问接口中的任何已定义常量或将其用于TypeHints之外,您无法与接口进行交互。接口没有方法体。它们仅用于定义实现类必须遵守的合同。
interface Logger
{
const FOO = 1;
public function log($msg);
}
echo Logger::FOO; // 1
Logger::log($msg); // Fatal error: Cannot call abstract method Logger::log()
new Logger; // Fatal error: Cannot instantiate interface Logger
请参阅http://php.net/manual/en/language.oop5.interfaces.php
当 对接口进行编码 或与接口进行交互时通常意味着什么只不过是调用中定义的方法 实现它们的类中的接口。您调用实现,而不是定义。该定义仅指定对于实现接口的每个Class,必须有一个具有指定参数的特定方法。
考虑这些课程:
Class DbLog implements Logger
{
public function log($msg) { /* log $msg to database */ }
}
Class FileLog implements Logger
{
public function log($msg) { /* log $msg to file */ }
}
两个类都实现Logger
,因此必须有方法log($msg)
。你基本上是在说:“嘿,如果你想成为Logger,请确保我可以在你身上调用log()。”。现在代码中的某个地方可能有一个需要记录器的类,比如
class Foo
{
protected $logger;
public function __construct(Logger $logger)
{
$this->logger = $logger;
$this->logger->log('I can haz logger! Yay!');
}
}
Foo
并不关心它是FileLog
,DbLog
还是其他任何具体记录器。它只关心它能够任何 Logger它可以调用log()
。 Foo甚至对log()
所做的事情都不感兴趣。 Foo
所关注的所有人都可以致电log()
。你不是在界面中调用log()
。您在传递给Foo
的conrete类中调用它,但在UML图中,您表示它就像在您链接的页面中显示的那样,因为您只是针对接口进行编码
这样做的主要优点是你的课程耦合得更少。您可以更轻松地交换依赖关系,例如在单元测试中使用Mocks时,您的代码将更易于维护。
基本上,将接口视为概念标准化。例如,当你购买一台新的DVD播放器时,你希望它有一个►按钮,以某种方式(你不关心如何,只是这样)使播放器播放DVD。当你按下那个按钮时,你没有按下DVD播放器必须有播放按钮的一般抽象DVD接口规范,但你点击了这个品牌播放器上播放按钮的具体实现。