Two implementations of the same interface and dynamic switching between them
- Honza Kuchař
- Member | 1662
Hi!
I wanted to implement Basket into simple e-shop. There is need to dynamicaly switch between Basket model implementation based on if user is logged in.
So we currently have:
IBasketStorage
|- SessionBasketStorage
|- DatabaseBasketStorage
Implementations are registered in DI container, Presenter requires IBasketStorage. Where should I put that switching logic? (e.g.: When is logged in I need to inject DatabaseStorage and when it is not I need to inject SessionStorage)
Or should I use BasketStorageFactory? How it should look like? (probably one method with boolean parameter if is logged in or not, right?)
- Filip Klimeš
- Nette Blogger | 156
In my opinion, BasketStorageFactory is the best solution for this. The factory could require Nette\Security\User which knows whether the user is logged in (isLoggedIn() method). Actually, you could use Abstract Factory pattern and the BasketStorageFactory could require SessionBasketStorageFactory and DatabaseBasketStorageFactory (these could be generated atomagically by Nette), so that the BasketStorageFactory doesn't have to require all the dependencies for the other two factories.
class BasketStorageFactory {
// .. constructor and attributes ..
public function create()
{
if($this->user->isLoggedIn() {
return $this->databaseBasketStorageFactory->create();
} else {
return $this->sessionBasketStorageFactory->create();
}
}
}
Last edited by Filip Klimeš (2015-03-05 12:20)
- David Matějka
- Moderator | 6445
Or you can create some proxy class, e.g.
class BasketStorageProxy implements IBasketStorage
{
//constructor..
public function save(...)
{
if ($this->user->isLoggedIn()) {
return $this->databaseBasketStorage->save(...);
} else {
return $this->sessionBasketStorage->save(...);
}
}
}
- Honza Kuchař
- Member | 1662
Finally we've used Service. So we were able to handle transitions from logged out state into logged in state and back.
<?php
class Service extends Object {
// ... dependencies and costructor
private $storage = null;
/**
* @return \App\Model\IStorage
*/
public function getStorage() {
if($this->storage === null){
$this->storage = $this->createStorage();
}
return $this->storage;
}
private function createStorage() {
return $this->user->loggedIn == true ? $this->databaseFactory->create() : $this->sessionFactory->create();
}
public function notifyUserLoggedIn() {
// do migration when user had logged in
}
public function notifyUserLoggedOut() {
// do migration when user had logged out
}
}
- Honza Kuchař
- Member | 1662
I think we do not need to mask underlying existence of storage class. So we've used Service class (as mentioned one post above)