Что такое хороший дизайн PHP (шаблон?) Для моего тестового приложения? - PullRequest
1 голос
/ 02 марта 2010

Я хочу написать простой класс (PHP5), который может «запускать» неизвестное количество подклассов. Эти подклассы лучше всего переводить как «проверки»; все они более или менее сделают одно и то же и дадут ответ (истина / ложь). Думайте об этом как о проверке запуска системы.

Со временем новые проверки (подклассы) будут добавлены в каталог, и они должны запускаться автоматически при вызове основного класса. Другие могут писать чеки, но им придется следовать функциям, продиктованным основным классом.

Каким будет простой, но простой способ построить это? Я нашел шаблон Factory и в сочетании с интерфейсом он кажется хорошей отправной точкой. Однако я не уверен, и я был бы признателен за совет по этому поводу.

РЕДАКТИРОВАТЬ: все приведенные здесь ответы работают, однако ответ Гордона дает дополнительные возможности для группирования и укладки, о чем я не думал во время запроса, но сейчас я весьма доволен.

Ответы [ 3 ]

3 голосов
/ 02 марта 2010

Если вы хотите создать пакетную функциональность, используйте Шаблон команды .

Ниже приведена очень простая реализация шаблона. Идея состоит в том, чтобы иметь унифицированный интерфейс для всех классов, которые вы хотите вызвать. Каждый класс инкапсулирует одну операцию в пакете:

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, который будет использоваться для создания команд проверки.

Вам не нужно иметь execute и undo для имен методов. Назовите это check, если хотите. Оставьте undo, если вам это не нужно. Тем не менее, основная идея остается неизменной: один интерфейс для всех команд, независимо от того, как это выглядит. Не стесняйтесь адаптироваться.

Альтернативой с несколько другим UseCase является шаблон Chain of Reponsibility . Проверьте это, чтобы увидеть, будет ли это также полезно.

1 голос
/ 02 марта 2010

Полагаю, проблема в том, как найти классы, которые вы должны создать и запустить, поскольку вам нужно знать имя класса.

Я предлагаю вам загрузить каждый * .php файл в каталог и использовать простое соглашение об именах. Например, имя файла (без расширения) - это имя класса. Тогда просто:

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

Где runCheck() - фактический метод, который должен предоставить каждый класс.

Вы ничего не сказали о запуске проверок в каком-либо конкретном порядке, но это можно исправить, добавив префикс nn_ к каждому файлу и загрузив их по порядку. Например 05_CheckFoo.php.

0 голосов
/ 02 марта 2010

Проверьте автозагрузку классов, чтобы вам не приходилось заботиться о том, сколько существует подклассов. PHP возьмет все: http://php.net/manual/en/language.oop5.autoload.php

...