POZOR! Článek jsem napsal před více jak rokem, a tudíž už nemusí reflektovat můj nynější názor nebo může být zastaralý.
Video (1:29)
Princip odděleného rozhraní je definované Robertem C. Martinem původně pro Xerox a říká:
Více specifických rozhraní je lepší než jedno obecné rozhraní.
Při jeho dodržování se kód stává více znovupoužitelný a užitečný. Pokud je více tříd nuceno implementovat rozhraní s metodami, které nepotřebují, je vhodné najít logický průnik (v čem se shodují) a rozhraní oddělit.
Na ukázku zde mám rozhraní IBag, třídu Bag, která jej implementuje a třídu Renderer:
<?php
interface IBag {
public function setContent(string $content);
public function appendContent(string $content);
public function prependContent(string $content);
public function getContent(string $content);
public function loadFromFile(string $file);
public function saveToFile(string $file);
public function render(): string;
}
class Bag implements IBag
{
private $content;
public function setContent(string $content)
{
$this->content = $content;
}
public function appendContent(string $content)
{
$this->content = $this->content . $content;
}
public function prependContent(string $content)
{
$this->content = $content . $this->content;
}
public function getContent(string $content)
{
return $content;
}
public function loadFromFile(string $file)
{
if (!file_exists($file)) {
throw new InvalidArgumentException("File from argument not exists.");
}
$this->content = file_get_contents($file);
}
public function saveToFile(string $file)
{
if (!file_exists($file)) {
throw new InvalidArgumentException("File from argument not exists.");
}
return file_put_contents($file, $this->content);
}
public function render(): string
{
return "Content: " . $this->content;
}
}
class Renderer
{
public function render(IBag $bag)
{
echo $bag->render();
}
}
Větší interface IBag mohu rozdělit na tři logické rozhraní: Contentable, Fileable, Renderable.
Třída Renderer tak už není nucena záviset na IBag, ale postačí Renderable. Třída Bag implementuje všechny tři rozhraní, ale další třídě může stačit už jenom třeba jedno.
<?php
interface Renderable {
public function render(): string;
}
interface Contentable
{
public function setContent(string $content);
public function appendContent(string $content);
public function prependContent(string $content);
public function getContent(string $content);
}
interface Fileable
{
public function loadFromFile(string $file);
public function saveToFile(string $file);
}
class Bag implements Renderable, Contentable, Fileable
{
private $content;
public function setContent(string $content)
{
$this->content = $content;
}
public function appendContent(string $content)
{
$this->content = $this->content . $content;
}
public function prependContent(string $content)
{
$this->content = $content . $this->content;
}
public function getContent(string $content)
{
return $content;
}
public function loadFromFile(string $file)
{
if (!file_exists($file)) {
throw new InvalidArgumentException("File from argument not exists.");
}
$this->content = file_get_contents($file);
}
public function saveToFile(string $file)
{
if (!file_exists($file)) {
throw new InvalidArgumentException("File from argument not exists.");
}
return file_put_contents($file, $this->content);
}
public function render(): string
{
return "Content: " . $this->content;
}
}
class Renderer
{
public function render(Renderable $bag)
{
echo $bag->render();
}
}
Jako u všech zásad je potřeba dbát na to, aby to nebylo přehnané. Aby nás pak nestrašily třídy se stovkou rozhraní. :)
Zdroje:
https://web.archive.org/web/20150906155800/http://www.objectmentor.com/resources/articles/Principles_and_Patterns.pdf
Znáte někoho, komu by článek mohl pomoct? Zasdílejte mu ho :)