Jeśli nie potrzebują Typ bezpieczeństwa, można użyć rodzajowe Dekorator cache:
class Cached
{
public function __construct($instance, $cacheDir = null)
{
$this->instance = $instance;
$this->cacheDir = $cacheDir === null ? sys_get_temp_dir() : $cacheDir;
}
public function defineCachingForMethod($method, $timeToLive)
{
$this->methods[$method] = $timeToLive;
}
public function __call($method, $args)
{
if ($this->hasActiveCacheForMethod($method, $args)) {
return $this->getCachedMethodCall($method, $args);
} else {
return $this->cacheAndReturnMethodCall($method, $args);
}
}
// … followed by private methods implementing the caching
Można by następnie owinąć instancji, który wymaga buforowania na ten dekorator tak:
$cachedInstance = new Cached(new Instance);
$cachedInstance->defineCachingForMethod('foo', 3600);
oczywiście $cachedInstance
nie ma metody foo()
. Sztuką jest tutaj utilize the magic __call
method to intercept all calls to inaccessible or non-existing methods i przekazanie ich do udekorowanej instancji. W ten sposób eksponujemy cały publiczny interfejs API udekorowanej instancji za pośrednictwem dekoratora.
Jak widać, metoda __call
zawiera również kod sprawdzający, czy dla tej metody istnieje buforowanie zdefiniowane. Jeśli tak, zwróci buforowane wywołanie metody. Jeśli nie, wywoła instancję i zwróci pamięć podręczną.
Alternatywnie można przekazać dedykowany element CacheBackend do programu Decorator zamiast implementować buforowanie w samym dekoratorze. Dekorator działałby wtedy jedynie jako pośrednik między udekorowanym wystrojem a zapleczem.
To ogólne podejście polega na tym, że Twój dekorator pamięci podręcznej nie będzie miał typu dekorowanej instancji.Kiedy twój kod zużywający spodziewa się wystąpienia typu Wystąpienie, dostaniesz błędy.
Jeśli potrzebujesz typu bezpieczny dekoratorów, trzeba użyć „klasyczne” podejście:
- Załóż interfejsu API urządzone instancji publicznej. Możesz to zrobić ręcznie lub, jeśli to dużo pracy, użyj mojego Interface Distiller) Zmień typ wskazań dla każdej metody, oczekując, że dekorowana instancja interfejsu będzie implementować je za pomocą Urządzonej instancji.
- Oddaj Dekorator wdrożyć go i przekazać żadnych metod do zdobionej przykład
- modyfikować wszystkie metody, które wymagają buforowania
- Powtórz dla wszystkich klas, które chcą korzystać z dekorator
w pigułce
class CachedInstance implements InstanceInterface
{
public function __construct($instance, $cachingBackend)
{
// assign to properties
}
public function foo()
{
// check cachingBackend whether we need to delegate call to $instance
}
}
Wada: wada: polega na tym, że jest to więcej pracy. Musisz to zrobić dla każdej klasy, która ma używać buforowania. Będziesz także musiał umieścić sprawdzanie w backendach pamięci podręcznej w każdej funkcji (duplikacji kodu), a także delegować wszelkie wywołania, które nie wymagają buforowania do udekorowanej instancji (nużące i podatne na błędy).
Łamie zasadę zastępowania Liskov, spójrz na projekt Proxy Manager, może pomaga, pomógł mi – decebal
@decebal Podejście używające '__call' oczywiście, ale wyraźnie wspomniałem, że nie jest to bezpieczny typ, co sugeruje. "Klasyczny" dekorator nie narusza LSP, ponieważ implementuje ten sam interfejs. – Gordon