Принцип разделения интерфейса: как разделить большой интерфейс с помощью множества дополнительных методов

Допустим, у меня есть интерфейс:

interface WorkerInterface
{
    public function doCommonAction1(CommonAction1Params $params): CommonAction1Result;

    public function doCommonAction2(CommonAction2Params $params): CommonAction2Result;

    /**
     * @return void
     *
     * @throws UnsupportedMethodException
     */
    public function doSpecificAction1(SpecificAction1Params $params): SpecificAction1Result;

    /**
     * @return void
     *
     * @throws UnsupportedMethodException
     */
    public function doSpecificAction2(SpecificAction2Params $params): SpecificAction2Result;
}

Проблема в том, что методы doSpecificAction1 и doSpecificAction2являются необязательными и поддерживаются не всеми работниками. Работник может поддержать doCommonAction1 и doCommonAction2 только, а также doCommonAction1, doCommonAction2 и doSpecificAction1, или же doCommonAction1, doCommonAction2, doSpecificAction2, или все методы вместе.

Также у меня есть WorkerFactory:

class WorkerFactory
{
    public function createWorker(string $workerId): WorkerInterface
    {
        // worker is created here
    }
}

Тогда у меня есть контроллер:

class ActionController {
    public function commonAction1(string $workerId, WorkerFactory $factory)
    {
        $worker = $factory->createWorker($workerId);

        $worker->doCommonAction1(new CommonAction1Params());
    }

    public function commonAction2(string $workerId, WorkerFactory $factory)
    {
        $worker = $factory->createWorker($workerId);

        $worker->doCommonAction2(new CommonAction2Params());
    }

    public function specificAction1(string $workerId, WorkerFactory $factory)
    {
        $worker = $factory->createWorker($workerId);

        try {
            $worker->doSpecificAction1(new SpecificAction1Params());
        } catch (UnsupportedMethodException $e) {
            // do something
        }
    }

    public function specificAction2(string $workerId, WorkerFactory $factory)
    {
        $worker = $factory->createWorker($workerId);

        try {
            $worker->doSpecificAction2(new SpecificAction2Params());
        } catch (UnsupportedMethodException $e) {
            // do something
        }
    }
}

Очевидно, что теперь мой код нарушает принцип разделения интерфейса. Я бы хотел его реорганизовать. Хорошо, я пытаюсь сделать что-то вроде этого:

interface WorkerInterface
{
    public function doCommonAction1(CommonAction1Params $params): CommonAction1Result;

    public function doCommonAction2(CommonAction2Params $params): CommonAction2Result;
}

interface SpecificAction1AwareInterface
{
    public function doSpecificAction1(SpecificAction1Params $params): SpecificAction1Result;
}

interface SpecificAction2AwareInterface
{
    public function doSpecificAction2(SpecificAction2Params $params): SpecificAction2Result;
}

Итак, теперь мои рабочие будут выглядеть так:

class Worker1 implements WorkerInterface {}

class Worker2 implements WorkerInterface, SpecificAction1AwareInterface {}

class Worker3 implements WorkerInterface, SpecificAction1AwareInterface, SpecificAction2AwareInterface {}

И теперь мой контроллер меняется на это:

class ActionController {
    public function commonAction1(string $workerId, WorkerFactory $factory)
    {
        $worker = $factory->createWorker($workerId);

        $worker->doCommonAction1(new CommonAction1Params());
    }

    public function commonAction2(string $workerId, WorkerFactory $factory)
    {
        $worker = $factory->createWorker($workerId);

        $worker->doCommonAction2(new CommonAction2Params());
    }

    public function specificAction1(string $workerId, WorkerFactory $factory)
    {
        $worker = $factory->createWorker($workerId);

        if ($worker instanceof SpecificAction1AwareInterface) {
            $worker->doSpecificAction1(new SpecificAction1Params());
        } else {
            // do something
        }
    }

    public function specificAction2(string $workerId, WorkerFactory $factory)
    {
        $worker = $factory->createWorker($workerId);

        if ($worker instanceof SpecificAction2AwareInterface) {
            $worker->doSpecificAction1(new SpecificAction2Params());
        } else {
            // do something
        }
    }
}

Но я думаю, что этот код кажется некрасивым. Я не уверен, что использование instanceof - хорошая идея, особенно потому, что SpecificAction1AwareInterface и SpecificAction2AwareInterface не связаны с WorkerInterface вообще.

Так есть ли какие-нибудь шаблоны проектирования, подходящие для моей ситуации? Заранее спасибо.

0 ответов

Другие вопросы по тегам