Добрый день всем.
Совершенствуюсь в php.Есть объект, у которого некоторое действие должно выполняться по разному в зависимости от некоторых параметров.
В примере: по разному считается рейтинг для разных категорий людей.
Вопрос: как это сделать грамотно?Поначалу для скорости написал примерно так:
PHP:
class Person { protected string $category; protected float $rating; public function __construct($parameters) { // … $this->calculateRating(); // … } protected function calculateRating() { switch ($this->category) { case «FirstCategory»: $this->rating = $this->calculateRatingForFirstCategory(); break; case «SecondCategory»: $this->rating = $this->calculateRatingForSecondCategory(); break; case «ThirdCategory»: $this->rating = $this->calculateRatingForThirdCategory(); break; } } protected function calculateRatingForFirstCategory() { // do something } protected function calculateRatingForSecondCategory() { // do something } protected function calculateRatingForThirdCategory() { // do something } }Полагаю, это не есть хороший код.
В книгах типа «Самоучитель PHP» и «PHP. Разработка веб-приложений» не написано, как правильно.
В статьях по SOLID я конкретных примеров тоже не увидел. Просто пишется про «расширяемость», но как её реализовать?
Некоторые статьи вообще советуют не использовать switch и if/elseif/else в таких случаях.Пока у меня идея использовать класс-создатель, и в нём устанавливать нужный метод.
Примерно так:PHP:
<?php class Person { protected string $category; protected float $rating; //.. //.. } class PersonProducer { public function getNew($parameters): Person { $person = new Person(); //.. //.. switch ($parameters->category) { case «FirstCategory»: $calculateRating = $this->calculateRatingForFirstCategory; break; case «SecondCategory»: $calculateRating = $this->calculateRatingForSecondCategory; break; case «ThirdCategory»: $calculateRating = $this->calculateRatingForThirdCategory; break; } $person->setCalculateRating = $calculateRating; //.. //.. return $person; } protected function calculateRatingForFirstCategory(): float { // do something } protected function calculateRatingForSecondCategory(): float { // do something } protected function calculateRatingForThirdCategory(): float { // do something } } $personProducer = new PersonProducer(); $person = PersonProducer->getNew($parameters);Или даже использовать разные классы.
Примерно так:PHP:
class Person { protected string $category; protected float $rating; //.. } class PersonFirstCategory Extends Person { //.. protected function calculateRating(): float { // calculate rating for FirstCategory } //.. } class PersonSecondCategory Extends Person { //.. protected function calculateRating(): float { // calculate rating for SecondCategory } //.. } class PersonThirdCategory Extends Person { //.. protected function calculateRating(): float { // calculate rating for ThirdCategory } //.. } class PersonProducer { public function getNew($parameters): Person { switch ($parameters->category) { case «FirstCategory»: $person = new PersonFirstCategory(); break; case «SecondCategory»: $person = new PersonSecondCategory(); break; case «ThirdCategory»: $person = new PersonThirdCategory(); break; } return $person; } } $personProducer = new PersonProducer(); $person = PersonProducer->getNew($parameters);Киньте в меня мануалом с примерами, как писать такие вещи правильно.
Что бы если через годик мне или другому человеку было меньше проблем изменить/добавить новый расчёт рейтинга.
Я бы создал класс Person. Методы и свойства у него определил. Как у тебя в первом случае. Только создал бы всего один метод расчёта рейтинга на все случаи. Но подождем, что скажут другие.
@romt добрый день.
Вот хорошая статья на тему полиморфизма.
И в ней наглядно с примером показано как написать структуру и даже как её можно использовать.Хотя и ваши рассуждения по коду о полиморфизме где-то рядом с истиной, но всё равно написаны с ошибками и не реализуют полиморфизм. При этом второй вариант кода совсем что-то мимо.
Поэтому очень рекомендую вам ознакомиться со статейкой, что я дал выше.
Почитать «PHP 8: объекты, шаблоны и методики программирования, 6-е издание «
Посмотреть как устроен ArgumentResolver у Symfony.
Псевдокод:PHP:
<?php class Person { protected string $category; protected RatingInterface $rating; public function __construct(RatingInterface $rating) { $this->rating = $rating; } public function calculateRating(): float { return $this->rating->calculateRating(); } } interface RatingInterface { public function calculateRating(): float; } interface RatingForCategoryResolverInterface { public function supports(string $categoryName): bool; public function resolve(): RatingInterface; } class FirstCategoryRating implements RatingInterface { public function calculateRating(): float { return 0; } } class SecondCategoryRating implements RatingInterface { public function calculateRating(): float { return 1; } } class ThirdCategoryRating implements RatingInterface { public function calculateRating(): float { return 2; } } class FirstCategoryRatingResolver implements RatingForCategoryResolverInterface { public function supports(string $categoryName): bool { } public function resolve(): RatingInterface { return new FirstCategoryRating; } } class SecondCategoryRatingResolver implements RatingForCategoryResolverInterface { public function supports(string $categoryName): bool { } public function resolve(): RatingInterface { return new SecondCategoryRating; } } class ThirdCategoryRatingResolver implements RatingForCategoryResolverInterface { public function supports(string $categoryName): bool { } public function resolve(): RatingInterface { return new ThirdCategoryRating; } } class PersonProducer { /**@var RatingForCategoryResolverInterface[] */ /** * @return RatingForCategoryResolverInterface[] */ { return [ new FirstCategoryRatingResolver, new ThirdCategoryRatingResolver, new SecondCategoryRatingResolver ]; } public function addRatingResolver(RatingForCategoryResolverInterface $ratingResolver) { $this->ratings[] = $ratingResolver; } } public function get($parameters): Person { $ratings = $this->ratings ?: $this->getDefaultRatingResolvers(); foreach ($ratings as $rating) { if ($rating->supports($parameters->category)) { return new Person($rating->resolve()); } } } } $personProducer = new PersonProducer(); $person = $personProducer->get($parameters);
Спасибо,
статью почитал,
книгу скачал, будем изучать.
Похожие записи:
- Определить числовые свойства
- Более быстрый алгоритм AAN для вычисления дискретного косинусного преобразования
- Создание и просмотр семейного древа
- Реализация двумерной бикубической интерполяции для dlarray в Matlab
- Скопируйте информацию о транспортном средстве из списка JSON в реляционную базу данных