Допустим, у нас есть Dog
класс и Category
класс, к которому могут быть отнесены собаки.
class Dog {
function categories() {} // Return the categories of the dog.
}
class Category {
function dogs() {} // Return the dogs under this category.
}
Собаки могут иметь категории «домашнее животное» и «овчарка». При присвоении категории «домашнее животное» это «домашняя собака», и то же самое относится и к «пастуху».
Собаки и овчарки имеют разные атрибуты и функции. Однако собака может быть как «собакой», так и «овчаркой».
Я могу представить себе разные интерфейсы для «любимой собаки» и «овчарки», например
interface Huggable {
function hug()
}
interface Trainable {
function train()
}
В идеале, когда собака относится к категории «домашние животные», она реализует Huggable
интерфейс, если он относится к категории «пастух», он реализует Trainable
категория.
Является ли это возможным?
Как я уже говорил, это невозможно реализовать с помощью PHP.
Но вы можете реализовать что-то, например, с помощью декораторов.
Глупый декоратор подход:
У вас будет класс, который будет украшен:
class Animal {
protected $categories = [];
public function getCategories() {
return $this->categories;
}
public function addCategory( string $category ) {
// we should check the animal doesn't already belong to this category
$this->categories[] = $category;
}
}
Ваши интерфейсы, Trainable
а также Huggable
:
interface Trainable {
function train();
}
interface Huggable {
// see https://github.com/php-fig/fig-standards/blob/master/proposed/psr-8-hug/psr-8-hug.md
function hug() : bool;
}
Один декоратор, который реализует Trainable и добавляет конкретную категорию к оформленному экземпляру:
class PetDecorator extends Animal implements Trainable {
public function __construct( Animal $animal ) {
$this->categories = $animal->getCategories();
$this->addCategory('pet');
}
public function train() {
echo "I'm housebroken!\n";
}
}
И другой FluffyDecorator
который реализует Huggable
class FluffyDecorator extends Animal implements Huggable {
public function __construct( Animal $animal ) {
$this->categories = $animal->getCategories();
$this->addCategory('loveBear');
}
public function hug( ) :bool {
echo "Much hug!\n";
return true;
}
}
Наконец, вы бы использовали это так:
$fido = new Animal();
$fidoPet = new PetDecorator($fido);
$fidoPet->train();
// I'm housebroken!
print_r($fidoPet->getCategories());
/*
Array
(
[0] => pet
)
*/
$fidoLove = new FluffyDecorator($fidoPet);
// Much hug!
$fidoLove->hug();
print_r($fidoLove->getCategories());
/*
Array
(
[0] => pet
[1] => loveBear
)
*/
Отношения «многие ко многим» между «Собаками» и «Категориями» я оставляю на ваше усмотрение. Это отдельная проблема и может быть решена различными способами.
Других решений пока нет …