- Java 双重比较
- java - 比较器与 Apache BeanComparator
- Objective-C 完成 block 导致额外的方法调用?
- database - RESTful URI 是否应该公开数据库主键?
我目前正在 Symfony 2 框架上编写一个小型控制台应用程序。我正在尝试将应用程序与框架隔离开来(主要是在听过一些关于六边形架构/端口和适配器、清洁代码以及将应用程序与框架解耦的有趣演讲后作为练习),以便它可以作为控制台应用程序运行,一个 Web 应用程序,或者毫不费力地迁移到另一个框架。
我遇到的问题是当我的一个接口(interface)是使用适配器模式实现的,它依赖于另一个也使用适配器模式实现的接口(interface)。这很难描述,最好用代码示例来描述。在这里,我在我的类/接口(interface)名称前加上“我的”前缀,只是为了清楚哪些代码是我自己的(我可以编辑)哪些属于 Symfony 框架。
// 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
,MySymfonyDialogAdaptor::askConfirmation
方法必须将MyOutputInterface
的实例作为参数。但是,对 Symfony 的 DialogHelper::askConfirmation
方法的调用需要 \Symfony\Component\Console\Output\OutputInterface
的实例,这意味着代码不会运行。
我可以看到几种解决方法,但都不是特别令人满意:
让 MySymfonyOutputAdaptor
实现 MyOutputInterface
和 Symfony\Component\Console\Output\OutputInterface
。这并不理想,因为我需要指定该接口(interface)中的所有方法,而我的应用程序只真正关心 writeln
方法。
让 MySymfonyDialogAdaptor
假定传递给它的对象是 MySymfonyOutputAdaptor
的实例:如果不是,则抛出异常。然后在MySymfonyOutputAdaptor
类中添加一个方法获取底层的\Symfony\Component\Console\Output\ConsoleOutput
对象,可以传递给Symfony的DialogHelper::直接 askConfirmation
方法(因为它实现了 Symfony 的 OutputInterface
)。这看起来像下面这样:
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
要求它的第一个参数是 MySymfonyOutputAdaptor 的一个实例,它应该指定它作为它的类型提示,但这意味着它不再实现 我的对话框界面
。此外,在其自己的适配器之外访问底层 ConsoleOutput
对象似乎并不理想,因为它实际上应该由适配器包装。
谁能提出解决这个问题的方法?我觉得我错过了一些东西:也许我把适配器放在了错误的地方,而不是多个适配器,我只需要一个适配器来包装整个输出/对话系统?或者我可能需要包含另一个继承层才能实现这两个接口(interface)?
感谢任何建议。
编辑:此问题与以下拉取请求中描述的问题非常相似:https://github.com/SimpleBus/CommandBus/pull/2
最佳答案
经过与同事的大量讨论(感谢 Ian 和 Owen),加上 Matthias 通过 https://github.com/SimpleBus/CommandBus/pull/2 提供的一些帮助,我们提出了以下解决方案:
<?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 的代码,反之亦然)并且我需要另一个单独的适配器来从 MyOutputInterface
转换回Symfony 的 OutputInterface
类。
这并不完全理想,因为我仍然需要在这个新适配器 (MyOutputToSymfonyOutputAdapter
) 中实现所有 Symfony 的方法,但是这个架构确实感觉结构很好,因为很明显每个适配器都在一个方向上转换:我相应地重命名了适配器以使其更清楚。
另一种选择是只完全实现我想要支持的方法(在这个例子中只是writeln
)并定义其他方法来抛出异常以指示适配器不支持它们如果他们被称为。
非常感谢大家的帮助。
关于php - 六边形架构/干净代码 : Problems implementing adaptor pattern,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26699118/
我在 JavaScript 文件中运行 PHP,例如...... var = '';). 我需要使用 JavaScript 来扫描字符串中的 PHP 定界符(打开和关闭 PHP 的 )。 我已经知道使
我希望能够做这样的事情: php --determine-oldest-supported-php-version test.php 并得到这个输出: 7.2 也就是说,php 二进制检查 test.
我正在开发一个目前不使用任何框架的大型 php 站点。我的大问题是,随着时间的推移慢慢尝试将框架融入应用程序是否可取,例如在创建的新部件和更新的旧部件中? 比如所有的页面都是直接通过url服务的,有几
下面是我的源代码,我想在同一页面顶部的另一个 php 脚本中使用位于底部 php 脚本的变量 $r1。我需要一个简单的解决方案来解决这个问题。我想在代码中存在的更新查询中使用该变量。 $name)
我正在制作一个网站,根据不同的情况进行大量 PHP 重定向。就像这样...... header("Location: somesite.com/redirectedpage.php"); 为了安全起见
我有一个旧网站,我的 php 标签从 因为短标签已经显示出安全问题,并且在未来的版本中将不被支持。 关于php - 如何避免在 php 文件中写入
我有一个用 PHP 编写的配置文件,如下所示, 所以我想用PHP开发一个接口(interface),它可以编辑文件值,如$WEBPATH , $ACCOUNTPATH和 const值(value)观
我试图制作一个登录页面来学习基本的PHP,首先我希望我的独立PHP文件存储HTML文件的输入(带有表单),但是当我按下按钮时(触发POST到PHP脚本) )我一直收到令人不愉快的错误。 我已经搜索了S
我正在寻找一种让 PHP 以一种形式打印任意数组的方法,我可以将该数组作为赋值包含在我的(测试)代码中。 print_r 产生例如: Array ( [0] => qsr-part:1285 [1]
这个问题已经有答案了: 已关闭11 年前。 Possible Duplicate: What is the max key size for an array in PHP? 正如标题所说,我想知道
我正在寻找一种让 PHP 以一种形式打印任意数组的方法,我可以将该数组作为赋值包含在我的(测试)代码中。 print_r 产生例如: Array ( [0] => qsr-part:1285 [1]
关闭。这个问题需要多问focused 。目前不接受答案。 想要改进此问题吗?更新问题,使其仅关注一个问题 editing this post . 已关闭 9 年前。 Improve this ques
我在 MySQL 数据库中有一个表,其中存储餐厅在每个工作日和时段提供的菜单。 表结构如下: i_type i_name i_cost i_day i_start i_
我有两页。 test1.php 和 test2.php。 我想做的就是在 test1.php 上点击提交,并将 test2.php 显示在 div 中。这实际上工作正常,但我需要向 test2.php
我得到了这个代码。我想通过textarea更新mysql。我在textarea中回显我的MySQL,但我不知道如何更新它,我应该把所有东西都放进去吗,因为_GET模式没有给我任何东西,我也尝试_GET
首先,我是 php 的新手,所以我仍在努力学习。我在 Wordpress 上创建了一个表单,我想将值插入一个表(data_test 表,我已经管理了),然后从 data_test 表中获取所有列(id
我有以下函数可以清理用户或网址的输入: function SanitizeString($var) { $var=stripslashes($var); $va
我有一个 html 页面,它使用 php 文件查询数据库,然后让用户登录,否则拒绝访问。我遇到的问题是它只是重定向到 php 文件的 url,并且从不对发生的事情提供反馈。这是我第一次使用 html、
我有一个页面充满了指向 pdf 的链接,我想跟踪哪些链接被单击。我以为我可以做如下的事情,但遇到了问题: query($sql); if($result){
我正在使用 从外部文本文件加载 HTML/PHP 代码 $f = fopen($filename, "r"); while ($line = fgets($f, 4096)) { print $l
我是一名优秀的程序员,十分优秀!