【问题标题】:What is a good PHP design (pattern?) for my testing-application?对于我的测试应用程序来说,什么是好的 PHP 设计(模式?)?
【发布时间】:2010-03-02 08:32:49
【问题描述】:

我想编写一个 simple 类 (PHP5),它可以“运行”未知数量的子类。这些子类最好翻译为“检查”;他们或多或少都会做同样的事情并给出答案(真/假)。将其视为系统启动检查。

随着时间的推移,新的检查(子类)将被添加到目录中,并且它们应该在调用主类时自动运行。其他人可能会写支票,但他们必须遵循主类规定的功能。

什么是构建这个的干净而简单的方法? 我找到了工厂模式并结合界面,这似乎是一个很好的起点。不过我不确定,我会很感激这方面的建议。

编辑:这里提供的答案都有效,但是 Gordon 的答案提供了批次和堆叠的其他可能性,这是我在询问时没有想到的,但现在我很高兴。

【问题讨论】:

    标签: php interface frameworks design-patterns factory


    【解决方案1】:

    如果您想创建类似批处理的功能,请使用Command Pattern。

    下面是该模式的一个非常简单的实现。这个想法是为您要调用的所有类提供统一的接口。每个类在批处理中封装一个操作:

    interface BatchCommand
    {
        public function execute();
        public function undo();
    }
    

    一个实现接口的类将是所有子类的指挥官:

    class BatchCommander implements BatchCommand
    {
        protected $commands;
    
        public function add(BatchCommand $command)
        {
            $this->commands[] = $command;
        }
        public function execute()
        {
            foreach($this->commands as $command) {
                $command->execute();
            }
        }
        public function undo()
        {
            foreach($this->commands as $command) {
                $command->undo();
            }
        }
    }
    

    一个简单的命令可能如下所示:

    class FileRename implements BatchCommand
    {
        protected $src;
        protected $dest;
    
        public function __construct($src, $dest)
        {
            $this->$src;
            $this->dest;
        }
    
        public function execute()
        {
            rename($this->src, $this->dest);
        }
    
        public function undo()
        {
            rename($this->dest, $this->src);
        }
    }
    

    你可以这样使用它:

    $commander = new BatchCommander;
    $commander->add(new FileRename('foo.txt', 'bar.txt'));
    $commander->add(/* other commands */);
    $commander->execute();
    

    因为 BatchCommander 本身就是一个 BatchCommand,您可以轻松地将属于一起的批次堆叠到其他批次中,从而创建一个非常灵活的树形结构,例如

    $batch1 = new BatchCommander;
    $batch1->add(/* some command */);
    $batch1->add(/* some other command */);
    
    $batch2 = new BatchCommander;
    $batch2->add(/* some command */);
    $batch2->add(/* some other command */);
    
    $main = new BatchCommander;
    $main->add($batch1);
    $main->add($batch2);
    $main->execute();
    

    在您的检查/测试上下文中,这意味着您可以将概念上属于的单个测试分组到一个测试套件中。您可以通过将一个套件堆叠到另一个套件中来创建测试套件的测试套件。

    当然,您也可以为 BatchCommander 提供一个文件路径来检查实例化,并通过运行文件路径中的文件让它初始化所有 BatchCommands。或者传递一个 Factory 实例用于创建 Check 命令。

    您不必为方法名称使用execute 和undo。如果需要,请将其命名为 check。如果您不需要,请忽略 undo。但是基本思想仍然保持不变:一个接口用于所有类的命令,无论它看起来像什么。随意适应。

    一个略有不同的 UseCase 的替代方案是Chain of Reponsibility 模式。看看它是否也有用。

    【讨论】:

    • 感谢您的回答。我不完全理解的东西;你写了一个实现接口的类将是指挥官,然后用public function BatchCommander implements BatchCommand开始代码是错字还是我误解了原理?
    • @Matt 这是故意的。 BatchCommander 命令所有 BatchCommands,但它本身也是一个命令。这允许您通过将 BatchCommand 分组到 BatchCommander 中来创建任意树结构。我将更新帖子作为示例。
    • 再次感谢 Gordon,感谢您的时间和补充。我确实错过了我现在掌握的要点(分组和堆叠)(我对此感到兴奋:))但是,我仍然不明白在哪里 invoke public function batchCommander 据我(确实是有限的)知识,这是一种方法,它应该存在于一个类中,但是哪个类呢?如果我使用您的示例,我会收到关于 public function 行 nr. 的 Parse error: syntax error, unexpected T_PUBLIC 错误
    • @Matt Gah!我的错。当然应该是class BatchCommander。对不起。
    • @Gordon:命令模式非常强大,但也许在真正需要所有灵活性之前,您不必走这条路。我在想 YAGNI。
    【解决方案2】:

    我想这里的问题是如何找到应该实例化和运行的类,因为您需要知道类的名称。

    我建议您加载目录中的每个 *.php 文件并使用简单的命名约定。例如,文件的名称(减去扩展名)是类的名称。然后就:

     // foreach $file in glob("*.php"):
        $classname = basename($file, ".php");
        $instance = new $classname(); 
        $result = $instance->runCheck();
    

    runCheck() 是每个类必须提供的实际方法。

    您没有说任何关于以任何特定顺序运行检查的内容,但这可以通过为每个文件添加 nn_ 前缀并按顺序加载它们来解决。例如05_CheckFoo.php。

    【讨论】:

    • 这有点低效。如果文件遵循命名模式(如您所建议的),例如01_individual-filename.checkcommand.php,他可以更好地做glob('*.checkcommand.php'),而不是遍历所有文件。
    • 已修复,虽然我不认为剃掉几毫秒是这里的问题 :)
    【解决方案3】:

    检查类自动加载,因此您不必关心存在多少子类。 PHP 将接管一切: http://php.net/manual/en/language.oop5.autoload.php

    【讨论】:

    • 您仍然需要知道要加载的类的实际名称,为此您仍然需要检查现有文件(或维护单独的类列表)。
    猜你喜欢
    • 1970-01-01
    • 2015-03-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-12-22
    • 2011-05-15
    相关资源
    最近更新 更多