Речь про наследование классов. От одного опытного программиста слышал, что класс-родитель не должен знать о классах которые от него наследуются. Т.е., как понимаю, в классе-родителе нельзя создавать объекты классов наследующихся от этого же класса. А вот спросить почему, я в тот момент забыл. Собственно вопрос - если правило: класс-«родитель» не должен знать про «детей» Верно, то почему так нельзя делать?
Ну всё объектно-ориентированное программирование строится на том, что ты передаёшь объект потомка в функцию, которая думает, что работает с родителем (полиморфизм в действии). И можешь подменять одного наследника другим в каких-то случаях (например, для тестирования). Плюс в идеале классы должны легко вытаскиваться из системы, и встраиваться в другой проект для повторного использования без изменений. Если класс-родитель завязан на наследниках, то его уже хрен перенесёшь без них в другой проект. В целом, единственный инструмент, позволяющий требовать какого-то поведения от наследников - абстрактные методы. Объявив метод абстрактным, ты обязываешь наследников его реализовать. --- Добавлено --- По хорошему, внутри класса вообще не должно быть операторов new, разве что new self или new static, все зависимости должны приходить из внешнего мира. Ты же на yii пишешь, вот, глянь видос с конференции по Yii2: --- Добавлено --- (это не значит, что я всегда сам так делаю, но, чем крупнее проект, тем более болезненны нарушения правил)
@Walk должен не должен - это всё писами по воде виляно главный вопрос - зачем ему знать или не знать про его детей? ответишь?
@mkramer, наличие new внутри класса - это агрегация. Без этого никак не обойтись. @Walk, по поводу создания потомков внутри родителей - получается рекурсия. Родительский класс должен содержать общий для всех потомков функционал, тогда как потомки частный случай реализации родителя. Если родительский функционал расширяется за счет потомков - значит диаграмма классов построена неверно. Скорее всего следует сделать рефракторинг классов. Либо объеденить родительский класс с дочерним, либо выделить иной функционал для родительского класса и от него наследовать прежний родительский и дочерний классы.
Коллеги, вы зря стараетесь - ТС-у для начала надо объяснить, чем отличаются понятие "класс" от понятия "объект". Если разберётся, то возможно вопрос станет не актуальным для него.
Так это не мне Вы, наверное, хотели ответить, а @igordata и @Walk По поводу внедрения через конструктор - вопрос спорный.
не спорный это просто один из способов закидывать всякое во внутрь класса в явном виде, а не через всякую черезжопную сложноотлавливаемую муть
Речь не о том как оно попадет в класс, а о том где же будет оператор new? Не в этом классе так в другом.
На Yii2 таких вопросов не возникает. Вот когда свои велосипеды придумываю - такой вопрос появляется. Вперед - объясните. Там тысячи строк кода.
@Walk мы же о программировании говорим. Мне не совсем понятно, что ты имеешь ввиду. А если приложишь код для наглядности, иллюстрирующий ситуацию, станет всем понятно, о чем речь.
Если ты пишешь что-то такое: PHP: class A { function ddd() { $b = new B(); // ... } } class B extends A { /* .... */ } То ты класс A уже из этого проекта не можешь выпилить. Это всё трудно отлаживать очень (получилась двунаправленная зависимость между A и B, которой всеми силами надо избегать). В конечном итоге все эти вещи замедляют отладку, тестирование, доработку.
@Walk, если, например, как-то так: PHP: interface actions { public function action_one(); public function action_two(); } abstract class A implements actions { /** * @return A; */ abstract public function getMe(); public function doSomeThisg() { $foo = $this->getMe(); $foo->action_one(); } } class B extends A { public function action_one() { echo "One"; } public function action_two() { echo "Two"; } public function getMe() { return new B(); } } $foo = new B(); $foo->doSomeThisg();
В общем понял (для себя), почему не стоит так делать: PHP: // Пример, как не надо делать class Main { // 50-100 свойств - переменные, массивы, многомерные массивы, объекты public $name = 'Masha'; // 100500 методов, хотим часть вынести в дочерний класс public function rename($name) { $rename = new Rename; $rename->newname($name); } } class Rename extends Main { // Представим, что это какой-то объемный метод на 500 строк public function newname($name) { $this->name = $name; echo $this->name.'<br />'; // Olya } } $obj = new Main; echo $obj->name.'<br />'; // Masha $obj->rename('Olya'); echo $obj->name.'<br />'; // Masha Дочерний класс создает копию родительского, и копию его свойств. Получается: 1. Бессмысленность в дочернем свойстве - все равно свойства родителя придется менять через return 2. Можно банально запутаться.
Это все понятно. Вопрос в том, КАК ЛУЧШЕ это сделать. Вот размышлял над вариантом через дочерние классы - но, как уже писал, слышал, что так делать нельзя. Разбирался, почему именно нельзя.
Наследование надо применять, только если можно сказать, что объект наследника является также объектом родителя. Вот у меня в проекте есть форма для введения параметров услуги "продажа нерудных материалов", от неё унаследована форма "продажа нерудных материалов с доставкой", которая добавляет поля, соответствующие доставке. Но про второю форму можно сказать, что она всё равно форма по продаже нерудных материалов, поэтому наследование применимо.
В вашем примере в родительском классе не создается дочерний класс, а также вы не создаете объект родительского класса. Как понимаю, вы показываете пример как надо. Меня же интересует пример как не надо, с разбором почему именно так не надо. Мне ваша формулировка не совсем ясна. Необходимость наследования, которую читал я - проста: если есть несколько объектов, у которых есть часть повторяющегося функционала, и все они выполняют одинаковую функцию - то имеет смысл эту повторяющуюся часть вынести в родительский класс, а все объекты сделать дочерними от этого родителя. Но меня интересует, есть ли другие сферы применения наследования. Например, в целях вынесения части функционала из родительского класса (но, как показывает практика - такой вариант не применим).
Это неверно. ООП - именно про абстрактное мышление, когда вы переводите программу в ряд взаимодействующих механизмов. Объекты должны отображать, большей частью, понятия предметной области. Поэтому отношения и выражаются словами "является" (наследование), "содержит" (агрегирование), "использует" и т.п.
Все говорят про эти абстракции, но что-то в том же Yii2 я их не наблюдаю - все вполне конкретно и решает вполне конкретные задачи - работа с бд, валидация данных, обработка входящего запроса, выдача результата и т.д. - никаких абстракций, одна конкретика.
Yii - это реализация низкого уровня задач. Твоё приложение - более высокий уровень. И то, берём Yii. Там есть интерфейс UrlRuleInterface, нечто, что должно разбирать запросы и строить url-ы, есть UrlManager, который использует массив объектов классов, реализующих UrlRuleInterface, чтоб разбирать запросы, есть также стандартная реализация интерфейса UrlRule, которой хватает на большинство задач. Но, UrlManager может работать с любой реализацией UrlRule, ты можешь написать свой класс по разбору запросов, подставить его в UrlManager, и всё будет в порядке. Это и есть абстракция - мы говорим, что UrlManager-у нужна некая хрень, которая умеет разбирать запросы и строить url-ы. UrlManager-у всё равно, как и кем это будет реализовано. Т.е. он работает с некоей абстрактной разбиралкой запросов, а не конкретной реализацией UrlRule.