In alcuni pacchetti di alto livello (che non possiedo) ho un'interfaccia di instradamento.
Ora questa interfaccia Route contiene i dettagli per una rotta specifica all'interno del mio sistema. Il pacchetto di alto livello non contiene un metodo per aggiungere get
parametri al percorso, come /customers?a=b
.
class CustomerRoute extends BaseRoute implements RouteInterface
{
public function __construct()
{
$this->setController(CustomerController::class);
$this->setAction('index');
$this->setUrl('/customers');
$this->setType('get');
}
}
Voglio aggiungere un altro metodo; setGetParameters
come per esempio in una nuova classe base:
public function setGetParameters(array $parameters)
{
$this->parameters = $parameters;
$this->setUrl($this->getUrl() . $this->buildQueryString($parameters));
}
protected function buildQueryString(array $parameters)
{
return '?' . http_build_query($parameters);
}
Ma ciò violerebbe il Principio di sostituzione di Liskov. Se creo una dipendenza su RouteInterface
, potrei non accedere a setGetParameters
.
Come:
$route->setGetParameters([
'a'=>'b'
]);
$route->getUrl();
Qual è il modo migliore per andare?
Ho preso in considerazione:
Modello adattatore (oggetto)
Ti piace così?
class RouteAdapter implements Contracts\RouteAdapter
{
protected $route;
public function __construct(RouteInterface $route)
{
$this->route = $route;
}
public function setGetParameters(array $parameters)
{
$this->parameters = $parameters;
}
//the route methods
public function getUrl()
{
$this->route->getUrl() . '?' . http_build_query($this->parameters);
}
//... other methods from route
}
Schema decoratore
Ma con decoratore (ereditarietà) l'interfaccia del percorso non può cambiare.
Vistor
Ma il visitatore è meglio utilizzato per diversi tipi di classi.
Che cosa faresti se non fosse il proprietario del pacchetto di alto livello e cosa faresti se lo facessi?
Cambieresti la classe base per aggiungere i metodi e anche cambiare la RouteInterface?
Aggiornamento 1
Estendere l'interfaccia a una soluzione?
Questo potrebbe non essere un modello di design specifico.
Così:
class Route extends NewAbstractRoute
{
//...
}
abstract class RouteInterface //the original interface
{
//....
}
abstract class NewAbstractRoute extends RouteInterface
{
public function setGetParameters(array $parameters);
}
class Implementation extends NewAbstractRoute
{/*..*/}
In questo modo non violerebbe il principio substition Liskov per il pacchetto e posso fare una dipendenza alla nuova interfaccia.
Ma questa soluzione potrebbe non essere buona dal momento che è meglio non usare l'ereditarietà per aggiungere metodi, dal momento che potrebbe crea troppi sottosistemi.