Php 六边形体系结构/干净代码:实现适配器模式的问题
我目前正在Symfony 2框架上编写一个小型控制台应用程序。我试图将应用程序与框架隔离(主要是在听了一些关于六边形体系结构/端口和适配器、干净的代码以及将应用程序与框架分离的有趣演讲后作为练习),以便它可以作为控制台应用程序、web应用程序运行,或者不费吹灰之力就转移到另一个框架 我遇到的问题是,我的一个接口是使用适配器模式实现的,它依赖于另一个也使用适配器模式实现的接口。这很难描述,最好用一个代码示例来描述。在这里,我用“my”作为类/接口名称的前缀,只是为了弄清楚哪些代码是我自己的(我可以编辑),哪些代码属于Symfony框架Php 六边形体系结构/干净代码:实现适配器模式的问题,php,oop,symfony,design-patterns,hexagonal-architecture,Php,Oop,Symfony,Design Patterns,Hexagonal Architecture,我目前正在Symfony 2框架上编写一个小型控制台应用程序。我试图将应用程序与框架隔离(主要是在听了一些关于六边形体系结构/端口和适配器、干净的代码以及将应用程序与框架分离的有趣演讲后作为练习),以便它可以作为控制台应用程序、web应用程序运行,或者不费吹灰之力就转移到另一个框架 我遇到的问题是,我的一个接口是使用适配器模式实现的,它依赖于另一个也使用适配器模式实现的接口。这很难描述,最好用一个代码示例来描述。在这里,我用“my”作为类/接口名称的前缀,只是为了弄清楚哪些代码是我自己的(我可以
// My code.
interface MyOutputInterface
{
public function writeln($message);
}
class MySymfonyOutputAdaptor implements MyOutputInterface
{
private $output;
public function __construct(\Symfony\Component\Console\Output\ConsoleOutput $output)
{
$this->output = $output;
}
public function writeln($message)
{
$this->output->writeln($message)
}
}
interface MyDialogInterface
{
public function askConfirmation(MyOutputInterface $output, $message);
}
class MySymfonyDialogAdaptor implements MyDialogInterface
{
private $dialog;
public function __construct(\Symfony\Component\Console\Helper\DialogHelper $dialog)
{
$this->dialog = $dialog;
}
public function askConfirmation(MyOutputInterface $output, $message)
{
$this->dialog->askConfirmation($output, $message); // Fails: Expects $output to be instance of \Symfony\Component\Console\Output\OutputInterface
}
}
// Symfony code.
namespace Symfony\Component\Console\Helper;
class DialogHelper
{
public function askConfirmation(\Symfony\Component\Console\Output\OutputInterface $output, $question, $default = true)
{
// ...
}
}
另外需要注意的是,\Symfony\Component\Console\Output\ConsoleOutput
实现了\Symfony\Component\Console\Output\OutputInterface
要符合MyDialogInterface
,MySymfonyDialogAdapter::ASKConfimation
方法必须将MyOutputInterface
的实例作为参数。但是,调用Symfony的DialogHelper::askConfirmation
方法需要一个\Symfony\Component\Console\Output\OutputInterface
实例,这意味着代码不会运行
我可以从以下两个方面来看待这一问题,但这两个方面都不是特别令人满意的:
mysymfonyoutputadapter
实现MyOutputInterface
和Symfony\Component\Console\Output\OutputInterface
。这并不理想,因为我需要指定该接口中的所有方法,而我的应用程序只关心writeln
方法mysymfonydialogadapter
假设传递给它的对象是mysymfonyoutputadapter
的实例:如果不是,则抛出异常。然后向mysymfonyoutputadapter
类添加一个方法,以获得底层的\Symfony\Component\Console\Output\ConsoleOutput
对象,该对象可以直接传递给Symfony的对话框助手::askConfirmation
方法(因为它实现了Symfony的输出接口
)。这将类似于以下内容:
class MySymfonyOutputAdaptor implements MyOutputInterface
{
private $output;
public function __construct(\Symfony\Component\Console\Output\ConsoleOutput $output)
{
$this->output = $output;
}
public function writeln($message)
{
$this->output->writeln($message)
}
public function getSymfonyConsoleOutput()
{
return $this->output;
}
}
class MySymfonyDialogAdaptor implements MyDialogInterface
{
private $dialog;
public function __construct(\Symfony\Component\Console\Helper\DialogHelper $dialog)
{
$this->dialog = $dialog;
}
public function askConfirmation(MyOutputInterface $output, $message)
{
if (!$output instanceof MySymfonyOutputAdaptor) {
throw new InvalidArgumentException();
}
$symfonyConsoleOutput = $output->getSymfonyConsoleOutput();
$this->dialog->askConfirmation($symfonyConsoleOutput, $message);
}
}
这感觉是错误的:如果MySymfonyDialogAdaptor::askConfirmation
要求其第一个参数是mysymfonyoutputadapter的实例,则它应该将其指定为其typehint,但这意味着它不再实现MyDialogInterface
。此外,在适配器外部访问底层的ConsoleOutput
对象似乎并不理想,因为它实际上应该由适配器包装编辑:此问题与以下请求中描述的问题非常相似:经过与同事的多次讨论(感谢Ian和Owen),再加上Matthias via的一些帮助,我们提出了以下解决方案:
<?php
// My code.
interface MyOutputInterface
{
public function writeln($message);
}
class SymfonyOutputToMyOutputAdaptor implements MyOutputInterface
{
private $output;
public function __construct(\Symfony\Component\Console\Output\OutputInterface $output)
{
$this->output = $output;
}
public function writeln($message)
{
$this->output->writeln($message)
}
}
class MyOutputToSymfonyOutputAdapter implements Symfony\Component\Console\Output\OutputInterface
{
private $myOutput;
public function __construct(MyOutputInterface $myOutput)
{
$this->myOutput = $myOutput;
}
public function writeln($message)
{
$this->myOutput->writeln($message);
}
// Implement all methods defined in Symfony's OutputInterface.
}
interface MyDialogInterface
{
public function askConfirmation(MyOutputInterface $output, $message);
}
class MySymfonyDialogAdaptor implements MyDialogInterface
{
private $dialog;
public function __construct(\Symfony\Component\Console\Helper\DialogHelper $dialog)
{
$this->dialog = $dialog;
}
public function askConfirmation(MyOutputInterface $output, $message)
{
$symfonyOutput = new MyOutputToSymfonyOutputAdapter($output);
$this->dialog->askConfirmation($symfonyOutput, $message);
}
}
// Symfony code.
namespace Symfony\Component\Console\Helper;
class DialogHelper
{
public function askConfirmation(\Symfony\Component\Console\Output\OutputInterface $output, $question, $default = true)
{
// ...
}
}
您可以尝试使用实现自己接口的实现,也可以扩展使用它们的symfony组件。这样,您就可以与Symfony一起实现,而无需任何额外工作。