Можно ли так у конструктора задавать параметры и не противоречит ли это принципу Барбары Лисков?
Всем привет.
Погружаюсь в ООП и возник вопрос по созданию дочернего класса.
Есть родительский класс
class Animal { public function __construct( public string $name, public int $health, public int $power, public bool $alive = true ) { } public function calcDamage() { return $this->power * (mt_rand(100, 300) / 200); } public function applyDamage(int $damage) { $this->health -= $damage; if($this->health <= 0) { $this->health = 0; $this->alive = false; } } } |
class Animal { public function __construct( public string $name, public int $health, public int $power, public bool $alive = true ) { } public function calcDamage() { return $this->power * (mt_rand(100, 300) / 200); } public function applyDamage(int $damage) { $this->health -= $damage; if($this->health <= 0) { $this->health = 0; $this->alive = false; } } }
Я от него наследуюсь и создаю следующий класс
class Mouse extends Animal { private float $hiddenLevel; public function __construct( public string $name, public int $health, public int $power ) { parent::__construct(name: $name, health: $health, power: $power); $this->hiddenLevel = 0.4; } } |
class Mouse extends Animal { private float $hiddenLevel; public function __construct( public string $name, public int $health, public int $power ) { parent::__construct(name: $name, health: $health, power: $power); $this->hiddenLevel = 0.4; } }
И вот тут у меня вопрос на счет конструкторов родителя и дочернего класса. Принцип Барбары Лисков гласит, что родитель может быть замещен ребенком без потери работоспособности кода (надеюсь я правильно понял этот принцип). И как я понимаю, конструктор ребенка должен совпадать с конструктором родителя.
Используя новшества PHP8 решил в конструкторе сразу же сделать присвоение параметров и последний параметр у меня необязательный. И тут у меня вопрос, надо ли согласно принципу Лисков передавать этот необязательный параметр дочернему классу ?
Хотел бы увидеть развернутые ответы от профи, чтобы получше разобраться в этом вопросе и огромная просьба, без флуда и каких-то споров в комментах.
Заранее благодарю.
P.S. Абстрактные классы и интерфейсы сейчас не рассматриваю, т.к. пытаюсь лучше разобраться в таких маленьких нюансах.
Дополнительно:
LSP относится не к классам, а к объектам. Что у дочернего класса "под капотом", как он создается и действует вне реализации методов и свойств базового класса - это его личное дело.
С одной стороны, конструктор - часть интерфейса класса. С другой - никакой внешний код не сможет вызвать конструктор дочернего класса, ничего о нем не зная. А принцип применяется именно для того, чтобы внешний код мог ничего не знать о дочерних классах. Так что соблюдать LSP в конструкторе - просто бессмысленно.
- Понял, спасибо за ответ)
Ответы:
Любые принципы вот эти - они абстрагированы от языка. Язык сверху накладывает на них ограничения. Поэтому 100% следования принципам не получается в общем смысле.
Поэтому мне кажется, вы сильно дословно восприняли рекомендации. Этот принцип не означает что можно взять и просто заменой (текстовой) поменять родителя на ребенка и все соберется без ошибок.
Это означает что ЛОГИЧЕСКИ можно заменить один класс на другой и ЛОГИЧЕСКИ ничего не сломается (а не будет ошибка компилятора)
И конкретно в вашем случае этот принцип не выполнится. Потому что если будет где то создание мертвого животного - на мышь вы его просто так не замените - логика отвалится.
- Согласен с вами, единственное у меня вопрос про передачу параметров в конструкторе) Остальное понимаю, что SOLID, GRASP и т.д. - набор рекомендаций, а не строгих правил)
Смысл в том, что бы не поломалось поведение в потомке.
class Mouse extends Animal { public function calcDamage() { throw new Exception('Мышь не наносит урон'); } } |
class Mouse extends Animal { public function calcDamage() { throw new Exception('Мышь не наносит урон'); } }
Опишите проблему, и специалист поможет с настройкой, исправлением ошибки или доработкой сайта. Подберём понятный план работ без лишней переписки.
Пока нет других ответов. Будьте первым, кто поможет автору.
Ответить на вопрос
Да, конструктору можно задавать параметры. В языке программирования PHP конструктор класса может иметь параметры, которые передаются при создании экземпляра объекта. Эти параметры могут быть использованы для инициализации объекта в момент его создания.
Принцип Барбары Лисков (Liskov Substitution Principle) гласит, что объекты должны быть заменяемыми на экземпляры их подтипов без изменения корректности программы. То есть, подклассы должны быть взаимозаменяемы с их суперклассами.
Если конструктор класса принимает параметры, это не противоречит принципу Барбары Лисков, поскольку конструктор является частью класса и отвечает за инициализацию объекта. Параметры конструктора могут быть использованы для передачи данных, необходимых для корректной инициализации объекта.
Пример использования параметров в конструкторе класса в PHP:
class Person { private $name; private $age; public function __construct($name, $age) { $this->name = $name; $this->age = $age; } public function getName() { return $this->name; } public function getAge() { return $this->age; } } $person = new Person("John Doe", 30); echo $person->getName(); // выводит "John Doe" echo $person->getAge(); // выводит 30
Таким образом, использование параметров в конструкторе класса в PHP является допустимым и не противоречит принципу Барбары Лисков, если это не нарушает заменяемость объектов и их подтипов.