oop — PHP: Как использовать расширенные интерфейсы, не нарушая принципы SOLID в этом случае?

Я очень сожалею о загадочном названии, но я, честно говоря, понятия не имею, как описать его в краткой форме в стиле заголовка.

Первая короткая версия. Простой механизм подтверждения по электронной почте. Одним из способов является отправка электронного письма со ссылкой для подтверждения. После нажатия на ссылку другой контроллер вызывает второй метод, который проверяет токен по URL. Между обоими действиями сохраняется объект ConfirmationObject с токеном и возможными другими данными. После успешного подтверждения используется «successHandler».

Упрощенный код:

interface SuccessHandlerInterface {
public function success(ConfirmationObjectInterface $object);
}

class EmailTester {
public function try(ConfirmationObjectInterface $object) {
// some code
}

public function confirm($token) {
$confirmationObject = $this->repository->findByToken($token);

$type = $confirmationObject->getType();
$successHandler = $this->handlersRegistry->getSuccessHandler($type);
$successHandler->success($confirmationObject);
}
}

Теперь мы будем использовать это так:

// Firstly let's implement our own success handler.
class UserRegistrationSuccessHandler implements SuccessHandlerInterface {
public function success(ConfirmationObjectInterface $object) {
// Do some stuff on success.
}
}

// Then let's register this success handler to be available in our `handlersRegistry` object.
$handlersRegistry->addType('user_registration', new UserRegistrationSuccessHandler());

// Now we will extend ConfirmationObjectInterface
interface RegistrationConfirmationObjectInterface extends ConfirmationObjectInterface {
public function getSomeDataGivenOnRegistration();
}

// And at the end, let's try our email

$confirmationObject = new RegistrationConfirmationObject(); // Which implements above interface.
// $confirmationObject->getType() === 'user_registration'

$emailTester->try($confirmationObject);

// Now confirmation link with token is being sent to the given email. If user will click it, below method will be invoked.
$emailTester->confirm($token);

Проблема в том, что я бы хотел иметь RegistrationConfirmationObjectInterface в доступном обработчике успеха, а не ConfirmationObjectInterface,

Я знаю, что могу сделать:

// Firstly let's implement our own success handler.
class SuccessHandler implements SuccessHandlerInterface {
public function success(ConfirmationObjectInterface $object) {
if ($object instanceof RegistrationConfirmationObjectInterface) {
// Do stuff
}
}
}

Но это плохо. Эта проверка бессмысленна как $object всегда будет примером RegistrationConfirmationObjectInterface, Как этот дизайн имеет недостатки, и как его можно улучшить?

2

Решение

Мне неясно, почему объекты подтверждения должны реализовывать два интерфейса. Из того, что я вижу здесь, RegistrationConfirmationObjectInterface имеет только один метод, который возвращает некоторую структуру данных, и ConfirmationObjectInterface не имеет методов вообще. Действительно ли здесь необходима строгая безопасность типов, особенно если вы уверены, что ваш заказ SuccessHandler получит RegistrationConfirmationObjectInterface всегда?

Если ConfirmationObjectInterface Реализации не содержат логики и являются просто структурами данных, заменяют их ассоциативными массивами. В противном случае я бы предложил что-то вроде этого:

interface ConfirmationObjectInterface
{
/**
* @return array
*/
public function getData();
}

class RegistrationConfirmationObject implements ConfirmationObjectInterface
{
public function getData()
{
return ['data specific to registration here'];
}
}

class SomethingElseConfirmationObject implements ConfirmationObjectInterface
{
public function getData()
{
return ['data specific to something else'];
}
}

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

0

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]