我有以下界面:
observeSingleEvent
我的应用程序需要一个函数来生成一个链接以将用户重定向到。将来,我可能需要更改链接生成的方式。现在,这是我简单的FakeLinkGenerator:
interface LinkGeneratorInterface
{
public function generateLink();
}
但是,如果将来我的链接生成需要额外的参数,那该怎么办呢?采取以下示例
class FakeLinkGenerator implements LinkGeneratorInterface
{
public function generateLink()
{
return "https://stackoverflow.com";
}
}
这需要我更改界面,这会使编码的目的失效。如果我有这个函数依赖于这个抽象class RealLinkGenerator implements LinkGeneratorInterface
{
public function generateLink($parameter)
{
// business logic with $parameter
return "https://stackoverflow.com"; // may append stuff depending on my business logic
}
}
:
LinkGeneratorInterface
我也必须改变这个实现。我希望能够为此函数指定不同的public function getLink(LinkGeneratorInterface $generator)
{
return $generator->generateLink();
}
。
注意:我的链接生成可能依赖于用户输入,因此不能通过构造函数注入参数。
答案 0 :(得分:1)
但是,如果将来我的链接生成需要额外的参数,那该怎么办呢?采取以下示例
然后您创建新方法,或者以破坏向后兼容性为代价更改您的界面。由您来决定哪种方式对您有用。
使编码的目的失败
你误解了界面的概念 - 它不是一个不可改变的具体块。您可以根据需要在需要时更改它。如果您认为您经常更改它,那么您的软件设计可能会有些不稳定 因为你根本没有预见到你的界面应该帮助定义的太多东西。
答案 1 :(得分:0)
这里有几个选项:
脏(我认为)这样做的方法是使用可选参数:
class FakeLinkGenerator implements LinkGeneratorInterface
{
public function generateLink($param = 'defaultValue')
{
return "https://stackoverflow.com/$param";
}
}
这将通过界面验证,并允许您在创建实现时具有很大的灵活性。当有效地使用合理的默认值时,这非常有用。什么使它小于可选是当参数不是可选的,我们只使用这个技巧来通过验证。这会导致额外的开销(此可选参数不是可选的)并且更有可能导致问题。
一种更简洁的方法,更简洁,因为我们保持方法签名不变,是从具体类构造函数中注入参数并在实现方法中使用它:
class FakeLinkGenerator implements LinkGeneratorInterface
{
private $param;
public function __construct($param) { $this->param = $param; }
public function generateLink()
{
return "https://stackoverflow.com/{$this->param}";
}
}
这是我首选的方法。从理论上讲,这也是一种有效的方式;接口应该定义成员,通过该成员我们与对象通信,将实现细节留给所述对象。理想情况下,我们不应该在构造函数中工作。由于这些原因,我们可以提出一个软规则,不在界面中定义构造函数的参数,让我们可以自由地使用这种方法。