P
P
phenya2015-12-04 18:08:58
PHP
phenya, 2015-12-04 18:08:58

Decorator implementing an interface, not a concrete class, is it possible?

Help break down dependencies. So, let's say we have some Repository interface:

interface Repository
{
   public function create();
   public function update();
   public function save();
}

There is an abstract class that implements this interface:
abstract class UsersRepository implements Repository
{
...
}

And there is a specific repository that works with the database
class DBUsersRepository extends UsersRepository
{
 ...
}

Moreover, the implementation is written in such a way that the create() and update() functions are associated with save() - it is common.
Further, the validation logic appears in the application, the implementation of which just wants to be done through the Decorator. If the Decorator class is inherited from DBUsersRepository, there are no problems. But this Decorator must be shared across all repositories regardless of the specific implementation:
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); 
      }
   }
}

As you can see, the decorator extends only one interface method. So the question is what to do with the rest? They should be and should work similarly to the accepted $repository, but in their own context. To client code:
$rep = new ValidationRepository( new DBUsersRepository());
    $rep->setValidator($validator);
    $rep->create($modelsData); //create() должен вызваться из UsersRepository, а функция save() в нем - уже из ValidationRepository

Worked correctly.

Answer the question

In order to leave comments, you need to log in

2 answer(s)
D
Denis, 2015-12-04
@prototype_denis

Excuse me, but from what ignoble repository does your repository take on the functions of a validator?
It's not OOP already, it's a crutch...
You need to validate (business logic) before the data gets into the repository.
And the errors below (database, etc.) should be thrown up by the repository.
The repository knows about the object only how it is stored and no more.
Do not try to cram more functionality into it than it should "pull".
The solution is more than obvious:

$rep = new ValidationRepository( new DBUsersRepository());

if ($validator->validate($modelsData)) {
    $rep->create();
} else {
    // а тут в зависимости от бизнес логики, обрабатываем ошибки.
}

Instead of crafty decorators in the "puff", use events.
They will be more flexible.

M
Mercury13, 2015-12-04
@Mercury13

So, I understood the problem (sorry, I'm a little sick, I think badly).
Before us is a clearly broken abstraction: we need to deeply embed into the object. Here is one of two.
1) Split the object into two, Repository with create() and update(), and DataStorage with save(). Then a validator can be attached as a layer between these objects.
2) Establish a point for connecting an external validator in save().
PS The decorator must implement the interface, but the set of features that it can do with this interface is small.

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question