Моя цель — создать класс, который можно использовать как статический а также нестатическая путь. Оба способа должны использовать одни и те же методы, но по-разному
Нестатические путь:
$color = new Color("#fff");
$darkenColor = $color->darken(0.1);
статический путь:
$darkenColor = Color::darken("#fff", 0.1);
Так что в этом примере метода darken
может использоваться как на существующем объекте, так и в качестве статического метода Color
учебный класс. Но в зависимости от того, как он используется, он использует разные параметры.
Как должен быть такой класс предназначенный? Что такое хороший шаблон для создания таких типов классов?
Класс будет иметь много разных методов, поэтому он должен избегать массовой проверки кода в начале каждого метода.
PHP на самом деле не поддерживает перегрузку методов, так что это не так просто реализовать, но есть способы.
Зачем предоставлять статические и нестатические?
Сначала я хотел бы спросить себя, действительно ли нужно предлагать как статические, так и нестатические подходы. Это кажется слишком сложным, возможно, вводит в заблуждение пользователей вашего цветового класса, и, кажется, не добавляет столько преимуществ. Я бы просто использовал нестатический подход и покончил с этим.
Статический Фабричный Класс
В основном вам нужны статические фабричные методы, так что вы можете создать дополнительный класс, который реализует это:
class Color {
private $color;
public function __construct($color)
{
$this->color = $color;
}
public function darken($by)
{
// $this->color = [darkened color];
return $this;
}
}
class ColorFactory {
public static function darken($color, $by)
{
$color = new Color($color);
return $color->darken($by);
}
}
Альтернативой было бы поместить статический метод внутрь Color
и дать ему другое имя, например createDarken
(это должно быть одинаковым каждый раз, поэтому будут вызываться все статические фабричные методы createX
для удобства пользователя).
callStatic
Другая возможность — использовать магические методы. __call
а также __callStatic
, Код должен выглядеть примерно так:
class Color {
private $color;
public function __construct($color)
{
$this->color = $color;
}
// note the private modifier, and the changed function name.
// If we want to use __call and __callStatic, we can not have a function of the name we are calling in the class.
private function darkenPrivate($by)
{
// $this->color = [darkened color];
return $this;
}
public function __call($name, $arguments)
{
$functionName = $name . 'Private';
// TODO check if $functionName exists, otherwise we will get a loop
return call_user_func_array(
array($this, $functionName),
$arguments
);
}
public static function __callStatic($name, $arguments)
{
$functionName = $name . 'Private';
$color = new Color($arguments[0]);
$arguments = array_shift($arguments);
// TODO check if $functionName exists, otherwise we will get a loop
call_user_func_array(
array($color, $functionName),
$arguments
);
return $color;
}
}
Обратите внимание, что это немного грязно. Лично я бы не использовал этот подход, потому что он не очень хорош для пользователей вашего класса (у вас даже не может быть правильных PHPDocs). Для программиста это проще всего, потому что вам не нужно добавлять много дополнительного кода при добавлении новых функций.
По вашим примерам кода и вашим комментариям я понимаю, что ваш метод ->darken()
изменит свойство в $color
объект, основанный на текущей стоимости этого свойства. С другой стороны, статический ::darken()
метод вернет значение затемненного цвета …
Если я правильно понял, вы можете сделать что-то вроде:
class Color {
protected $value;
public static function darkenColor($value, $coef) {
$darkened = //Darken $value using $coef somehow...
return $darkened;
}
public function darken($coef) {
$darkened = Color::darkenColor($this->value, $coef);
$this->value = $darkened;
return $darkened;
}
}
При таком подходе вам не нужно повторять код потемнения цвета, и вы предлагаете как динамические, так и статические методы из класса.
Статический метод «выполняет свою работу» и может вызываться независимо, а динамический метод просто использует статический метод для выполнения вычислений и присвоения результата свойству объекта.
Обратите внимание, что вы должны использовать разные имена для методов, так как PHP не поддерживает методы перегрузки …
Тем не менее, лично я переместил бы статические методы в другой класс (ы), например, ColorManager
или же ColorCalculator
или, что еще лучше, если код для затемнения цвета достаточно сложен, и у вас будет больше подобных операций, я бы создал ColorDarkener
класс только с этим методом …
class Color {
protected $value;
public function darken($coef) {
$darkened = ColorDarkener::darken($this->value, $coef);
$this->value = $darkened;
return $darkened;
}
}
class ColorDarkener {
public static function darken($value, $coef) {
$darkened = //Darken $value using $coef somehow...
return $darkened;
}
}
Поскольку вы специально спрашиваете о дизайн:
Как должен быть разработан такой класс?
Они не должны быть.
Вы предоставляете два способа сделать то же самое точный вещь. Это почти никогда не хорошая идея. Это нарушает принцип единой ответственности, а также другие принципы SOLID.
Вместо этого держите ваш объект в состоянии и предоставьте вспомогательные функции:
class Color {
public function __construct($color) {/**/}
public function darken($by) {/**/}
}
function darken($color, $by) {
return (new Color($color))->darken($by);
}
Делать его статичным просто не нужно, поскольку PHP поддерживает первоклассные функции.
Так далеко как Шаблоны проектирования, для статических методов не существует шаблона проектирования ООП, поскольку статические методы не являются ООП. Они функциональные или процедурные. Поэтому просто используйте функцию …