Ematten
Понятно, что нет смысла заводить два отдельных класса “Собака” и “Черная собака”, потому что второй класс будет дублировать первый.
Нельзя просто так, по названиям, сказать, что такие-то классы нужны, а такие-то классы не нужны. Даже если эти названия очень похожи и кажутся логически связанными как-то. Это не показатель.
Вообще, есть три понятия: абстракция, объект, класс. Это всё разные понятия, хотя их легко спутать, и часто даже профессионалы, которые изучают ООП по своим ощущениям от чьего-то кода, с которым работают на работе, а не тонко разбираясь в теории и всех деталях досконально, путают эти понятия и сливают всё в одну кашу. Недавно я слышал от одного профессионала, что он там тоже состояние у класса делает какое-то, хотя речь шла об экземпляре класса. То есть он путает потому, что он изучал ООП по экспериментам с кодом, а не по скучным книгам с математическими доказательствами (для этого нужно образование, чтобы понимать, о чём пишут в таких книгах и что там за уравнения). Кажется, что это несущественная оговорка у него, ерунда. Но на самом деле, это говорит о том, что у него нет фундаментального видения, через которое обычно и видишь множество объектов в качестве одного скопления, а множество классов в качестве другого скопления.
Понимаешь, из-за этого вот, из-за этой каши, человек и не может отделить связи между классами и связи между объектами этих классов. Об абстракциях, которые формируются вообще до формирования каких-то классов и даже объектов, у них вообще речи нет, хотя абстракции - это фундамент для зарождения информационной системы. С абстракций всё начинается.
Допустим, у тебя есть стена и тень на стене. Тень на стене попадает на трещину в стене и становится темнее в этом месте. Так вот границы трещины в стене и границы трещины в тени на стене - это разные границы. Одни границы описывают, докуда будет продолжаться светлая тень на стене. Другие границы описывают, докуда будет продолжаться тёмная тень внутри трещины. Казалось бы, это хрень какая-то, там можно и дальше углубляться в детали, но если ты играл в компьютерные игры, то ты видел, что когда юнит подходит к двери с автоматом, то он дулом автомата протыкает дверь насквозь и его просто видно по этому дулу, вылезающему сквозь дверь, что он сейчас за дверью стоит и ждёт, когда ты её откроешь, и можно просто, не открывая дверь, стрелять либо сквозь неё или прямо ему в дуло автомата, чтобы его завалить там за дверью. При этом у юнита полная уверенность, что ты его не видишь, так как дверь не открыта и визуального контакта из-за этого между вами нет.
Так вот, не факт, что Собаки и ЧёрныеСобаки как классы находятся в отношении наследования. А если и находятся, то ты так сразу и не скажешь, кто от кого происходит Собаки от ЧёрныхСобак или ЧёрныеСобаки от Собак. Потому что вопреки логике может быть и так и так. Можно даже найти такую иерархию, где ЧёрныеСобаки стоят выше Собак и Собаки происходят от них. Для этого можно использовать концептуальную кластеризацию либо вообще теорию прототипов. Например, если кластеризация производится по признаку максимальной похожести на чёрное тело, то ЧёрныеСобаки больше похожи на черное тело, чем просто Собаки. И тогда мы можем сказать, что ЧёрныеСобаки стоят на вершине иерархии наследования, а КрасныеСобаки и Собаки являются производными классами от ЧёрныхСобак. У одной цвет стирали, у другой чёрный цвет перекрашивали в красный. То есть речь идёт о том, что не вся логика укладывается в логику реального мира. Тебе может казаться, что нельзя дверь проткнуть автоматом, потому что это невозможно в реальном мире, а в компьютерных играх (программах) мы встречаем это сплошь и рядом и можем этим пользоваться.
Ematten
Для этого можем ввести свойство объекта “цвет собаки”.
А если у собаки несколько цветов сразу? Это всё не так просто. Хочется, конечно, уложить всё в простые модели, как в жизни - всё легко и просто. Но в мире программ это всё не так устроено. Поэтому не торопись создавать свойство, если тебе показалось, что оно очень логично. Оно может вылезти потом боком. Сначала надо всё хорошенько обдумать. Может, не один раз.
Ematten
Допустим у меня есть необходимость инициализировать два объекта класса “Собака”, при этом первый - новая собака, а вторая - собака, свойства которой уже были описаны и занесены в базу данных. Для инициализации второго объекта мне нужно будет дергать БД. В этом случае есть ли смысл использовать два класса “Новая собака” и “Знакомая собака” или достаточно все описать в одном классе?
Не, у тебя один класс Собаки, а у этого класса есть операция заполнения объекта Собака данными. И вот туда надо подать данные или сразу, или взяв их из базы данных. Так что объект Собака не будет знать о существовании базы данных какой-то там в соответствии с законом Деметры. Если объект Собака не знает, откуда появились данные в нём, - это хорошо. Если объект Собака знает, откуда появились данные в нём, - это плохо. Плохо это потому, что эта информация бесполезна для этого объекта, а при этом внедрить туда что-то другое вместо базы данных будет сложно, потому что у тебя все Собаки, Кошки и Лошади будут знать про эту базу данных и их придётся всех переделывать капитально, чтобы они про неё знать перестали. Закон Деметры защищает от всей этой возни, поэтому его надо соблюдать везде и во всём. Звучит он так: меньше знаешь - крепче спишь.
А полиморфный конструктор, который делается в таких случаях на базе ad-hoc полиморфизма, который там можно сделать на случай разной инициализации экземпляра, идёт уже потом в качестве решения. Сначала нужно определить, нужно ли его делать вообще. Не надо бросаться сразу на это. Можно просто пропереться, наделать всякой лажи красивой внешне, чтобы быть похожим на профессионала (по оценке дураков всяких, рассматривающих фантики с открытыми ртами), а потом обосраться просто в тот момент, когда надо будет исправить небольшой бажок, вылезший потом впоследствии, или небольшой недостаток архитектуры, который всё портит годами потом. Понимаешь, да, если в фундамент заложить красивый кирпич с трещиной внутри, ничего не проверить перед этим, а просто довольствоваться внешней красотой это кирпича и думать о рекламе своих услуг, как она попрёт, когда все увидят этот кирпич в твоей кладке, то он будет смотреться красиво очень, но когда дом будет построен и этот красивый кирпич лопнет со временем из-за той трещины, ты очень пожалеешь, что закладывал его тогда, чисто чтобы про тебя думали, как о прекрасном строителе, и грамоту тебе дали в тот день “лучший строитель Урюпинска в 1973-м году!”, потому что реклама в итоге не сработала, как ожидалось, а дом уже построен и в нём живёшь ты, и очень скоро он из-за лопнувшего кирпича сложится, как карточный домик, со штукатуркой тебе же на голову и всеми остальными прелестями. Не надо делать умные вещи, чтобы внешне что-то там выглядело. Умнее ты от этого не станешь и выглядеть умным ты будешь только у дураков в их компании, которые сами ничего делать не умеют. Надо делать эффективные вещи, которые работают годами и надёжно.