Decorator реализующий интерфейс, а не конкретный класс, возможно ли? Помогите разрулить зависимости. Итак, допустим у нас есть некий интерфейс Repository:interface Repository { public function create(); public function update(); public function save(); } Есть абстрактный класс реализующий этот интерфейс:abstract class UsersRepository implements Repository { ... } И есть конкретный репозиторий, работающий с БДclass DBUsersRepository extends UsersRepository { ... } Причем реализация написана таким образом, что ф-ии creatе() и update() связаны с save() - она общая. Дальше в приложении появляется логика валидации, внедрение которой как раз и хочется сделать через Декоратор. В случае если класс Декоратора наследовать от DBUsersRepository - проблем никак нет. Но этот Декоратор должен быть общим для всех репозиториев независимо от конкретной реализации:class ValidationRepository implements Repository { protected $repository; protected $validator; public function __construct(Repository $repository) { $this->repository = $repository; } public function setValidator(Validator $validator) { $this->validator = $validator; return $this; } public function save($model) { if($this->validator->validate($model)){ return $this->repository->save($model); } } } Как видно декоратор расширяет только один метод интерфейса. Отсюда вопрос, что делать с остальными? Они должны быть и работать должны аналогично принимаемого $repository, но в собственном контексте. Чтобы клиентский код:$rep = new ValidationRepository( new DBUsersRepository()); $rep->setValidator($validator); $rep->create($modelsData); //create() должен вызваться из UsersRepository, а функция save() в нем - уже из ValidationRepository Отрабатывал корректно.
Для того чтобы декоратор работал корректно и для остальных методов интерфейса Repository, необходимо в классе ValidationRepository также реализовать эти методы, которые необходимо расширить или оставить без изменений.
Примерно таким образом можно реализовать декоратор для остальных методов интерфейса Repository:
class ValidationRepository implements Repository { protected $repository; protected $validator; public function __construct(Repository $repository) { $this->repository = $repository; } public function setValidator(Validator $validator) { $this->validator = $validator; return $this; } public function create($model) { return $this->repository->create($model); } public function update($model) { return $this->repository->update($model); } public function save($model) { if($this->validator->validate($model)){ return $this->repository->save($model); } } }
Таким образом, в декораторе ValidationRepository реализованы все методы интерфейса Repository, для которых необходимо использовать дополнительную логику валидации. Клиентский код, использующий данный декоратор, будет также работать корректно с остальными методами интерфейса Repository.
Для того чтобы декоратор работал корректно и для остальных методов интерфейса Repository, необходимо в классе ValidationRepository также реализовать эти методы, которые необходимо расширить или оставить без изменений.
Примерно таким образом можно реализовать декоратор для остальных методов интерфейса Repository:
class ValidationRepository implements Repository{
protected $repository;
protected $validator;
public function __construct(Repository $repository)
{
$this->repository = $repository;
}
public function setValidator(Validator $validator)
{
$this->validator = $validator;
return $this;
}
public function create($model)
{
return $this->repository->create($model);
}
public function update($model)
{
return $this->repository->update($model);
}
public function save($model)
{
if($this->validator->validate($model)){
return $this->repository->save($model);
}
}
}
Таким образом, в декораторе ValidationRepository реализованы все методы интерфейса Repository, для которых необходимо использовать дополнительную логику валидации. Клиентский код, использующий данный декоратор, будет также работать корректно с остальными методами интерфейса Repository.