Состав наследственного имущества: ГК РФ Статья 1112. Наследство / КонсультантПлюс

Содержание

Исковые требования о включении в состав наследственного имущества вкладов наследодателя и признании за наследником права на наследство по закону на данные вклады, находящиеся в банке, в отношении которого открыто конкурсное производство, подведомственны судам общей юрисдикции (Извлечение) — Верховный Суд Российской Федерации





            3. Исковые требования о включении в состав
                 наследственного имущества вкладов
          наследодателя и признании за наследником права
             на наследство по закону на данные вклады,
             находящиеся в банке, в отношении которого
                 открыто конкурсное производство,
              подведомственны судам общей юрисдикции

                       (И з в л е ч е н и е)


     М. обратилась  в суд с иском к открытому акционерному обществу
"Акционерный Банк "Инкомбанк" (ОАО "Акционерный Банк "Инкомбанк") в
интересах   несовершеннолетнего   сына  Б.  о  включении  в  состав
наследственного имущества вкладов его отца С.  (умершего 10  января
1997  г.)  в  этом  банке,  признании за Б.  права на наследство по
закону на данные вклады,  а также  взыскании  в  его  пользу  суммы
вкладов,  процентов  по  ним  и  процентов  за  пользование  чужими
денежными средствами.
     Определением Черемушкинского  районного  суда   г.  Москвы  от
8 сентября 1999 г. (оставленным без изменения судебной коллегией по
гражданским делам Московского городского суда) производство по делу
по иску М. прекращено.
     Президиум Московского   городского  суда  16  ноября  2000  г.
протест заместителя Председателя Верховного  Суда  РФ  о  частичной
отмене вынесенных решений удовлетворил по следующим основаниям.
     Принимая решение,  суд  исходил  из  того,  что  заявление   о
признании  ОАО  "Акционерный  Банк  "Инкомбанк"  банкротом  принято
арбитражным  судом  к  производству,  а  в силу п.  4 ст. 11 и п. 1
ст.  57  Федерального   закона   от   8   января  1998  г.  N  6-ФЗ
"О несостоятельности (банкротстве)" (далее - Закон) с этого момента
кредиторы  не  вправе  обращаться к должнику в целях удовлетворения
своих  требований  в   индивидуальном   порядке   и   имущественные
требования  к  должнику могут быть предъявлены только с соблюдением
порядка предъявления требований, установленного настоящим Законом.
     С выводом суда согласиться нельзя.
     Действительно, в п.  1 ст.  98  Закона  установлено,  что  все
требования  к  должнику  предъявляются  только в рамках конкурсного
производства.  Однако это положение подлежит  применению  с  учетом
норм,  содержащихся  в  других статьях данного Закона,  в частности
ст.ст. 2-4, 11-15, 46, 75, 114.
     Как указано   в   ст.   2   Закона,   под   несостоятельностью
(банкротством)  понимается   признанная   арбитражным   судом   или
объявленная   должником  неспособность  должника  в  полном  объеме
удовлетворить требования кредиторов по  денежным  обязательствам  и
(или) исполнить обязанность по уплате обязательных платежей.
     Должником признается     юридическое     лицо,     неспособное
удовлетворить  требования  кредиторов  по денежным обязательствам и
(или) исполнить  обязанность  по  уплате  обязательных  платежей  в
течение   определенного   срока,   а  под  денежным  обязательством
понимается обязанность  должника  уплатить  кредитору  определенную
денежную   сумму   по   гражданско-правовому  договору  и  по  иным
основаниям,   предусмотренным   Гражданским   кодексом   Российской
Федерации. Конкурсными кредиторами признаются кредиторы по денежным
обязательствам,  за исключением  граждан,  перед  которыми  должник
несет ответственность за причинение вреда жизни и здоровью, а также
учредителей  (участников)   должника   -   юридического   лица   по
обязательствам, вытекающим из такого участия.
     Согласно ст.  114  Закона  конкурсный  управляющий  производит
расчеты   с   кредиторами  в  соответствии  с  реестром  требований
кредиторов.
     Установление размера   требований  кредиторов  производится  в
порядке, определенном ст.ст. 46, 75 Закона.
     В силу   ст.   15   Закона  в  реестре  требований  кредиторов
указываются сведения о каждом кредиторе,  размере его требований по
денежным   обязательствам   и   (или)   обязательным  платежам,  об
очередности удовлетворения каждого требования.
     Разногласия, возникающие    между   конкурсными   кредиторами,
налоговыми  и  иными   уполномоченными   органами   и   арбитражным
управляющим,  о  составе,  размере  и об очередности удовлетворения
требований по денежным обязательствам и (или) обязательным платежам
рассматриваются   арбитражным   судом  в  порядке,  предусмотренном
настоящим Законом.
     Помимо заявления  о  взыскании  суммы  вкладов  и   процентов,
истицей предъявлены требования о включении в состав наследственного
имущества вкладов С.  и признании за  Б.  права  на  наследство  по
закону на данные вклады,  не связанные со взысканием денежных сумм,
определением их размера и установлением очередности  удовлетворения
денежных требовании.
     Таким образом,  дело по иску М.  подведомственно  судам  общей
юрисдикции,  что  не  противоречит также ст.  57 Закона.  По смыслу
данной  статьи  в  ее  взаимосвязи  с  другими  положениями  Закона
(ст.ст.   46,   75,   114),   кредитор   должен  соблюдать  порядок
предъявления  имущественных  претензий  к  должнику,  установленный
указанным Законом,  в случае возникновения между ними разногласий о
составе,  размере и  об  очередности  удовлетворения  имущественных
требований.  Эти имущественные требования предполагают включение их
в реестр требований кредиторов с целью погашения за счет  имущества
должника.
     Между тем  требование  М.   в   части   включения   в   состав
наследственного  имущества  вкладов С.  и признании за Б.  права на
наследство по закону на данные вклады  носит  иной  характер  и  не
направлен  на  урегулирование  разногласии о составе,  размере и об
очередности удовлетворения имущественных претензий,  а также на  их
погашение за счет имущества должника.
     Кроме того,  ст. 57  Закона   имеет   в   виду   имущественные
требования,  вытекающие  из  внедоговорных  и  других обязательств,
предусматривающих  взыскание  с  должника  денежных  сумм  и  иного
имущества должника.
     Указанная часть требований М. не  вытекает  из  договора  либо
иного  обязательства,  предусматривающих  уплату  денежных  сумм из
средств или за счет имущества должника.
     Предъявление М.  в  суд  общей  юрисдикции  иска о включении в
состав наследственного имущества вкладов С. и признании за Б. права
на   наследство   по   закону  на  данные  вклады  не  противоречит
требованиям ст 98 Закона,  основано на  положениях ст.ст. 11, 12 ГК
РФ и ст. 25 ГПК РСФСР.
     В связи с изложенным суд незаконно прекратил  производство  по
делу  по иску М.  к ОАО "Акционерный Банк "Инкомбанк" о включении в
состав наследственного имущества вкладов С. и признании за Б. права
на наследство по закону на данные вклады по п. 1 ст. 219 ГПК РСФСР.
     Поэтому президиум  Московского  городского  суда   определение
Черемушкинского  районного  суда  г.  Москвы и определение судебной
коллегии по гражданским делам Московского городского суда отменил в
части требования М.  о включении в состав наследственного имущества
вкладов С.  и признании за Б.  права на  наследство  по  закону  на
данные  вклады,  дело  направил  в этой части на рассмотрение в суд
первой инстанции.


                           ____________

Какое имущество входит в состав наследства?

Определение состава наследства является одним из важнейших элементов при разрешении вопроса о переходе имущества от умершего гражданина (наследодателя) к другому лицу (наследнику или наследникам).

В соответствии с пунктом 128 Правил совершения нотариальных действий нотариусами, нотариус при выдаче свидетельства о праве на наследство, путем истребования соответствующих доказательств, проверяет не только факт смерти наследодателя, время и место открытия наследства, наличие или отсутствие завещания, но и в обязательном порядке проверяет состав и место нахождения наследственного имущества.

Какое имущество входит в состав наследства?

Пунктом 1 статьи 1040 Гражданского кодекса Республики Казахстан (Особенная часть) установлено, что в состав наследства входит принадлежащие наследодателю имущество, а также права и обязанности, существование которых не прекращается с его смертью.

Недвижимое имущество в составе наследства

Согласно пункту 1 статьи 117 Гражданского кодекса Республики Казахстан (Общая часть), к недвижимому имуществу (недвижимые вещи, недвижимость) относятся: 

  • земельные участки;
  • здания, сооружения;
  • многолетние насаждения;
  • и иное имущество, прочно связанное с землей, то есть объекты, перемещение которых без несоразмерного ущерба их назначению невозможно.

В соответствии с пунктом 2 статьи 117 Гражданского кодекса, к недвижимым вещам законодателем приравниваются также подлежащие государственной регистрации:

  • воздушные и морские суда;
  • суда внутреннего водного плавания;
  • суда плавания "река-море";
  • космические объекты;
  • линейная часть магистральных трубопроводов.

При этом законодательством Республики Казахстан к недвижимым вещам может быть отнесено и иное имущество.

Таким образом, при наличии соответствующих правоустанавливающих документов на недвижимое имущество, зарегистрированное за наследодателем, оно включается в состав наследства и может быть унаследовано наследниками.

Движимое имущество в составе наследства

В соответствии с пунктом 3 статьи 117 Гражданского кодекса, имущество, не относящееся к недвижимости, включая деньги и ценные бумаги, признаются движимым имуществом.

Согласно пункту 2-1 статьи 115 Гражданского кодекса, к деньгам и правам (требованиям) по денежному обязательству (правам требования по уплате денег) применяется соответственно правовой режим вещей или имущественных прав (требований), если иное не предусмотрено Гражданским кодексом, иными законодательными актами Республики Казахстан или не вытекает из существа обязательства.

Таким образом, с учетом положений статьи 1040 Гражданского кодекса, в состав наследства может быть включено, как недвижимое имущество, так и движимое. Также в состав наследства могут быть включены права требования, объективированные результаты творческой интеллектуальной деятельности, фирменные наименования, товарные знаки и иные средства индивидуализации изделий, имущественные права и другое имущество.

Какое имущество не входит в состав наследства?

В соответствии с пунктом 2 статьи 1040 Гражданского кодекса, не входят в состав наследства права и обязанности, неразрывно связанные с личностью наследодателя. К таковым относятся:

  • права членства в организациях, являющихся юридическими лицами, если иное не установлено законодательными актами или договором;
  • право на возмещение вреда, причиненного жизни или здоровью;
  • права и обязанности, вытекающие из алиментных обязательств;
  • права на пенсионные выплаты, пособия и другие выплаты на основании трудового законодательства Республики Казахстан и законов Республики Казахстан в сфере социального обеспечения;
  • личные не имущественные права, не связанные с имущественными.

В соответствии с пунктом 3 статьи 115 Гражданского кодекса, к личным не имущественным благам и правам относятся: жизнь, здоровье, достоинство, честь, доброе имя, деловая репутация, неприкосновенность частной жизни, личная и семейная тайна, право на имя, право на авторство, право на неприкосновенность произведения и другие нематериальные блага и права.

Таким образом, гражданским законодательством четко определен состав имущества, которое может быть унаследовано после смерти наследодателя, а также обозначены личные не имущественные права и блага, которые прекращаются с смертью наследодателя.

Включение имущества в наследственную массу


В обиходе мы воспринимаем наследство в основном как движимое имущество и денежные вклады, однако наследство не ограничивается только этими категориями. В состав наследства входят определенные права и обязанности, которые переходят к наследникам. Юридическое определение наследственной массы, наследственного имущества гораздо шире. Она представляет собой совокупность не только имущественных прав, но и обязанностей наследодателя. При этом долги наследодателя называются пассивом наследственной массы. К наследникам наследственная масса переходит как единое целое. 

Согласно Гражданскому Кодексу РФ в состав наследства (наследственную массу) входят принадлежавшие наследодателю на день открытия наследства:

  • имущество (движимое и недвижимое), в том числе денежные средства и их эквиваленты: акции, облигации и т.д., 
  • права имущественного характера (в том числе, указанные в текущих договорах, заключенных наследодателем до смерти), 
  • обязанности имущественного характера (займы, кредиты и другие).

Не входят в состав наследства права и обязанности, неразрывно связанные с личностью наследодателя: право на алименты, право на возмещение вреда, причиненного жизни и здоровью гражданина, а также права и обязанности, переход которых не допускается законом. В состав наследства не входят личные неимущественные права и другие нематериальные блага.

В то же время может возникнуть ситуация, что определенные документы не были оформлены умершим в надлежащем порядке, они потеряны, или оформлены с ошибками, что не позволяет нотариусу совершить необходимые действия по оформлению наследства.

Довольно распространенным основанием для включения имущества в наследственную массу является ненадлежащее оформление договора приватизации с участием наследодателя. В договоре могут быть ошибки в написании личных данных участников договора, отсутствовать подпись умершего, неполно указан адрес, могут быть не определены доли и т.п., в силу чего приватизированная собственность была включена в состав наследства.

Кроме того, довольно часто возникает ситуация когда определенное имущество было скрыто или фиктивно выведено из состава наследственного имущества и требуется признать имущество частью наследства. Например после смерти одного из супругов выясняется, что совместный автомобиль был продан и переоформлен на другое лицо. Добиться правды в указанной ситуации возможно только через суд, в рамках которого необходимо ставить вопрос об оспаривании незаконных сделок и включении имущества в наследственную массу.

Исковое заявление о включении имущества в наследственную массу составляется для подтверждения того, что умерший действительно являлся собственником имущества, на которое претендуют наследники, в том случае, если подтверждающие документы отсутствуют или составлены неправильно. Истцами являются наследники, заинтересованные в оформлении своих прав на наследственное имущество.

Юристы юридической компании "Гарант-Право" помогут Вам разобраться в возникшей спорной ситуации, правильно и своевременно сформируют пакет документов для суда, и защитят Вашу собственность в судебном порядке. Мы обладаем необходимым опытом и знаниями для ведения судебных дел такой категории, и знаем все тонкости и специфику для разрешения ситуации в интересах клиента.


Верховный суд РФ разъяснил правила погашения долгов умерших

Верховный суд РФ разъяснил правила погашения долгов умерших

Верховный суд Российской Федерации при рассмотрении конкретного спора о взыскании с наследника неустойки за несвоевременную уплату алиментов разъяснил положения действующего законодательства.

В частности, указал, что статьей 1112 ГК РФ установлено, что не входят в состав наследства «права и обязанности, неразрывно связанные с личностью наследодателя», к таким относится право на получение алиментов.

В соответствии со статьей 1175 ГК РФ наследники, принявшие наследство, отвечают по долгам наследодателя солидарно. Каждый из наследников отвечает по долгам в пределах стоимости перешедшего к нему наследственного имущества.

Согласно Постановлению Пленума Верховного Суда РФ от 29.05.2012 № 9 «О судебной практике по делам о наследовании» имущественные права и обязанности не входят в состав наследства, если они «неразрывно связаны с личностью наследодателя». В частности, в состав наследства не входит право на алименты и алиментные обязательства - о чем говорится и в Семейном кодексе РФ.

Выплата алиментов, которые взыскивают по суду, прекращается со смертью того, кто их получает или, кто их выплачивает (статья 120 Семейного кодекса).

В этой связи Верховный суд РФ делает следующий вывод - не связанные с личностью наследодателя имущественные права и обязанности входят в состав наследства. К наследникам одновременно переходят как права на наследственное имущество, так и обязанности по погашению долгов наследодателя, если таковые были на момент смерти.

Если наследник должника принял наследство, то он сам становится должником кредитора наследодателя, но в пределах стоимости перешедшего к нему имущества

Если к наследнику переходит долг по алиментам, то к нему переходит и обязанность платить неустойку, начисленную на момент смерти наследодателя.

Обязанность платить неустойку и долг по алиментам - это долги, не связанные с личностью, и поэтому наследник обязан эти долги выплатить в пределах имущества, которое ему перешло.

Вместе с тем, не наследуются и с момента смерти должника прекращаются обязательства по уплате алиментов на будущее, т.к. они неразрывно связаны с личностью должника.

Прокуратура города Владивостока

Определение Верховного Суда РФ № 117-КГ19-20 от 2 июля 2019 года

Судебная коллегия по гражданским делам Верховного Суда Российской Федерации в составе председательствующего Юрьева И.М., судей Горохова Б.А., Назаренко Т.Н.

рассмотрела в открытом судебном заседании гражданское дело по иску Боевой Маргариты Римовны к Исламовой Ренате Римовне, обществу с ограниченной ответственностью «Риль», обществу с ограниченной ответственностью «Тамам» о выделе доли в общем имуществе супругов, включении её в наследственную массу, признании участником юридических лиц,

по кассационной жалобе Исламовой Ренаты Римовны на апелляционное определение судебной коллегии по гражданским делам Севастопольского городского суда от 17 сентября 2018 г.

Заслушав доклад судьи Верховного Суда Российской Федерации Юрьева И.М., выслушав объяснения представителя Исламовой Р.Р. - Реуцкого А.В., поддержавшего доводы кассационной жалобы, Судебная коллегия по гражданским делам Верховного Суда Российской Федерации

установила:

Боева М.Р. обратилась в суд с иском к Исламовой Р.Р., ООО «Риль», ООО «Тамам» о выделе доли в общем имуществе супругов Исламовой В.В. и Исламова Р.М., включении её в состав наследственного имущества, признании себя участником юридических лиц ООО «Риль» и ООО «Тамам».

В обоснование иска Боева М.Р. указала, что её отцом Исламовым Р.М. в период брака с Исламовой В.В. были зарегистрированы ЧП «Риль» и ООО «Тамам», единственным учредителем которых являлся Исламов Р.М. После смерти Исламовой В.В., наступившей 8 июня 2012 г., наследство по закону приняли её супруг Исламов Р.М, дочери Исламова Р.Р. и Боева М.Р. 23 июня 2014 г. умер Исламов Р.М., после смерти которого наследство по завещанию приняла Исламова Р.Р., в том числе 100% доли в уставном капитале ООО «Риль» и ООО «Тамам».

Полагая, что поскольку ООО «Риль» и ООО «Тамам» были учреждены в период брака её родителей, то её матери Исламовой В.В. принадлежала 1/2 доли в уставном капитале этих обществ, которая должна быть включена в состав наследственной массы после её смерти.

Решением Ленинского районного суда г. Севастополя от 14 мая 2018 г. в удовлетворении исковых требований Боевой М.Р. отказано.

Апелляционным определением судебной коллегии по гражданским делам Севастопольского городского суда от 17 сентября 2018 г. решение суда первой инстанции отменено, постановлено новое решение, которым исковые требования Боевой М.Р. удовлетворены частично.

Выделена супружеская доля Исламовой В.В. в ООО «Риль» и в ООО «Тамам» в виде 50% уставного капитала. Включены 50% уставного капитала ООО «Риль» и ООО «Тамам» в состав наследства, открывшегося после смерти Исламовой В.В., умершей 8 июня 2012 г. В остальной части иска отказано.

В кассационной жалобе Исламова Р.Р. ставит вопрос о передаче жалобы с делом для рассмотрения в судебном заседании Судебной коллегии по гражданским делам Верховного Суда Российской Федерации для отмены обжалуемого апелляционного определения, как незаконного.

Определением судьи Верховного Суда Российской Федерации Юрьева И.М. от 4 июня 2019 г. кассационная жалоба с делом передана для рассмотрения в судебном заседании Судебной коллегии по гражданским делам Верховного Суда Российской Федерации.

Проверив материалы дела, обсудив доводы кассационной жалобы, Судебная коллегия по гражданским делам Верховного Суда Российской Федерации находит, что имеются основания для отмены апелляционного определения.

В соответствии со статьёй 387 Гражданского процессуального кодекса Российской Федерации основаниями для отмены или изменения судебных постановлений в кассационном порядке являются существенные нарушения норм материального права или норм процессуального права, которые повлияли на исход дела и без устранения которых невозможны восстановление и защита нарушенных прав, свобод и законных интересов, а также защита охраняемых законом публичных интересов.

Такие нарушения норм материального и процессуального права были допущены при рассмотрении настоящего дела судом апелляционной инстанции.

Как установлено судом и следует из материалов дела, Исламова В.В. и Исламов Р.М. состояли в браке с 11 января 1969 г. (т.1, л.д. 10)

23 августа 1995 г. произведена государственная регистрация ЧП «Риль», 25 ноября 1996 г. - регистрация ООО «Тамам», участником которых являлся Исламов Р.М. (т. 1, л.д. 17-25).

8 июня 2012 г. умерла Исламова В.В., после смерти которой наследство приняли наследники по закону первой очереди: супруг Исламов Р.М., дочери Исламова Р.Р. и Боева М.Р.

23 июня 2014 г. умер Исламов Р.М., после смерти которого наследство по завещанию приняла дочь Исламова Р.Р., в том числе 100% доли уставного капитала в ООО «Риль» и ООО «Тамам», и 15 июня 2016 г. получила свидетельства о праве на наследство по завещанию (т.1, л.д. 160-162, 164, т. 2, л.д. 130-136).

Разрешая спор и отказывая в удовлетворении исковых требований Боевой М.Р., суд первой инстанции исходил из пропуска истцом срока исковой давности к заявленным требованиям о выделе доли в совместно нажитом имуществе супругов - её родителей, что явилось основанием для отказа в удовлетворении требований.

Суд пришёл к выводу о том, что трёхлетний срок исковой давности для предъявления иска исчисляется со дня смерти её матери Исламовой В.В. - 8 июня 2012 г., поскольку истец считала, что Исламова В.В. является собственницей 1/2 доли уставного капитала названных обществ. Кроме того, суд указал, что при жизни Исламовой В.В. её доля в ООО «Риль» и ООО «Тамам» не была определена и, соответственно, не могла быть включена в состав наследства после её смерти.

Отменяя решение суда первой инстанции и принимая по делу новое решение о частичном удовлетворении иска, суд апелляционной инстанции указал, что Исламова В.В. на момент смерти являлась собственником доли в праве общей собственности на спорное имущество в силу закона, Боева М.Р. своевременно обратилась с заявлением о принятии наследства после смерти Исламовой В.В., приняла его, соответственно, вправе претендовать на любое имущество, где бы оно ни находилось и в чём бы ни заключалось.

Судебная коллегия по гражданским делам Верховного Суда Российской Федерации находит, что выводы суда апелляционной инстанций сделаны с существенным нарушением норм материального и процессуального права.

В соответствии со статьёй 1112 Гражданского кодекса Российской Федерации в состав наследства входят принадлежавшие наследодателю на день открытия наследства вещи, иное имущество, в том числе имущественные права и обязанности.

Исходя из разъяснений, данных в пункте 33 постановления Пленума Верховного Суда Российской Федерации от 29 мая 2012 г. № 9 «О судебной практике по делам о наследовании», в состав наследства, открывшегося со смертью наследодателя, состоявшего в браке, включается его имущество, а также его доля в имуществе супругов, нажитом ими во время брака, независимо от того, на имя кого из супругов оно приобретено либо на имя кого или кем из супругов внесены денежные средства, если брачным договором не установлено иное.

Для приобретения наследства наследник должен его принять (пункт 1 статьи 1152 Гражданского кодекса Российской Федерации).

Статьёй 1153 Гражданского кодекса Российской Федерации определено, что принятие наследства осуществляется подачей по месту открытия наследства нотариусу заявления наследника о принятии наследства либо заявления наследника о выдаче свидетельства о праве на наследство.

Как усматривается из материалов дела, после смерти Исламовой В.В. Боева М.Р. приняла наследство путём обращения к нотариусу с заявлением о принятии наследства, в суд с требованиями в отношении долей ООО «Риль» и ООО «Тамам» Боева М.Р. обратилась в феврале 2018 г.

Согласно статье 195 Гражданского кодекса Российской Федерации исковой давностью признаётся срок для защиты права по иску лица, право которого нарушено.

В силу статьи 196 Гражданского кодекса Российской Федерации общий срок исковой давности составляет три года со дня, определяемого в соответствии со статьёй 200 указанного кодекса, предусматривающей, что срок исковой давности начинает течь со дня, когда лицо узнало или должно было узнать о нарушении своего права и о том, кто является надлежащим ответчиком по иску о защите этого права.

Таким образом, действующее законодательство связывает начало течения срока исковой давности с тем моментом, когда лицо узнало или должно было узнать о нарушении своего права, и с тем, когда лицо узнало или должно было узнать о том, кто является надлежащим ответчиком по иску о защите этого права.

Суд первой инстанции, отказывая Боевой М.Р. в иске о выделе супружеской доли матери и включении её в наследственную массу, исходил из пропуска срока исковой давности, о применении которого заявили ответчики.

В соответствии с частью 1 статьи 327 Гражданского процессуального кодекса Российской Федерации суд апелляционной инстанции повторно рассматривает дело в судебном заседании по правилам производства в суде первой инстанции с учётом особенностей, предусмотренных главой 39 названного кодекса.

Апелляционное определение должно соответствовать общим требованиям, предъявляемым к решению суда статьёй 195 Гражданского процессуального кодекса Российской Федерации, то есть должно быть законным и обоснованным.

Согласно разъяснениям, содержащимся в пунктах 2 и 3 постановления Пленума Верховного Суда Российской Федерации от 19 декабря 2003 г. № 23 «О судебном решении», решение является законным в том случае, когда оно принято при точном соблюдении норм процессуального права и в полном соответствии с нормами материального права.

Решение является обоснованным тогда, когда имеющие значение для дела факты подтверждены исследованными судом доказательствами, удовлетворяющими требованиям закона об их относимости и допустимости, или обстоятельствами, не нуждающимися в доказывании (статьи 55, 59-61, 67 Гражданского процессуального кодекса Российской Федерации), а также тогда, когда оно содержит исчерпывающие выводы суда, вытекающие из установленных фактов.

Однако при принятии судом апелляционной инстанции обжалуемого судебного постановления указанные выше требования закона соблюдены не были.

В силу пункта 6 части 2 статьи 329 Гражданского процессуального кодекса Российской Федерации в апелляционном определении должны быть указаны мотивы, по которым суд пришёл к своим выводам, и ссылка на законы, которыми суд руководствовался.

Между тем, отменяя решение суда первой инстанции об отказе в иске в связи с пропуском срока исковой давности, суд апелляционной инстанции не привёл мотивы, по которым он считает вывод суда о применении срока исковой давности неправильным.

Поскольку истечение срока исковой давности, о применении которого заявлено стороной в споре, является самостоятельным основанием к вынесению судом решения об отказе в иске, то суд апелляционной инстанции, отменяя такое решение, должен был сделать своё суждение относительно срока исковой давности.

Однако суд апелляционной инстанции не привёл ни одного довода об отклонении установленных судом первой инстанции обстоятельств относительно срока исковой давности, имеющих существенное значение для рассмотрения дела. Более того, суд апелляционной инстанции не определил указанное обстоятельство в качестве юридического значимого и не дал ему правой оценки.

Кроме того, суд апелляционной жалобы не учёл, что в настоящее время собственником 100% доли в уставном капитале ООО «Риль» и ООО «Тамам» на основании свидетельства о праве на наследство по завещанию является Исламова Р.Р. Свидетельство о праве на наследство по завещанию не оспорено и недействительным не признано.

Таким образом, обжалуемое судебное постановление нельзя признать отвечающими требованиям статей 195 и 329 Гражданского процессуального кодекса Российской Федерации.

С учётом изложенного Судебная коллегия по гражданским делам Верховного Суда Российской Федерации находит, что допущенные судом апелляционной инстанции нарушения норм материального и процессуального права являются существенными, они повлияли на исход дела и без их устранения невозможны восстановление и защита нарушенных прав и законных интересов заявителя, в связи с чем апелляционное определение судебной коллегии по гражданским делам Севастопольского городского суда от 17 сентября 2018 г. нельзя признать законным, оно подлежит отмене с направлением дела на новое рассмотрение в суд апелляционной инстанции.

При новом рассмотрении дела суду следует учесть изложенное и разрешить дело в соответствии с установленными по делу обстоятельствами и требованиями закона.

Руководствуясь статьями 387, 388, 390 Гражданского процессуального кодекса Российской Федерации, Судебная коллегия по гражданским делам Верховного Суда Российской Федерации

определила:

апелляционное определение судебной коллегии по гражданским делам Севастопольского городского суда от 17 сентября 2018 г. отменить, направить дело на новое апелляционное рассмотрение в судебную коллегию по гражданским делам Севастопольского городского суда.

Состав наследства

Юридическая энциклопедия МИП онлайн - задать вопрос юристу » Статьи по Наследству » Наследственное право » Состав наследства

Понятие и состав наследства вытекает из права наследования, гарантия которого установлена Конституцией и является одним из главных элементов прав человека.


Понятие и состав наследства

Наследственное право является совокупностью правовых норм, которая регулируется кроме Конституции и другими НПА России. Основой регулирования наследственных отношений является ГК РФ, однако часть указанных правоотношений регулируются нормами ФЗ об АО, кооперативах, семейным законодательством, законом о нотариате и т. д.

Право наследования тесно связано с правами частной собственности. Когда происходит наследование, имущество переходит от наследодателя к наследникам по закону или по завещанию, по правилам универсального правопреемства. Это значит, что наследство получают наследники в комплексе, как единое целое. Наследственное право гарантирует свободу составления завещания, которая позволяет любому гражданину реализовать свое волеизъявление. Состав наследства определён в положениях статьи 1112 ГК РФ.

В состав наследства попадает все имущество умершего, включая имущественные права и лежащие на нем материальные обязательства. Но, учитывая нормы законодательства, не всякие имущественные права, а также обязанности умершего могут быть включены в наследство.

Не входят в состав наследства принадлежащие наследодателю права и обязанности, которые связаны с личностью умершего.

Также ограничения, установленные ст. 1185 ГК РФ и ст. 1112 ГК РФ, не содержат полного перечня не входящих в состав наследства прав и обязанностей.

Необходимо отметить, кто является наследодателем. Им может быть только физическое лицо, вне зависимости от возраста и состояния дееспособности, имущество которого переходит после смерти к наследникам, указанным в завещании, а также определенным в порядке наследования по закону. 

Включение имущества в наследство

При включении имущества в состав наследственной массы подается иск в судебные органы. Такие дела рассматриваются в общем исковом порядке. Зачастую, в заявление о включении в состав наследства входят принадлежавшие умершему объекты, права на которые по определенным причинам не были зарегистрированы им в установленном законом порядке при жизни. В этом случае в суде придется доказывать принадлежность наследодателю имущества при включении его в состав наследственной массы.

Наследование отдельных разновидностей имущества регламентируют положения главы 65 ГК РФ. В большинстве ситуаций это касается наследования предприятий, прав на участие в кооперативах, прав, которые предполагают участие в коммерческих организациях, если наследование касается прав на имущество крестьянских фермерских хозяйств и т. д.

В состав наследства участника хозяйственных товариществ и обществ входят доли (акции) в уставных (складочных) капиталах других хозяйственных товариществ и обществ, которые ему принадлежали на момент смерти. К примеру, в состав наследства участника акционерного общества входят принадлежавшие умершему участнику акции. Наследники, которые получили в наследство такие акции, соответственно становятся членами АО.

 

Долги в составе наследства

Долги в составе наследства являются неотъемлемой частью всего наследства, поскольку общие правила наследования предполагают универсальное правопреемство. Это значит неотделимость прав, полученных в наследство от умершего, с принадлежавшими ему  обязанностями.

С целью обеспечения мер, которые призваны сохранять наследство, положения статьи 1172 ГК РФ предусматривают, что входящие  в состав наследства наличные деньги вносятся на депозитный счет нотариуса.

 

Право на алименты в составе наследства

Если речь идет об обязательствах, которые касаются выплаты алиментов, то необходимо отметить, что положение части 2 статья 120 Семейного Кодекса предусматривает прекращение таких обязательств с момента смерти должника, поскольку они неотделимо связаны с его личностью. Это означает, что наследник не может принять в наследство те обязательства, принадлежавшие наследодателю, которые прекратились в связи с его смертью.

Право получать алименты не может переходить по наследству. В случае смерти получателя наследники не смогут получать причитающиеся ему алименты.

 

Наследование прав члена потребительского кооператива

Если умерший при жизни был членом потребительского кооператива, то к составу его наследства будет причислен его пай. Наследник умершего члена дачного, гаражного, а также жилищного или иного потребительского кооператива может рассчитывать на принятие в кооператив. Для этого потребуется подать заявление председателю правления потребительского кооператива. Образец заявления можно взять в правлении кооператива.

Кто из наследников умершего члена потребительского кооператива, в каком порядке и в какие сроки будет наследовать пай, определяет действующее законодательство и учредительные документы кооператива.

Следует учитывать, что при полном погашении паевых взносов члена потребительского кооператива он получает право собственности на имущество кооператива. В связи с этим следует отличать, когда происходит открытие наследства, наследование пая от получения имущества.

 

Определение состава наследства

Для определения состава наследства, а также его охраны, нотариус обладает правом истребования соответствующей информации по своему запросу. Полученные сведения о том, что произошло открытие наследства, а также какие объекты входят в его состав, нотариус сообщает только исполнителю завещания либо непосредственно наследникам.

Когда производится опись имущества, правами присутствовать обладает исполнитель завещания, наследники, а также в некоторых случаях представители органа опеки и попечительства. Впоследствии по их заявлению назначается оценка имущества, входящего в состав наследственной массы.

 

Иск о включении имущества в состав наследства

В тех случаях, когда существуют вопросы относительно состава наследственной массы, требующие разрешения в судебном порядке, которыми, к примеру, чаще всего являются споры о включении имущества в наследство, суды рассматривают их в исковом производстве. Такие иски носят имущественный характер и подлежат оценке. Для их рассмотрения необходимо подать иск в соответствии с подсудностью, определенной процессуальным законодательством. Образец иска, как правило, находится в суде на информационном стенде.

Необходимо остановиться на значении свидетельства о праве на наследство. Его выдача является нотариальным действием, оно выдается по месту, где открыто наследство. Для того чтобы его получил наследник, необходимо нотариусу или уполномоченному должностному лицу подать соответствующее заявление.

Образец заявления можно получить у нотариуса. Если же наследник фактически принял наследство и предоставил бесспорность этого факта нотариусу, а ему было отказано в выдаче свидетельства, наследник обладает правом обжаловать действия нотариуса. Образец заявления на обжалование таких действий можно найти на интернет-ресурсах.

Если таких фактов недостаточно для доказательства принятия наследства, в таком случае необходимо в суде рассмотреть дело об установлении юридических фактов. Составление заявления можно заказать на консультации у юриста. Свидетельство, в соответствии с общими правилами законодательства, выдается в любое время наследникам по прошествии полугодовалого срока со дня, когда произошло открытие наследства. 

Автор статьи

Кузнецов Федор Николаевич

Опыт работы в юридической сфере более 15 лет; Специализация - разрешение семейных споров, наследство, сделки с имуществом, споры о правах потребителей, уголовные дела, арбитражные процессы.

Состав наследства (наследственная масса) | Услуги по оформлению наследства

По наследству переходит любое имущество и благо, которое принадлежало наследодателю, если оно не связано с наследодателем (к примеру, право на возмещение вреда, право на алименты, а также права и обязанности, переход которых в порядке наследования не допустим). В состав наследственной массы входит любое имущество (недвижимое или движимое имущество, иные вещи, ценные бумаги, деньги и т.д.), которым наследодатель владел на праве собственности на день открытия наследства.

В состав наследства входит также право на получение денежных средств, которые наследодатель не успел получить при его жизни (пособия, пенсии). Страховая выплата не входит в наследственную массу, в случае если страховой договор заключен в пользу выгодоприобретателя. Сумма страхового возмещения является составляющей наследства, только в том случае, если наследодателем при жизни не была получена причитающаяся ему компенсация. При наследовании пая, долей или акций в уставном капитале обществ вопрос о возможности принять в них участие решается на основании соответствующего законодательства.

Вместе с имуществом, которое перешло по наследству к наследнику переходят и обязанности по его управлению и содержанию, расчеты с долгами наследодателя перед кредиторами и т.д.

Неимущественные права, связанные с личностью наследодателя, не могут переходить в порядке наследования. Однако законами и иными нормативно правовыми актами предусмотрено, что в некоторых случаях права могут быть переданы в порядке наследования (например, право на издание журнала или книги и т.д.).

В состав наследства не могут быть включены права на вещи или вещи, которыми наследодатель незаконно владел (например, оружие и т.д.). Наследник лишь может получить в наследство вещь, ограниченную в обороте, только если у него будет на то разрешение.

Подытоживая итоги, можно сделать вывод, что переход наследства осуществляется посредством завещания, на основании закона и называется универсальным правопреемством.
Также можно выделить некоторые особенности, связанные с переходом наследства:

  • в состав наследства входят те права и обязанности, носителем которых при жизни был сам наследодатель;
  • некоторые права не могут переходить по наследству;
  • переход по наследству ряда прав и обязанностей, может быть исключен из наследственной массы или ограничен в силу закона;
  • права и обязанности по наследству переходят не только с неимущественным, но и с имущественным содержанием.

Наследование против состава. А что использовать? | by Brian

Вы быстро получите довольно глубокое и широкое наследство. В некоторые дни вы можете получить глубокую иерархию классов. Одно изменение от высшего класса может уничтожить все нижележащие классы. В тот момент, когда вы решите наследовать от другого класса, вы привяжете к нему свой класс. Вы никогда не знаете, что будет делать суперкласс, потому что он находится вне вашего контроля: D Это известно как проблема хрупкого базового класса.

Иерархию классов очень, очень трудно изменить после развертывания.Один из вариантов - переписать все это целиком.

Видимо, наследование меня так сильно раздражает. В один прекрасный день получаю:

 git pull master 

Все в порядке - конфликтов нет. Пришло время создать ветку для работы. Перво-наперво запустите проект - все еще хорошо, компиляция прошла успешно. Затем я проверяю свою последнюю разработанную функцию - и бум, она запуталась.

После некоторой отладки я наконец выяснил, почему. Это из-за некоторых изменений, внесенных в корневой класс!

Иногда мы действительно используем наследование ненадлежащим образом.Принцип подстановки Лискова был бы наиболее важным ориентиром для определения того, подходит ли наследование вашему проекту или нет.

Например: B наследуется от A. Используйте подстановку Лискова, чтобы обосновать связь между B и A, затем измените связь и подтвердите ее снова. Если кажется, что отношения имеют смысл в обоих направлениях, лучше не использовать наследование.

Используя наследование, вы можете учитывать, что делает суперкласс, а также то, что ваши подклассы могут захотеть переопределить / изменить.Вместо того, чтобы сосредоточиться на своей области действия, вам, возможно, придется потратить время на понимание большого количества кода в вашем приложении, чтобы просто «заставить его работать» хорошо.

Одна проблема с наследованием заключается в том, что оно побуждает вас предсказывать будущее - это ловушка. Наследование побуждает создавать таксономию объектов на самых ранних этапах проекта. Поступая так, вы, вероятно, совершите дизайнерские ошибки. В некоторых случаях он также нарушает инкапсуляцию, открывая свойства / методы для использования подклассами.

Еще одним недостатком наследования является то, что оно делает отладку серьезной проблемой, когда иерархия классов становится слишком сложной. Простая трассировка стека может выплеснуться за пределы экрана при наличии 30 уровней наследования.

Состав vs. наследование: как выбрать?

В начале ...

... не было наследования и композиции, только код.

И код был громоздким, повторяющимся, блочным, несчастливым, многословным и утомительным.

Копирование и вставка были основными механизмами повторного использования кода.Процедуры и функции были редкими, новомодные устройства рассматривались с подозрением. Вызвать процедуру было дорого! Отделение фрагментов кода от основной логики вызвало путаницу!

Было темное время.

Затем мир озарил объектно-ориентированное программирование (ООП)… И мир в значительной степени игнорировал это в течение нескольких десятилетий. 1 . Вплоть до графических пользовательских интерфейсов 2 , которые оказались очень, очень нужны ООП. Когда вы нажимаете кнопку в окне, что может быть проще, чем отправить этой кнопке (или ее суррогату) сообщение Click 3 ?

После этого ООП взлетело.Было написано множество 4 книг и появилось бесчисленное количество 5 статей. Итак, к настоящему времени все подробно разбираются в объектно-ориентированном программировании, не так ли?

К сожалению, код (и Интернет) говорит «нет».

Самая большая путаница и разногласия, по-видимому, заключается в противопоставлении композиции наследованию, что часто резюмируется в мантре «отдавайте предпочтение композиции перед наследованием». Давай поговорим об этом.

Мантры, считающиеся вредными

Как эвристика, «предпочитать композицию наследованию» - это нормально, однако я не поклонник мантр.Хотя они часто содержат зерно истины, людям слишком легко услышать лозунг, не понимая его источника или контекста, и, таким образом, не думать самостоятельно - а это никогда не получается.

Я также не поклонник нелепых заголовков типа «Наследование - это зло» 6 , особенно когда автор пытается подкрепить такое возмутительное утверждение ненадлежащим использованием наследования… а затем обвиняет наследование. Как плотник, заявляющий, что молотки бесполезны, потому что они плохо заворачивают винты.

Начнем с основ.

Определения

Вот определение объектно-ориентированного программирования, которое я буду использовать в оставшейся части статьи: предположим, что у нас есть «классический» язык ООП, то есть тот, который поддерживает классы с полями, методами и единичным наследованием. Без интерфейсов, без миксинов, без аспектов, без множественного наследования, без делегатов, без замыканий, без лямбда-выражений, только основы:
  • Класс: именованное понятие в доменном пространстве с необязательным суперклассом, определенным как набор полей и методов.
  • Поле: именованное свойство некоторого типа, которое может ссылаться на другой объект (см. Состав)
  • Метод: именованная функция или процедура с параметрами или без них, реализующая некоторое поведение класса.
  • Наследование: класс может наследовать - использовать по умолчанию - поля и методы своего суперкласса. Наследование является транзитивным, поэтому класс может наследовать от другого класса, который наследуется от другого класса, и так далее, вплоть до базового класса (обычно Object, возможно, неявного / отсутствующего).Подклассы могут переопределять некоторые методы и / или поля, чтобы изменить поведение по умолчанию.
  • Состав: когда тип поля является классом, поле будет содержать ссылку на другой объект, создавая, таким образом, связь между ними. Не вдаваясь в нюансы разницы между простой ассоциацией, агрегацией и композицией, давайте интуитивно определим композицию, как когда класс использует другой объект для обеспечения некоторых или всех своих функций.
  • Инкапсуляция: взаимодействуя с объектами, а не напрямую с реализацией методов и полей, мы скрываем и защищаем реализацию класса.Если потребитель ничего не знает об объекте, кроме его общедоступного интерфейса, он не может полагаться на какие-либо внутренние детали реализации.

Наследование является фундаментальным

Наследование является фундаментальным для объектно-ориентированного программирования. Язык программирования может иметь объекты и сообщения, но без наследования он не является объектно-ориентированным (просто «объектно-ориентированным», но все же полиморфным).

… и композиция

тоже Состав также является основополагающим для каждого языка.Даже если язык не поддерживает композицию (что в наши дни редко!), Люди все равно мыслят в терминах частей и компонентов. Без композиции невозможно разбить сложные проблемы на модульные решения.

(Инкапсуляция тоже имеет важное значение, но мы не будем здесь много говорить об этом.)

Так в чем суета?

Композиция и наследование имеют фундаментальное значение, так что в этом такого?

Главное - думать, что одно может заменить другое во всех случаях, или что одно лучше или хуже другого.Как и во всем остальном в разработке программного обеспечения, здесь нужно идти на компромиссы.

Композицию понять довольно просто - композицию можно увидеть в повседневной жизни: у стула есть ножки, стена из кирпича и раствора и так далее. Хотя определение наследования простое, оно может стать сложным и запутанным, если его использовать неразумно. Наследование - это скорее абстракция, о которой мы можем только говорить, а не касаться напрямую. Хотя во многих ситуациях можно имитировать наследование с помощью композиции, часто это бывает громоздко.Цель композиции очевидна: сделать из частей целое. Цель наследования немного сложнее, потому что наследование служит двум целям: семантике и механике.

Семантика наследования

Наследование фиксирует семантику (значение) в иерархии классификации (таксономии), упорядочивая концепции от обобщенных до специализированных, группируя связанные концепции в поддеревьях и т. Д. Семантика класса в основном фиксируется в его интерфейсе, наборе сообщений, на которые он отвечает, но часть семантики также находится в наборе сообщений, которые отправляет класс.При наследовании от класса вы неявно принимаете на себя ответственность за все сообщения, которые суперкласс отправляет от вашего имени, а не только за сообщения, которые он может получать. Это делает подкласс более тесно связанным со своим суперклассом, чем если бы он просто использовал экземпляр суперкласса в качестве компонента вместо наследования от него. Обратите внимание, что даже в классах, которые мало что делают, имя класса передает разработчику значительную семантическую информацию о предметной области.

Механика наследования

Наследование захватывает механику, кодируя представление данных (полей) и поведения (методов) класса и делая его доступным для повторного использования и увеличения в подклассах. Механически подкласс наследует реализацию суперкласса и, следовательно, его интерфейс.

Двойная цель наследования 7 в большинстве современных языков ООП, я считаю, является причиной наибольшей путаницы. Многие думают, что «повторное использование кода» является основной целью наследования, но это не единственная его цель.Чрезмерный упор на повторное использование может привести к трагическим ошибкам в дизайне. Давайте посмотрим на пару примеров.

Как злоупотребить наследованием - Пример 1

Давайте начнем с простого и чрезвычайно распространенного примера неправильного использования наследования:
 class Stack extends ArrayList {
    public void push (значение объекта) {…}
    public Object pop () {…}
}
 

Этот класс будет функционировать как стек, но его интерфейс фатально раздут. Открытый интерфейс этого класса - это не просто push и pop, как можно было бы ожидать от класса с именем Stack, он также включает в себя получение, установку, добавление, удаление, очистку и множество других сообщений, унаследованных от ArrayList, которые не подходят для Куча.

Вы можете переопределить все нежелательные методы и, возможно, адаптировать некоторые полезные (например, clear), но это большая работа, чтобы скрыть ошибку моделирования. Фактически, три ошибки моделирования, одна семантическая, одна механическая, одна и та, и другая:

  1. Семантически утверждение «Стек является списком массивов» неверно; Стек не является правильным подтипом ArrayList. Предполагается, что стек должен обеспечивать выполнение последним вошел - первым вышел, ограничение легко удовлетворяется интерфейсом push / pop, но не обеспечивается интерфейсом ArrayList.
  2. Механически наследование от ArrayList нарушает инкапсуляцию; использование ArrayList для хранения коллекции объектов стека - это вариант реализации, который следует скрыть от потребителей.
  3. Наконец, реализация стека путем наследования от ArrayList является междоменной связью: ArrayList - это коллекция с произвольным доступом; Стек - это концепция организации очередей со специально ограниченным (неслучайным) доступом 8 . Это разные области моделирования.
Последний вопрос важен, но немного тонок, поэтому давайте рассмотрим его на другом примере.

Как злоупотребить наследованием - пример 2

Создание класса концепции предметной области путем наследования от класса реализации является распространенным злоупотреблением наследованием. Например, предположим, что мы хотим что-то сделать с определенным сегментом наших клиентов. Легко и очевидно, что нужно создать подкласс ArrayList, назвать его CustomerGroup и начать кодирование, верно?

Неправильно. Это будет отношения междоменного наследования, и их следует избегать:

  1. ArrayList уже является подклассом списка, коллекция утилит - реализация класса .
  2. CustomerGroup - это еще один подкласс - домен , класс .
  3. Доменные классы должны использовать классов реализации, а не наследовать от них.
Пространство реализации должно быть невидимым на уровне домена. Когда мы думаем о том, что делает наше программное обеспечение, мы работаем на уровне домена; мы не хотим отвлекаться на подробности о том, как он работает. Если мы сосредоточимся только на «повторном использовании кода» через наследование, мы будем неоднократно попадать в эту ловушку.

Одинарное наследование - не проблема

Одиночное наследование по-прежнему является наиболее распространенной моделью ООП; одинарное наследование - это обязательно наследование реализации, которое может привести к сильной связи между классами. Проблема, казалось бы, в том, что у нас есть только один путь наследования, который можно использовать для моделирования как наших механических, так и семантических потребностей. Если вы используете его для одного, вы не можете использовать его для другого. Так разве множественное наследование не решает эту проблему?

. Отношения наследования не должны пересекать границы домена (домен реализации или домен приложения).Заставляя CustomerGroup наследовать от ArrayList , но также и от (скажем) DemographicSegment, эти два поддомена запутываются, что сбивает с толку таксономию.

Предпочтительное (по крайней мере, для меня!) Решение - унаследовать от служебных классов столько, сколько необходимо для реализации ваших механических структур, а затем использовать эти структуры в доменных классах посредством композиции, а не наследования. Позвольте мне повторить это:

Если вы не создаете класс реализации, вы не должны наследовать от класса реализации.

Это одна из самых распространенных проблем новичков - ведь это так удобно! - и причины, по которым это неправильно, не часто обсуждаются в литературе по программированию, поэтому я повторю это еще раз: классы области приложения должны использовать классов реализации, а не быть одним из них. Держите эти таксономии / домены отдельно.

Итак, когда и как нам использовать наследование?

Использование колодца наследования

Наиболее распространенное и выгодное использование наследования - это для дифференциального программирования .Нам нужен виджет, аналогичный существующему классу Widget, но с несколькими настройками и улучшениями. В этом случае наследуйте прочь; это уместно, потому что наш подкласс по-прежнему является виджетом, мы хотим повторно использовать весь интерфейс и реализацию из суперкласса, и наши изменения в основном добавочные . Если вы обнаружите, что ваш подкласс удаляет вещи, предоставленные суперклассом, вопрос о наследовании от этого суперкласса.

Наследование наиболее полезно для группировки связанных наборов концепций, идентификации семейств классов и в целом организации имен и концепций, описывающих домен.По мере того, как мы углубляемся в реализацию системы, мы можем обнаружить, что наши первоначальные обобщения о концепциях предметной области, зафиксированные в наших иерархиях наследования, начинают разрушаться. Не бойтесь разбирать иерархии наследования на наборы взаимодополняющих взаимодействующих интерфейсов и компонентов, когда код ведет вас в этом направлении 9 .

Как определиться: по составу или по наследству?

Если у вас есть ситуация, когда сработает либо композиция, либо наследование, подумайте о разделении обсуждения дизайна на две части:
  1. Представление / реализация концепций вашей предметной области - одно измерение
  2. Семантика концепций вашей предметной области и их отношения друг к другу - это второе измерение
В общем, наследование в пределах одного из этих параметров нормально.Проблема возникает, когда мы забываем разделить два измерения и начинаем наследование через межпространственные границы.

Если вы обнаружите, что используете компонент для обеспечения подавляющего большинства своих функциональных возможностей, создавая методы пересылки в своем классе для вызова методов компонента, раскрывая поля компонента и т. Д., Подумайте, является ли наследование - для некоторых или всех желаемых поведение - может быть более подходящим.

Ничто не заменит объектное моделирование и критическое дизайнерское мышление.Но если у вас есть какие-то рекомендации, учтите их -

Наследование следует использовать только в следующих случаях:

  1. Оба класса находятся в одном логическом домене
  2. Подкласс - это правильный подтип суперкласса
  3. Реализация суперкласса необходима или подходит для подкласса
  4. Усовершенствования, внесенные подклассом, в основном являются аддитивными.
Бывают моменты, когда все эти вещи сходятся:
  • Моделирование предметной области более высокого уровня
  • Каркасы и расширения каркасов
  • Дифференциальное программирование
Если вы не делаете ничего из этого, вероятно, вам не понадобится часто наследование классов.«Предпочтение» композиции - это не вопрос «лучше», это вопрос «наиболее подходящего» для ваших нужд в конкретном контексте.

Надеюсь, эти рекомендации помогут вам заметить разницу.

Удачного кодирования!

Приложение

Особая благодарность за ценный вклад и комментарии следующим работникам мысли: Питу Ходжсону, Тиму Брауну, Скотту Робинсону, Мартину Фаулеру, Минди Ор, Шону Ньюхэму, Сэму Гибсону и Махендре Кария.
1. Первый официально объектно-ориентированный язык, SIMULA 67, родился в 1967 году.Объектно-ориентированному программированию 48 лет!
2. Программисты систем и приложений приняли C ++ в середине 1980-х, но повсеместному распространению ООП пришлось ждать еще десять лет.
3. да, я слишком упрощаю, игнорируя слушателей / делегатов событий и т. Д .; стараюсь сделать эту статью короткой!
4. Amazon заявляет о 24 777 книгах по теме объектно-ориентированного программирования на момент написания этой статьи
5. Поиск в Google утверждает ~ 8 миллионов результатов для точной фразы «объектно-ориентированное программирование» на момент написания этой статьи
6. Поиск в Google дает ориентировочные результаты 37 600 результатов для точной фразы «наследство - зло» на момент написания этой статьи
7.Семантика (интерфейсы) и механика (представление) могут быть разделены за счет дополнительной сложности языка; см., например, спецификацию языка D К. Дж. Дэйта и Хью Дарвена.
8. С некоторой грустью обратите внимание на то, что класс Java Stack наследуется от Vector.
9. Проектирование классов для повторного использования посредством наследования выходит за рамки данной статьи. Просто имейте в виду, что потребители экземпляров и подклассов имеют разные потребности, и обе из них должны быть удовлетворены дизайном вашего класса.

oop - Состав против наследования

, если класс A имеет композиционные отношения с другим классом B

Предположим, вы имеете в виду A <*> --- B или A <*> ---> B , а не наоборот ( B <*> --- A или B <*> - -> A ), потому что это не очень понятно в вашем вопросе.

класс A не может существовать без класса b

Речь идет не о классах , а о экземплярах, этих классов, и B могут иметь экземпляры независимо от этого состава, поэтому ограниченный срок жизни не для всех экземпляров B .

работает как наследование? наследует ли класс A атрибуты и методы от класса B?

A наследует B означает A является B , это абсолютно не тот случай, когда A <*> --- B или A <*> ---> B или наоборот.

Тогда, независимо от видимости операций, вы не сможете применить операции A к экземплярам B или наоборот, за исключением, конечно, если у вас также есть наследство, большее, чем композиция.

Об атрибутах B , в зависимости от способа реализации композиции, возможно, они являются частью соответствующего экземпляра A , например, в C ++ не используется указатель для композиции. Но в любом случае это не означает, что эти атрибуты B являются атрибутами A , для доступа к ним необходимо сначала получить доступ к экземпляру B через композиции, и это также предполагает, что экземпляр A имеет право прямого доступа к этим атрибутам B , поэтому они обычно являются общедоступными .

Обратите внимание: также у вас может быть A <*> ---> B <*> ---> A и т. Д., И, к счастью, это подразумевает A наследует B и B наследует A , что невозможно

Разница между составом и наследованием

В программировании повторно используемый код - это использование существующего программного обеспечения для создания нового программного обеспечения с использованием принципов повторного использования. Возможность повторного использования кода считается фундаментальной производственной функцией в компаниях, интенсивно использующих информационные технологии.В объектно-ориентированных системах это продвигается путем установления отношений между классами. Есть два основных способа установить эти отношения в объектно-ориентированном программировании - наследование и композиция. Реализация наследования - это один из способов связать классы, но ООП обеспечивает новый вид отношений между классами, называемый композицией. Устанавливая связь между новыми и существующими классами, новый класс может наследовать или внедрять код одного или нескольких существующих классов.

В ООП наследование - это методология, с помощью которой объект приобретает характеристики одного или нескольких других объектов.Это один из самых мощных инструментов для реализации повторного использования кода в ООП. При использовании наследования новый класс может быть создан путем установления родительско-дочерних отношений с существующими классами. Композиция объектов - альтернатива наследованию классов. Использование объекта в другом объекте называется композицией. Во многих случаях вы захотите использовать объект в качестве поля в другом классе, потому что легко создавать сложные классы, используя ранее написанные, хорошо спроектированные классы в качестве компонентов.Это называется композицией. Что ж, и наследование, и композиция во многих случаях обеспечивают эквивалентную функциональность, композиция объекта - лучшая модель повторного использования, чем наследование классов. В этой статье сравниваются два подхода.

Что такое наследование?

Наследование - один из самых мощных инструментов для реализации возможности повторного использования кода в объектно-ориентированном программировании. Это относится к функциональным возможностям, с помощью которых один объект приобретает характеристики одного или нескольких других объектов.Наследование в C ++ означает, что вы можете создавать классы, которые наследуют свои атрибуты из существующих классов. Это означает, что вы специализируете класс для создания связи между классами, что приводит к сильной связи между базовым и производным классами. Реализация наследования способствует повторному использованию кода, поскольку новые классы создаются из существующих классов. Наследование классов также упрощает изменение повторно используемой реализации. Но у наследования классов есть и недостатки. Во-первых, поскольку наследование определяется во время компиляции, вы не можете изменять реализации, унаследованные от родительских классов во время выполнения.

Что такое композиция?

ООП обеспечивает еще одну взаимосвязь между классами, называемую композицией, которая также известна как отношение наличия. Если особенности одного объекта должны быть частью другого объекта, отношения требуют композиции. Чтобы составить класс из существующих классов, объект каждого класса должен быть объявлен как член нового класса. Проще говоря, использование объекта в другом объекте называется композицией.Часто вы можете захотеть использовать объект как поле в другом классе. Вы используете объект внутри класса в композиции. В отличие от наследования классов, состав объектов определяется динамически во время выполнения посредством объектов, получающих ссылки на другие объекты. Кроме того, композиция обеспечивает лучший способ использования объекта без ущерба для внутренних деталей объекта, поэтому композиция полезна.

Разница между составом и наследованием

Подход

Хотя и наследование, и композиция способствуют повторному использованию кода в объектно-ориентированной системе, устанавливая отношения между классами и обеспечивая во многих отношениях эквивалентную функциональность, они используют разные подходы.С помощью наследования вы можете создавать классы, которые наследуют свои атрибуты от существующих классов, поэтому, используя наследование для создания класса, вы можете расширять существующий класс. Напротив, использование объекта в другом объекте называется композицией. Композиция объектов - альтернатива наследованию классов. Если особенности одного объекта должны быть частью другого объекта, отношения требуют композиции.

Отношения

В наследовании вы специализируете класс для создания отношения «is-a» между классами, что приводит к сильной связи между базовым и производным классами.Это позволяет спроектировать иерархию классов, и иерархия начинается с самого общего класса и переходит к более конкретным классам. Реализуя наследование, функции-члены одного класса становятся свойствами другого класса, не кодируя их явно внутри класса. В композиции вы используете объект внутри класса, и любые запросы к объекту перенаправляются на объект. Внутренние детали не связаны друг с другом в композиции, так что это отношения «есть».

Реализация

Наследование классов определяется во время компиляции, поэтому вы не можете изменить реализации, унаследованные от родительских классов во время выполнения.Поскольку наследование предоставляет подклассу сведения о реализации его родителя, оно часто нарушает инкапсуляцию. Любые изменения в родительском классе будут отражены в подклассе, что может создать проблемы, когда вы попытаетесь повторно использовать подкласс. Напротив, композиция объектов определяется динамически во время выполнения посредством объектов, получающих ссылки на другие объекты. А поскольку доступ к объектам осуществляется только через их интерфейсы, инкапсуляция не нарушается. Любой объект может быть заменен во время выполнения другим объектом, если он имеет тот же тип.

Состав против наследования: сравнительная таблица

Сводная информация о составе и наследовании

Во многих случаях вам может понадобиться использовать объект в качестве поля в другом классе, потому что сложные классы легче создавать, используя заранее написанные, хорошо спроектированные классы. Здесь вы используете композицию. Наследование предоставляет способ повторного использования кода путем расширения класса с минимальными усилиями, поэтому наследование является ценным инструментом для установления отношений между классами.В общем, предпочтительно использовать композицию, поскольку она обеспечивает способ использования объекта без ущерба для внутренних деталей объекта, в которых композиция полезна. Наследование не без проблем, но, как и наследование, композиция объектов вызывает аналогичные проблемы с производительностью в отношении создания и уничтожения объектов.

Сагар Хиллар - плодовитый автор контента / статей / блогов, работающий старшим разработчиком / писателем контента в известной фирме по обслуживанию клиентов, базирующейся в Индии.У него есть желание исследовать разноплановые темы и разрабатывать высококачественный контент, чтобы его можно было лучше всего читать. Благодаря его страсти к писательству, он имеет более 7 лет профессионального опыта в написании и редактировании услуг на самых разных печатных и электронных платформах.

Вне своей профессиональной жизни Сагар любит общаться с людьми из разных культур и происхождения. Можно сказать, что он любопытен по натуре. Он считает, что каждый - это опыт обучения, и это приносит определенное волнение, своего рода любопытство, чтобы продолжать работать.Поначалу это может показаться глупым, но через некоторое время это расслабляет и облегчает начало разговора с совершенно незнакомыми людьми - вот что он сказал ».

Последние сообщения Сагара Хиллара (посмотреть все)

: Если вам понравилась эта статья или наш сайт. Пожалуйста, расскажите об этом. Поделитесь им с друзьями / семьей.

Cite
APA 7
Khillar, S. (24 июня 2019 г.). Разница между составом и наследованием. Разница между похожими терминами и объектами.http://www.differencebetween.net/technology/difference-between-composition-and-inheritance/.
MLA 8
Хиллар, Сагар. «Разница между составом и наследством». Разница между похожими терминами и объектами, 24 июня 2019 г., http://www.differencebetween.net/technology/difference-between-composition-and-inheritance/.

Принцип наследования состава

Принцип из книги «Банда четырех»

Вердикт

В Python, как и в других языках программирования, этот великий принцип вдохновляет архитекторов программного обеспечения чтобы уйти от объектной ориентации и наслаждайтесь более простыми практиками объектно-ориентированного программирования.

Это второй выдвинутый принцип по книге "Банда четырех" в самом начале, в главе «Введение». Принцип настолько важен, что они отображают его с отступом и курсивом, как это:

Отдайте предпочтение композиции объекта над наследованием класса.

Давайте возьмем одну конструктивную задачу. и посмотрите, как работает этот принцип с помощью нескольких классических шаблонов проектирования «Банды четырех». Каждый шаблон проектирования будет собирать простые классы, не обремененный наследством, в элегантное рабочее решение.

Задача: взрыв подкласса

Ключевой недостаток наследования как стратегии проектирования в том, что класс часто нужно специализировать сразу по нескольким осям проектирования, приводя к тому, что называет Банда четырех "Распространение классов" в их главе о мостах и «Взрыв подклассов для поддержки каждой комбинации» в их главе Decorator.

Модуль регистрации

Python является хорошим примером в самой стандартной библиотеке модуля, который следует принципу композиции над наследованием, поэтому давайте в качестве примера возьмем ведение журнала.Представьте себе базовый класс ведения журнала который постепенно получил подклассы поскольку разработчикам нужно было отправлять сообщения журнала в новые места назначения.

 import sys
импорт системного журнала

# Начальный класс.

класс Logger (объект):
    def __init __ (сам, файл):
        self.file = файл

    def log (self, message):
        self.file.write (сообщение + '\ n')
        self.file.flush ()

# Еще два класса, которые отправляют сообщения в другое место.

класс SocketLogger (Регистратор):
    def __init __ (self, sock):
        self.sock = носок

    def log (self, message):
        себя.sock.sendall ((сообщение + '\ n'). encode ('ascii'))

класс SyslogLogger (Регистратор):
    def __init __ (себя, приоритет):
        self.priority = приоритет

    def log (self, message):
        syslog.syslog (собственный приоритет, сообщение)
 

Проблема возникает, когда к этой первой оси дизайна присоединяется другая. Представим, что теперь сообщения журнала нужно фильтровать - некоторые пользователи хотят видеть только сообщения со словом «Ошибка» в них, и разработчик отвечает новым подклассом Logger :

 # Новое направление дизайна: фильтрация сообщений.класс FilteredLogger (Регистратор):
    def __init __ (сам, шаблон, файл):
        self.pattern = шаблон
        super () .__ init __ (файл)

    def log (self, message):
        если self.pattern в сообщении:
            super (). log (сообщение)

# Оно работает.

f = FilteredLogger ('Ошибка', sys.stdout)
f.log ('Игнорируется: это не важно')
f.log ('Ошибка: но вы хотите это увидеть')
 
Ошибка
: но вы хотите это увидеть
 

Ловушка поставлена, и будет запущено в тот момент, когда приложение необходимо фильтровать сообщения но записывать их в сокет, а не в файл.Ни один из существующих классов не покрывает этот случай. Если разработчик продолжит работу над подклассом и создает FilteredSocketLogger который сочетает в себе черты обоих классов, тогда происходит взрыв подкласса.

Может, программисту повезет и никаких дополнительных комбинаций не потребуется. Но в общем случае приложение завершится с 3 × 2 = 6 классами:

 Регистратор FilteredLogger
SocketLogger FilteredSocketLogger
SyslogLogger FilteredSyslogLogger
 

Общее количество классов увеличится геометрически если m и n , оба продолжают расти.Это «разрастание классов» и «взрыв подклассов» чего «Банда четырех» хочет избежать.

Решение - распознать что класс, отвечающий как за фильтрацию сообщений, так и за регистрацию сообщений слишком сложно. В современной объектно-ориентированной практике его обвинят в нарушении «принципа единой ответственности».

Но как мы можем раздавать две функции фильтрации сообщений и вывода сообщений в разных классах?

Решение №1: Шаблон адаптера

Одним из решений является шаблон адаптера: чтобы решить, что исходный класс регистратора не нуждается в улучшении, потому что любой механизм вывода сообщений можно обернуть так, чтобы он выглядел как файловый объект, ожидаемый регистратором.

  1. Итак, мы сохраняем оригинальный Logger .
  2. И еще у нас есть FilteredLogger .
  3. Но вместо создания подклассов, зависящих от места назначения, мы адаптируем каждое место назначения к поведению файла а затем передать адаптер в регистратор в качестве выходного файла.

Вот адаптеры для каждого из двух других выходов:

 импортный разъем

класс FileLikeSocket:
    def __init __ (self, sock):
        self.sock = носок

    def write (self, message_and_newline):
        себя.sock.sendall (message_and_newline.encode ('ascii'))

    def flush (сам):
        проходить

класс FileLikeSyslog:
    def __init __ (себя, приоритет):
        self.priority = приоритет

    def write (self, message_and_newline):
        message = message_and_newline.rstrip ('\ n')
        syslog.syslog (собственный приоритет, сообщение)

    def flush (сам):
        проходить
 

Python поощряет утиную типизацию, поэтому единственная ответственность адаптера - предложить правильные методы - наши адаптеры, например, освобождены от необходимости наследовать от классов, которые они обертывают или из файла типа , который они имитируют.Они также не обязаны повторно внедрять полный список из более чем дюжины методов, которые предлагает настоящий файл. Так же, как не важно, чтобы утка могла ходить, если все, что вам нужно, это шарлатан, нашим адаптерам необходимо реализовать только два файловых метода что Logger действительно использует.

И так избежать взрыва подкласса! Объекты регистратора и объекты адаптера можно свободно смешивать и сопоставлять во время выполнения без необходимости создания дополнительных классов:

 sock1, sock2 = socket.socketpair ()

fs = FileLikeSocket (sock1)
logger = FilteredLogger ('Ошибка', фс)
logger.log ('Предупреждение: сообщение номер один')
logger.log ('Ошибка: сообщение номер два')

print ('Получен сокет:% r'% sock2.recv (512))
 
 Сокет получил: b'Error: сообщение номер два \ n '
 

Обратите внимание, что это было только для примера что класс FileLikeSocket написан выше - в реальной жизни этот адаптер встроен в стандартную библиотеку Python. Просто вызовите любой метод makefile () сокета получить комплектный адаптер, делающий розетку похожей на файл.

Решение № 2: Образец моста

Образец моста разделяет поведение класса между внешним «абстракционным» объектом, который видит вызывающий и обернутый внутрь объект «реализация». Мы можем применить паттерн моста к нашему примеру регистрации. если мы примем (возможно, слегка произвольное) решение что фильтрация принадлежит к классу «абстракция» в то время как выходные данные относятся к классу «реализации».

Как и в случае адаптера, отдельный эшелон классов теперь управляет письмом.Но вместо того, чтобы искажать наши выходные классы чтобы соответствовать интерфейсу объекта файла Python - что потребовало неловкого маневра добавления новой строки в регистратор что иногда приходилось снимать заново в адаптере - Теперь мы можем сами определить интерфейс обернутого класса.

Итак, давайте спроектируем внутренний объект «реализации» для приема необработанного сообщения, вместо добавления новой строки, и уменьшите интерфейс до единственного метода emit () вместо того, чтобы также поддерживать метод flush () обычно это было безуспешно.

 # «Абстракции», которые увидят вызывающие абоненты.

класс Logger (объект):
    def __init __ (сам, обработчик):
        self.handler = обработчик

    def log (self, message):
        self.handler.emit (сообщение)

класс FilteredLogger (Регистратор):
    def __init __ (сам, шаблон, обработчик):
        self.pattern = шаблон
        super () .__ init __ (обработчик)

    def log (self, message):
        если self.pattern в сообщении:
            super (). log (сообщение)

# «Реализации», скрытые за кадром.

класс FileHandler:
    def __init __ (сам, файл):
        себя.file = файл

    def emit (self, message):
        self.file.write (сообщение + '\ n')
        self.file.flush ()

класс SocketHandler:
    def __init __ (self, sock):
        self.sock = носок

    def emit (self, message):
        self.sock.sendall ((сообщение + '\ n'). encode ('ascii'))

класс SyslogHandler:
    def __init __ (себя, приоритет):
        self.priority = приоритет

    def emit (self, message):
        syslog.syslog (собственный приоритет, сообщение)
 

Объекты абстракции и объекты реализации теперь можно свободно комбинировать во время выполнения:

 обработчик = FileHandler (sys.стандартный вывод)
logger = FilteredLogger ('Ошибка', обработчик)

logger.log ('Игнорируется: это не будет регистрироваться')
logger.log ('Ошибка: это важно')
 

Это более симметрично, чем адаптер. Вместо вывода в файл, встроенного в регистратор но нефайловый вывод, требующий дополнительного класса, теперь всегда строится работающий регистратор путем составления абстракции с реализацией.

Еще раз, взрыв подкласса избегается потому что два вида классов составляются вместе во время выполнения без необходимости расширения какого-либо класса.

Решение № 3: Шаблон декоратора

Что, если бы мы хотели применить два разных фильтра к одному и тому же журналу? Ни одно из вышеперечисленных решений не поддерживает несколько фильтров - скажем, одна фильтрация по приоритету, а другая - по ключевому слову.

Вернитесь к фильтрам, определенным в предыдущем разделе. Причина, по которой мы не можем складывать два фильтра это асимметрия между интерфейсом, который они предлагают, и интерфейсом, который они оборачивают: они предлагают метод log () но вызовите метод emit () своего обработчика.Обертывание одного фильтра другим приведет к ошибке AttributeError когда внешний фильтр пытался вызвать внутренний фильтр emit () .

Если вместо этого мы изменим наши фильтры и обработчики, чтобы предложить тот же интерфейс, так что все они одинаково предлагают метод log () , Затем мы подошли к шаблону декоратора:

 # Все регистраторы выполняют реальный вывод.

класс FileLogger:
    def __init __ (сам, файл):
        self.file = файл

    def log (self, message):
        себя.file.write (сообщение + '\ n')
        self.file.flush ()

класс SocketLogger:
    def __init __ (self, sock):
        self.sock = носок

    def log (self, message):
        self.sock.sendall ((сообщение + '\ n'). encode ('ascii'))

класс SyslogLogger:
    def __init __ (себя, приоритет):
        self.priority = приоритет

    def log (self, message):
        syslog.syslog (собственный приоритет, сообщение)

# Фильтр вызывает тот же метод, что и предлагает.

класс LogFilter:
    def __init __ (self, pattern, logger):
        self.pattern = шаблон
        себя.logger = регистратор

    def log (self, message):
        если self.pattern в сообщении:
            self.logger.log (сообщение)
 

Впервые, код фильтрации переместился за пределы какого-либо конкретного класса регистратора. Вместо этого теперь это отдельная функция который можно обернуть вокруг любого регистратора, который мы захотим.

Как и в случае с нашими первыми двумя решениями, фильтрацию можно комбинировать с выводом во время выполнения без построения специальных комбинированных классов:

 log1 = FileLogger (sys.stdout)
log2 = LogFilter ('Ошибка', log1)

log1.log ('Шумно: этот логгер всегда производит вывод')

log2.log ('Игнорируется: будет отфильтровано')
log2.log ('Ошибка: это важно и печатается')
 
 Шумно: этот регистратор всегда выдает вывод
Ошибка: это важно и печатается
 

И поскольку классы декораторов симметричны - они предлагают точно такой же интерфейс, который они оборачивают - теперь мы можем складывать несколько разных фильтров поверх одного и того же журнала!

 log3 = LogFilter ('серьезный', log2)

log3.log ('Ошибка: это плохо, но не так уж плохо')
log3.log ('Ошибка: это довольно серьезно')
 
Ошибка
: это довольно серьезно
 

Но обратите внимание на одно место, где симметрия этого дизайна нарушается: в то время как фильтры можно складывать, процедуры вывода не могут быть объединены или сложены. Сообщения журнала по-прежнему могут быть записаны только на один выход.

Решение №4: За пределами банды четырех шаблонов

Модулю регистрации

Python требовалась еще большая гибкость: не только для поддержки нескольких фильтров, но для поддержки нескольких выходов для одного потока сообщений журнала.На основе дизайна модулей логирования на других языках - см. PEP 282 Раздел «Влияния» для основных источников вдохновения - модуль ведения журнала Python реализует свой собственный шаблон «Композиция поверх наследования».

  1. Класс Logger , с которым взаимодействуют вызывающие абоненты сам по себе не реализует ни фильтрацию, ни вывод. Вместо этого он поддерживает список фильтров и список обработчиков.
  2. Для каждого сообщения журнала регистратор вызывает каждый из своих фильтров. Сообщение отбрасывается, если какой-либо фильтр отклоняет его.
  3. Для каждого сообщения журнала, принятого всеми фильтрами, регистратор перебирает свои обработчики вывода и просит каждого из них на emit () сообщение.

Или, по крайней мере, в этом суть идеи. Ведение журнала в стандартной библиотеке на самом деле более сложное. Например, каждый обработчик может иметь собственный список фильтров в дополнение к перечисленным его регистратором. И каждый обработчик также указывает минимальный «уровень» сообщения. например, INFO или WARN , что, довольно сбивает с толку, не применяется ни самим обработчиком ни одним из фильтров обработчика, но вместо этого с помощью оператора if похоронен глубоко внутри регистратора, где он петляет над обработчиками.Таким образом, общий дизайн выглядит немного беспорядочно.

Но мы можем использовать основные идеи регистратора стандартной библиотеки - что сообщения регистратора может заслужить как несколько фильтров , так и несколько выходов - для полного разделения классов фильтров и классов обработчиков:

 # Регистратор теперь только один.

класс Logger:
    def __init __ (себя, фильтры, обработчики):
        self.filters = фильтры
        self.handlers = обработчики

    def log (self, message):
        если все (f.match (сообщение) для f в self.фильтры):
            для h в self.handlers:
                h.emit (сообщение)

# Фильтры теперь знают только о строках!

класс TextFilter:
    def __init __ (сам, шаблон):
        self.pattern = шаблон

    def match (self, text):
        вернуть self.pattern в тексте

# Обработчики выглядят так же, как «регистраторы» в предыдущем решении.

класс FileHandler:
    def __init __ (сам, файл):
        self.file = файл

    def emit (self, message):
        self.file.write (сообщение + '\ n')
        self.file.flush ()

класс SocketHandler:
    def __init __ (self, sock):
        себя.sock = носок

    def emit (self, message):
        self.sock.sendall ((сообщение + '\ n'). encode ('ascii'))

класс SyslogHandler:
    def __init __ (себя, приоритет):
        self.priority = приоритет

    def emit (self, message):
        syslog.syslog (собственный приоритет, сообщение)
 

Обратите внимание, что только с этой последней точкой поворота в нашем дизайне действительно ли фильтры сияют своей простотой. В первый раз, они принимают только строку и возвращают только вердикт. Все предыдущие дизайны либо скрыл фильтрацию внутри одного из классов ведения журнала, или седловидные фильтры с дополнительными функциями помимо простого вынесения приговора.

Фактически, слово «журнал» полностью исчезло из названия класса фильтра, и по очень важной причине: в нем больше нет ничего особенного для ведения журнала! TextFilter теперь полностью многоразовый в любом контексте, который связан со строками. Наконец, отделившись от конкретной концепции ведения журнала, будет легче тестировать и поддерживать.

Опять же, как и все решения проблемы "композиция вместо наследования", классы составляются во время выполнения без необходимости наследования:

 f = TextFilter ('Ошибка')
h = FileHandler (sys.стандартный вывод)
logger = Регистратор ([f], [h])

logger.log ('Игнорируется: это не будет регистрироваться')
logger.log ('Ошибка: это важно')
 

Здесь есть важный урок: принципы проектирования, такие как композиция вместо наследования, в конце, важнее отдельных паттернов, таких как Адаптер или Декоратор. Всегда следуйте принципу. Но не всегда стесняйтесь выбрать узор из официального списка. Дизайн, к которому мы пришли более гибкий и простой в обслуживании чем любой из предыдущих дизайнов, хотя они были основаны на официальных паттернах Банды четырех но этот окончательный дизайн - нет.Иногда да, вы найдете существующий шаблон дизайна это идеально подходит для вашей проблемы - но если нет, ваш дизайн может быть сильнее, если вы выйдете за их рамки.

Dodge: утверждения «если»

Я подозреваю, что приведенный выше код поразил многих читателей. Типичному программисту на Python: такое интенсивное использование классов может показаться полностью надуманным - неловкое упражнение в попытке воплотить старые идеи 80-х кажутся актуальными для современного Python.

Когда появляется новое требование к конструкции, делает ли типичный программист Python действительно идти писать новый класс? Нет! «Лучше простое, чем сложное.” Зачем добавлять класс, когда вместо этого будет работать оператор if ? Один класс регистратора может постепенно наращивать условные выражения пока он не обработает все те же дела как в наших предыдущих примерах:

 # Каждая новая функция в виде оператора «если».

класс Logger:
    def __init __ (self, pattern = None, file = None, sock = None, priority = None):
        self.pattern = шаблон
        self.file = файл
        self.sock = носок
        self.priority = приоритет

    def log (self, message):
        если self.pattern не равен None:
            если сам.шаблон отсутствует в сообщении:
                возвращение
        если self.file не равен None:
            self.file.write (сообщение + '\ n')
            self.file.flush ()
        если self.sock не равен None:
            self.sock.sendall ((сообщение + '\ n'). encode ('ascii'))
        если self.priority не равен None:
            syslog.syslog (собственный приоритет, сообщение)

# Работает нормально.

logger = Регистратор (шаблон = 'Ошибка', файл = sys.stdout)

logger.log ('Предупреждение: не так важно')
logger.log ('Ошибка: это важно')
 

Вы можете узнать этот пример как более типичный для практики проектирования Python вы сталкивались с реальными приложениями.

Подход с утверждением if не лишен преимуществ. Весь спектр возможных вариантов поведения этого класса можно понять за одно чтение кода сверху вниз. Список параметров может выглядеть подробным, но, благодаря необязательным аргументам ключевого слова Python, для большинства вызовов класса не нужно указывать все четыре аргумента.

(Это правда, что этот класс может обрабатывать только один файл и один сокет, но это случайное упрощение для удобства чтения.Мы могли легко изменить параметры файла и socket . в списки именованных файлов и сокетов .)

Учитывая, что каждый программист Python изучает , если быстро, но может потребоваться гораздо больше времени, чтобы понять классы, это может показаться очевидной победой чтобы код полагался на простейший из возможных механизмов это заставит функцию работать. Но давайте уравновесим это искушение, объяснив, что было потеряно. уклоняясь от состава над наследованием:

  1. Населенный пункт. Реорганизация кода для использования операторов if не был явным преимуществом для удобочитаемости. Если вам поручено улучшить или отладить одну конкретную функцию - скажем, поддержка записи в сокет - вы обнаружите, что не можете прочитать его код в одном месте. Код, стоящий за этой единственной функцией разбросаны по списку параметров инициализатора, код инициализатора, и сам метод log () .
  2. Возможность удаления. Недооцененное свойство хорошего дизайна в том, что это упрощает удаление функций.Возможно, только ветераны крупных и зрелых приложений Python достаточно сильно оценит важность удаления кода для здоровья проекта. В случае наших решений на основе классов, мы можем тривиально удалить такую ​​функцию, как вход в сокет удалив класс SocketHandler и его модульные тесты как только приложение больше не нуждается в этом. Напротив, удаление функции сокета из леса , если операторы не только требует осторожности чтобы избежать нарушения смежного кода, но возникает неудобный вопрос, что делать с параметром socket в инициализаторе.Его можно удалить? Нет, если нам нужно поддерживать согласованность списка позиционных параметров - нам нужно будет сохранить параметр, но вызовите исключение, если оно когда-либо использовалось.
  3. Анализ мертвого кода. Относится к предыдущему пункту заключается в том, что когда мы используем композицию вместо наследования, анализаторы мертвого кода может тривиально обнаружить когда исчезает последнее использование SocketHandler в базе кода. Но анализ мертвого кода часто беспомощен, чтобы сделать такое определение, как «Теперь вы можете удалить все атрибуты и утверждения if, если связанные с выходом сокета, потому что не сохранился вызов инициализатора передает что-либо для socket , кроме Нет .”
  4. Тестирование. Один из самых сильных сигналов о работоспособности кода, который дают наши тесты. сколько строк нерелевантного кода нужно запустить не дойдя до тестируемой линии. Протестировать такую ​​функцию, как вход в сокет, легко если тест может просто запустить экземпляр SocketHandler , передайте ему активную розетку, и попросите его на emit () сообщение. Никакой код не запускается, кроме кода, относящегося к функции. Но тестируем логирование сокета в нашем лесу , если утверждения будет выполняться как минимум в три раза больше строк кода.Необходимость настройки регистратора с правильным сочетанием нескольких функций просто проверить один из них это важный предупреждающий знак, это может показаться тривиальным в этом небольшом примере но приобретает решающее значение по мере роста системы.
  5. Эффективность. Я намеренно ставлю этот вопрос в последнюю очередь, потому что удобочитаемость и ремонтопригодность обычно более важные проблемы. А вот в дизайне проблемы с лесом , если заявление также свидетельствует о неэффективности подхода.Даже если вам нужен простой нефильтрованный журнал в один файл, каждое отдельное сообщение будет принудительно запускать инструкцию if против всех возможных функций, которые вы могли бы включить. Техника композиции, напротив, запускает код только для функций, которые вы составили вместе.

По всем этим причинам Я предполагаю, что кажущаяся простота оператора if forest это, с точки зрения разработки программного обеспечения, во многом иллюзия. Возможность читать регистратор сверху вниз как единый фрагмент кода. происходит за счет нескольких других концептуальных затрат который будет резко расти вместе с размером кодовой базы.

Dodge: множественное наследование

Некоторые проекты Python отстают от практики композиции, а не наследования потому что они склонны уклоняться от принципа с помощью спорной особенности языка Python: множественное наследование.

Вернемся к примеру кода, с которого мы начали, где FilteredLogger и SocketLogger были двумя разными подклассами базового класса Logger . На языке, поддерживающем только одиночное наследование, FilteredSocketLogger пришлось бы выбрать наследовать от SocketLogger или FilteredLogger , а затем придется дублировать код из другого класса.

Но Python поддерживает множественное наследование, поэтому новый FilteredSocketLogger может указывать как SocketLogger , так и FilteredLogger как базовые классы и наследовать от обоих:

 # Базовый класс и подклассы нашего исходного примера.

класс Logger (объект):
    def __init __ (сам, файл):
        self.file = файл

    def log (self, message):
        self.file.write (сообщение + '\ n')
        self.file.flush ()

класс SocketLogger (Регистратор):
    def __init __ (self, sock):
        себя.sock = носок

    def log (self, message):
        self.sock.sendall ((сообщение + '\ n'). encode ('ascii'))

класс FilteredLogger (Регистратор):
    def __init __ (сам, шаблон, файл):
        self.pattern = шаблон
        super () .__ init __ (файл)

    def log (self, message):
        если self.pattern в сообщении:
            super (). log (сообщение)

# Класс, полученный посредством множественного наследования.

класс FilteredSocketLogger (FilteredLogger, SocketLogger):
    def __init __ (self, pattern, sock):
        FilteredLogger.__init __ (сам, шаблон, нет)
        SocketLogger .__ init __ (сам, носок)

# Работает нормально.

logger = FilteredSocketLogger ('Ошибка', sock1)
logger.log ('Предупреждение: не так важно')
logger.log ('Ошибка: это важно')

print ('Получен сокет:% r'% sock2.recv (512))
 
 Сокет получил: b'Error: это важно \ n '
 

Имеет несколько поразительных сходств к нашему решению Decorator Pattern. В обоих случаях:

  • Есть класс регистратора для каждого вида вывода (вместо асимметрии нашего адаптера между записью файлов напрямую а не файлы через переходник).
  • Сообщение сохраняет точное значение, предоставленное вызывающим абонентом (вместо привычки нашего Адаптера замены его значением, специфичным для файла добавив новую строку).
  • Фильтр и логгеры симметричны в том, что они оба реализуют один и тот же метод log () . (Другие наши решения помимо Decorator были классы фильтров, предлагающие один метод а выходные классы предлагают другой).
  • Фильтр никогда не пытается произвести вывод самостоятельно, но, если сообщение проходит фильтрацию, переносит задачу вывода на другой код.

Эти близкие сходства с нашим предыдущим решением Decorator означает, что мы можем сравнить его с этим новым кодом сделать необычно резкое сравнение между композицией над наследованием и множественным наследованием. Давайте еще больше заострим внимание с помощью вопроса:

Если у нас есть тщательные модульные тесты как для регистратора, так и для фильтра, насколько мы уверены, что они будут работать вместе?

  1. Успех примера Decorator зависит только от публичного поведения каждого класса: что LogFilter предлагает метод log () который, в свою очередь, вызывает log () для объекта, который он обертывает (что тест может тривиально проверить с помощью крошечного фальшивого регистратора), и что каждый регистратор предлагает рабочий метод log () .Пока наши модульные тесты проверяют эти два публичных поведения, мы не можем нарушить композицию не провалив наших модульных тестов.

    Множественное наследование, напротив, зависит от поведения, которое невозможно проверить просто создавая экземпляры рассматриваемых классов. Публичное поведение FilteredLogger в том, что он предлагает метод log () который и фильтрует, и записывает в файл. Но множественное наследование зависит не только от этого публичного поведения, но о том, как это поведение реализовано внутри.Множественное наследование будет работать если метод подчиняется своему базовому классу с помощью super () , но нет, если метод выполняет свой собственный write () в файл, даже если любая реализация удовлетворяет модульному тесту.

    Таким образом, набор тестов должен выходить за рамки модульного тестирования. и выполнить фактическое множественное наследование класса - или патч обезьяны, чтобы убедиться, что log () вызывает super (). log () - чтобы гарантировать, что множественное наследование продолжает работать как будущие разработчики работают над кодом.

  2. Множественное наследование представило новый метод __init __ () потому что ни один из методов базового класса __init __ () принимает достаточно аргументов для комбинированного фильтра и регистратора. Этот новый код нужно протестировать, поэтому потребуется хотя бы один тест для каждого нового подкласса.

    У вас может возникнуть соблазн придумать схему чтобы избежать нового __init __ () для каждого подкласса, например, принять * args и затем передать их super ().__init __ () . (Если вы будете придерживаться этого подхода, просмотрите классическое эссе «Питон считается вредным в высшей степени опасным». который утверждает, что только ** кВт на самом деле безопасен.) Проблема с такой схемой в том, что она ухудшает читаемость - вы больше не можете понять, какие аргументы принимает метод __init __ () просто прочитав его список параметров. И инструменты проверки типов больше не сможет гарантировать правильность.

    Но даете ли вы каждому производному классу свой собственный __init __ () или объедините их в цепочку, ваши модульные тесты оригинального FilteredLogger и SocketLogger не могут сами по себе гарантировать что классы правильно инициализируются при объединении.

    Напротив, дизайн декоратора оставляет свои инициализаторы счастливо и строго ортогонально. Фильтр принимает свой шаблон , регистратор принимает свой носок , и между ними нет возможного конфликта.

  3. Наконец, возможно, что два класса работают нормально сами по себе, но имеют атрибуты класса или экземпляра с тем же именем что столкнется когда классы объединены посредством множественного наследования.

    Да, наши маленькие примеры здесь сделать вероятность столкновения слишком малой, чтобы о ней беспокоиться - но помните, что эти примеры просто стоят в для более сложных классов вы можете писать в реальных приложениях.

    Пишет ли программист тесты для защиты от коллизий запустив dir () для экземпляров каждого класса и проверка общих атрибутов, или написав интеграционный тест для каждого возможного подкласса, исходные модульные тесты двух отдельных классов снова не смог гарантировать что они могут чисто сочетаться посредством множественного наследования.

По любой из этих причин модульные тесты двух базовых классов могут оставаться зелеными даже если их способность объединяться посредством множественного наследования сломано.Это означает, что "Банда четырех" «Взрыв подклассов для поддержки каждой комбинации» также огорчит ваши тесты. Только путем тестирования каждая комбинация м × n базовых классов в вашем приложении Можете ли вы сделать безопасным для приложения использование таких классов во время выполнения.

Помимо нарушения гарантий модульного тестирования, множественное наследование предполагает как минимум три дополнительных обязательства.

  1. Самоанализ просто в случае с Decorator. Просто print (my_filter.logger) или просмотреть этот атрибут в отладчике чтобы увидеть, какой тип выходного регистратора прикреплен. Однако в случае множественного наследования вы можете только узнать, какой фильтр и регистратор были объединены изучив метаданные самого класса - либо прочитав его __mro__ или подвергая объект серии тестов isinstance () .
  2. В случае с Decorator все тривиально взять живую комбинацию фильтра и логгера и во время выполнения заменить другой регистратор через присвоение .атрибут регистратора - скажем, потому что пользователь только что переключил предпочтение в интерфейсе приложения. Но сделать то же самое в случае множественного наследования потребует более нежелательного маневра перезаписи класса объекта. При изменении класса объекта во время выполнения не невозможно в динамическом языке, таком как Python, это обычно считается симптомом эта разработка программного обеспечения пошла не так.
  3. Наконец, множественное наследование не имеет встроенного механизма чтобы помочь программисту правильно упорядочить базовые классы. FilteredSocketLogger не будет успешно записывать в сокет, если его базовые классы поменяны местами и, как свидетельствуют десятки вопросов о переполнении стека, Программистам на Python вечно трудно с размещением сторонних базовых классов в правильном порядке. Паттерн Decorator, напротив, делает очевидным, каким образом составляются классы: фильтр __init __ () хочет объект регистратора , но регистратор __init __ () не запрашивает фильтр .

Множественное наследование, значит, несет ряд обязательств не добавляя ни единого преимущества. По крайней мере, в этом примере решение дизайнерской проблемы с наследованием строго хуже, чем дизайн, основанный на композиции.

Dodge: Миксины

The FilteredSocketLogger из предыдущего раздела нужен собственный метод __init __ () потому что ему нужно было принимать аргументы для обоих своих базовых классов. Но оказывается, что эта ответственность можно избежать.Конечно, в случаях, когда подкласс не требует дополнительных данных, проблемы не возникает. Но даже классы, требующие дополнительных данных может доставить его другими способами.

Мы можем сделать FilteredLogger более дружелюбен к множественному наследованию если мы предоставим значение по умолчанию для шаблона в самом классе а затем предложите вызывающим абонентам настроить атрибут напрямую, внеполосная инициализация:

 # Не принимайте «шаблон» во время инициализации.класс FilteredLogger (Регистратор):
    шаблон = ''

    def log (self, message):
        если self.pattern в сообщении:
            super (). log (сообщение)

# Множественное наследование стало проще.

класс FilteredSocketLogger (FilteredLogger, SocketLogger):
    pass # Этот подкласс не требует дополнительного кода!

# Вызывающий может просто установить «шаблон» напрямую.

logger = FilteredSocketLogger (sock1)
logger.pattern = 'Ошибка'

# Работает нормально.

logger.log ('Предупреждение: не так важно')
logger.log ('Ошибка: это важно')

print ('Получен сокет:% r'% sock2.recv (512))
 
 Сокет получил: b'Error: это важно \ n '
 

Повернув FilteredLogger к маневру инициализации который ортогонален базовому классу, почему бы не довести идею ортогональности до логического завершения? Мы можем преобразовать FilteredLogger в «миксин» который живет полностью вне иерархии классов с которым его объединит множественное наследование.

 # Упростите фильтр, сделав его миксином.

class FilterMixin: # Нет базового класса!
    шаблон = ''

    def log (self, message):
        если сам.шаблон в сообщении:
            super (). log (сообщение)

# Множественное наследование выглядит так же, как указано выше.

класс FilteredLogger (FilterMixin, FileLogger):
    pass # Опять же, подкласс не требует дополнительного кода.

# Работает нормально.

logger = FilteredLogger (sys.stdout)
logger.pattern = 'Ошибка'
logger.log ('Предупреждение: не так важно')
logger.log ('Ошибка: это важно')
 

Миксин концептуально проще чем отфильтрованный подкласс, который мы видели в последнем разделе: у него нет базового класса, который мог бы усложнить порядок разрешения методов, поэтому super () всегда будет звонить следующий базовый класс, указанный в заявлении class .

У миксина также более простая история тестирования, чем у эквивалентного подкласса. В то время как FilteredLogger потребует тестов что оба запускают его автономно а также объединить его с другими классами, FilterMixin требует только тестов, которые сочетают его с регистратором. Поскольку миксин сам по себе неполный, Невозможно даже написать тест, который запускал бы его автономно.

Но все остальные обязанности множественного наследования по-прежнему применяются. Итак, пока шаблон миксина улучшает читаемость и концептуальную простоту множественного наследования, это не полное решение его проблем.

Dodge: Динамическое построение классов

Как мы видели в предыдущих двух разделах, ни традиционное множественное наследование, ни миксины решить проблему Банды четырех «взрыва подклассов для поддержки каждой комбинации» - они просто избегают дублирования кода, когда необходимо объединить два класса.

Множественное наследование в общем случае по-прежнему требует «Увеличение количества классов» с м × n заявлений о классе что каждый выглядит:

 класс FilteredSocketLogger (FilteredLogger, SocketLogger):
    ...
 

Но оказывается, что Python предлагает обходной путь.

Представьте, что наше приложение читает файл конфигурации чтобы узнать фильтр журнала и место назначения журнала, которое он должен использовать, файл, содержимое которого неизвестно до времени выполнения. Вместо того, чтобы строить все м × n возможных классов заблаговременно а затем выбрав нужный, мы можем подождать и воспользоваться этим фактом что Python не только поддерживает оператор class но встроенная функция типа () который динамически создает новые классы во время выполнения:

 # Представьте себе 2 отфильтрованных регистратора и 3 регистратора вывода.filter = {
    'шаблон': PatternFilteredLog,
    'severity': SeverityFilteredLog,
}
output = {
    'файл': FileLog,
    'сокет': SocketLog,
    'syslog': SyslogLog,
}

# Выберите два класса, которые мы хотим объединить.

с open ('config') как f:
    имя_фильтра, имя_вывода = f.read (). split ()

filter_cls = фильтры [имя_фильтра]
output_cls = выходы [output_name]

# Создаем новый производный класс (!)

name = имя_фильтра.title () + output_name.title () + 'Журнал'
cls = тип (имя, (filter_cls, output_cls), {})

# Вызовите его как обычно, чтобы создать экземпляр.logger = cls (...)
 

Кортеж классов передан в type () имеет то же значение как ряд базовых классов в заявлении class . Вызов type () выше создает новый класс через множественное наследование как от отфильтрованного регистратора, так и от регистратора вывода.

Прежде, чем вы спросите: да, это также будет работать для построения оператора класса в виде простого текста а затем передайте его в eval () .

Но создание классов «на лету» связано с серьезными проблемами.

  • Страдает читаемость. Человек, читающий приведенный выше фрагмент кода придется делать дополнительную работу чтобы определить, какой объект является экземпляром cls . Кроме того, многие программисты Python не знакомы с типом () и нужно будет остановиться и ломать голову над его документацией. Если у них возникнут трудности с новой концепцией что классы могут быть определены динамически, они все еще могут быть сбиты с толку.
  • Если сконструированный класс, например PatternFilteredFileLog указан в сообщении об исключении или ошибке, разработчик, вероятно, будет недоволен, обнаружив что ничего не возникает, когда они ищут код для этого имени класса.Отладка становится сложнее когда вы даже не можете найти класс. Может быть потрачено много времени поиск кодовой базы для type () звонков и пытаемся определить, какой из них сгенерировал класс. Иногда разработчикам приходится прибегать для вызова каждого метода с плохими аргументами и используя номера строк в результирующих трассировках отследить базовые классы.
  • Самоанализ типа, в общем случае, сбой для классов, динамически создаваемых во время выполнения. Ярлыки «Перейти к классу» в редакторе некуда будет тебя отвезти когда вы выделяете экземпляр PatternFilteredFileLog в отладчике.И движки проверки типов, такие как mypy и пир-чек вряд ли предложит сильную защиту для вашего сгенерированного класса что они могут предоставить для обычных классов Python.
  • Прекрасный блокнот Jupyter с функцией автозагрузки % обладает почти сверхъестественными способностями для обнаружения и перезагрузки измененного исходного кода в живом интерпретаторе Python. Но этому мешает, например, множественное наследование классов. что matplotlib строит во время выполнения через type () вызывает внутри своего subplot_class_factory () .

После того, как его обязательства будут взвешены, попытка использовать генерацию классов среды выполнения как последний маневр спасти и без того неисправный механизм множественного наследования стоит как reductio ad absurdum всего проекта уклонения от композиции над наследованием когда вам нужно поведение объекта варьироваться по нескольким независимым осям.

Наследование или композиция: что лучше для вашего проекта JavaScript? | автор: Фернандо Доглио

Как я уже сказал, обе эти концепции не совсем новые, но в моем случае я изучал программирование еще в те дни, думая, что если вам нужно расширить поведение, вы сделали это путем подкласса и из-за что наследование было моим единственным инструментом, когда дело доходило до расширения и добавления поведения к классу.Начнем с этого.

Наследование

По сути, в объектно-ориентированном контексте наследование - это метод, который мы можем использовать для создания производных классов, которые заимствуют все у своих родителей, то есть каждое общедоступное и защищенное свойство и метод, исключая частные. Это позволяет вам поддерживать связь с родительским классом, который обновляется в момент изменения его кода, что делает его лучшей альтернативой, чем просто копирование его кода и его расширение вручную.

Приведенный выше код TypeScript показывает основы наследования.Оба класса Dog и Cat расширяют или наследуют от FourLeggedAnimal , что означает, что они принимают все свои свойства и методы, нам не нужно переопределять их, если, как в моем примере, мы не хотим перезаписать что они делают. Наследование позволяет нам абстрагировать общее поведение, состояние (другими словами, методы и свойства) в одном месте, откуда мы можем извлечь (родительский класс).

Некоторые языки программирования допускают множественное наследование, например JAVA, что, в свою очередь, позволяет вам делать то, что мы только что сделали, но из нескольких источников.

Еще одно большое преимущество наследования, в основном для строго типизированных языков, таких как JAVA, TypeScript и другие, заключается в том, что переменные, объявленные с типом вашего родительского класса, могут также содержать объекты из его дочерних классов. Другими словами:

Следуя тем же определениям классов, что и раньше, в этом примере объявляется список элементов типа FourLeggedAnimals , в то время как на самом деле он содержит Cat и Dog . Это возможно, потому что оба объекта имеют один и тот же родительский класс.то же самое касается того факта, что мы можем безопасно вызвать метод speak в строке 6. Благодаря тому факту, что этот метод уже определен в родительском классе, мы знаем, что он будет у всех наших объектов (мы можем Не знаю, какая именно реализация будет использоваться, если мы не видели код, но мы можем быть уверены, что эта строка не выдаст ошибку из-за ошибки отсутствующего метода).

А что насчет композиции?

Хотя, как вы увидите, оба инструмента могут дать очень похожий результат, композиция - это совсем другое дело от наследования.Вместо подтипа, как мы делали раньше, композиция позволяет нам моделировать , имеет одно отношение между объектами.

Это, в свою очередь, помогает вам инкапсулировать состояние и поведение внутри компонента , а затем использовать этот компонент из других классов, формально известных как составной компонент .

Если мы вернемся к нашему примеру с животными, мы можем переосмыслить нашу внутреннюю архитектуру и получить что-то вроде этого:

По сути, теперь у нас есть три разных компонента, в двух из которых мы инкапсулировали поведение ( Barker и компоненты Meower ) и заявляют, что в AnimalProperties мы инкапсулировали наше состояние.У нас больше нет общего класса для Dog и Cat , от которого мы могли бы наследовать.

Суть компонентного подхода заключается в том, что теперь вы можете легко поддерживать и изменять код для любого из них, не затрагивая основные классы или их код. Этот тип отношений называется слабосвязанными .

Теперь мы можем перейти на следующий уровень и, добавив простой интерфейс, мы можем еще больше упростить наш код.

Проверьте это, мы снова имеем только один класс животных, который содержит нашу основную логику.И чтобы уточнить, интерфейс позволяет нам только обобщать форму нашего объекта, он ничего не реализует (интерфейсы на самом деле не реализуют код, а только определяют свой API). С его помощью мы можем создать общий «тип», если хотите, который описывает форму нашего объекта, что, в свою очередь, позволяет нам определить переменную для переноса любого из них внутрь (см. Свойство субъект внутри класса Animal ).

Как же тогда создать Dog или Cat ? Позвольте мне показать вам:

Перво-наперво: обратите внимание, что конечный результат такой же.Мы можем создать общий список животных, перебрать его и вызвать тот же метод со 100% уверенностью, что он будет у всех объектов. Опять же, мы не знаем, как это будет реализовано, потому что именно здесь компоненты (в данном случае) вступают в игру.

Главное отличие здесь в том, что вместо двух разных классов для описания наших животных у нас есть только один, который, заметьте, настолько податлив, что может быть превращен в любое животное при правильном наборе компонентов.

И если вы еще не заметили, хотя тот же эффект может быть достигнут либо наследованием, либо композицией, первый происходит во время компиляции (или интерпретации), а второй - во время выполнения.Насколько это важно? На самом деле очень важно, , видите ли, при правильном наборе методов вы можете превратить Cat в Dog или даже в совершенно новое животное во время выполнения, чего вы не могли бы сделать с наследованием.

С помощью нового метода setActor вы можете изменить лающий для моуэра в любой заданной точке, и хотя такое поведение может показаться немного странным, могут быть случаи использования, когда этот уровень динамизма идеально подходит для вашей логики.

Теперь, когда мы понимаем, что это такое и как их можно использовать, правда в том, что они оба великолепны!

Извините за разочарование, но я действительно думаю, что для каждого из них есть идеальные варианты использования.

Случай наследования

Наследование имеет смысл, потому что мы склонны связывать концепции ООП с объектами реального мира, а затем пытаемся обобщить их поведение, обобщая их природу.

Другими словами, мы не думаем, что кошка и доктор имеют 4 ноги и набор органов, которые позволяют им либо лаять, либо мяукать.Мы думаем о них как о животных, , что переводится как наследство.

И поэтому идеальный вариант использования для перехода с наследованием - это когда 80% вашего кода является общим для двух или более классов, и в то же время конкретный код сильно отличается от . И не только это, но и уверенность в том, что ни в коем случае не потребуется менять конкретный код друг на друга. Тогда наследование - это определенно правильный путь, с ним у вас будет более простая внутренняя архитектура и меньше кода, о котором нужно думать.

Чемодан для композиции

Как мы уже видели, композиция - это очень гибкий инструмент . Вам определенно нужно немного изменить свое мышление, особенно если вас, как и меня, уже учили наследованию в прошлом и то, что это единственное решение для повторного использования кода внутри контекста ООП.

Однако теперь, когда вы увидели свет (кстати, добро пожаловать), вы знаете, что это неправда. Мало того, вы также знаете, что общий код также может быть абстрагирован на различные компоненты, которые, в свою очередь, могут быть настолько сложными, насколько им нужно (при условии, что их общедоступный интерфейс остается неизменным), и что мы можем менять их местами во время выполнения, что для меня является удивительно гибким.

Еще одно большое преимущество, которое я вижу, заключается в том, что при наследовании, если вам нужно создать новый конкретный класс (например, добавить сейчас класс Lion ), вам нужно будет понять код класса FourLeggedAnimal , чтобы сделать уверен, что теперь ты получаешь от этого. И это было бы просто для того, чтобы вы могли реализовать другую версию метода speak . Однако, если вы выбрали композицию, все, что вам нужно было сделать, это создать новый класс, реализующий новую логику для метода speak , не зная ни о чем другом, и все.

Конечно, в контексте этого примера дополнительная когнитивная нагрузка, связанная с чтением очень простого класса, может показаться несущественной, однако рассмотрим реальный сценарий, в котором вам придется пройти через сотни строк кода только для того, чтобы конечно, вы понимаете базовый класс. Это определенно не идеально.

путь к алгебраическим типам данных

Сколько раз вы работали с иерархией наследования, которую было практически невозможно изменить? Что заставило вас почувствовать, что вы не тот, кто все контролирует, а просто вставляете кусочки и кусочки в этого большого колосса? Если вы какое-то время зарабатываете на жизнь программированием, скорее всего, вы сталкивались с этим не раз.Так как же этого избежать?

Мы будем использовать типичный домен интернет-магазина в примерах, с которыми вы, скорее всего, знакомы.

В чем проблема?

Смоделируем изделие. Товар имеет название и может быть оценен двумя способами. Либо в какой-то валюте (в нашем случае евро) , либо относительно другого продукта (например, большая кола всегда стоит на 50% дороже, чем меньшая кола) . Первая попытка смоделировать это с помощью наследования, вероятно, будет выглядеть так:

Пока все хорошо с наследованием, но теперь появляется новое требование.Товар может быть доставлен в пределах определенного города или получен по конкретному адресу. Продолжая исходное решение, мы получим 4 финальных класса:

  • Возможна поставкаФиксированная цена товара
  • Отправляемая Относительная цена Товар
  • Самовывоз с фиксированной ценой
  • Самовывоз Относительная цена Товар

Вы видите, что он не идеален. Особенно, если будет другое требование аналогичным образом, в результате чего всего будет 8 классов, затем еще 16 и так далее.Или что, если мы хотим добавить еще один способ доставки (расширить текущее требование) ?

IS против HAS

Чтобы решить эту проблему, нам нужно переосмыслить то, как мы моделируем наши данные. На данный момент наша модель утверждает, что, например, Cola - это продукт с фиксированной ценой, который можно отгрузить . Вместо этого мы можем заявить, что у Cola есть фиксированная цена, а у - доставка. Давайте сделаем это.

Довольно просто. Без наследования, мы составили продукт из 2-х вещей.Как выглядит Price или Delivery ?

Теперь, если мы хотим добавить еще один тип цены, мы просто добавляем еще один класс, производный Price , вместо того, чтобы создавать в 2 раза больше классов, которые у нас есть, но с сохранением чистой и гибкой модели данных, что делает невозможные состояния непредставимыми и красивыми моделями. наш домен.

Но мы использовали наследование для композиции ?!

Да, но мы использовали его как механизм для различения нескольких структур данных, а не для моделирования всего нашего продукта.Кроме того, мы сохранили вложение только на одном уровне, и в базовых классах ничего нет. Наследование становится беспорядочным из-за нескольких уровней, виртуальных методов и обмена данными. Как избежать этого несчастья?

Перед этим давайте также посмотрим, как будет выглядеть код, работающий с Price . Допустим, мы хотим рассчитать окончательную цену в долларах. Идеальным решением в рамках ООП было бы введение абстрактной функции в базовый класс и использование полиморфизма.

Но поскольку нам нужно вызвать http-клиент в этой функции, чтобы получить обменный курс, это решение очень плохое.Мы не хотим жестко кодировать HTTP-вызов клиента в объекте. Кроме того, могут быть сотни функций, которые ведут себя по-разному для каждого типа цены, и мы не хотим загрязнять классы всеми этими методами. Более того, мы могли бы работать с этим классом из другой сборки, а это значит, что мы не можем расширить класс таким образом. Лучше посчитаем цену в каком-нибудь сервисе.

Но поскольку мы не можем использовать полиморфизм, что, если мы добавим еще один тип цены? Мы можем легко забыть расширить этот код для работы с этим.

Алгебраические типы данных

Если вы присмотритесь, мы смоделировали все с помощью простых отношений «И» и «ИЛИ». Например Товар состоит из Цена И Доставка . Цена состоит из FixedPrice ИЛИ RelativePrice . RelativePrice состоит из BaseProduct И Adjustment . Вы видите образец? Добро пожаловать в мир алгебраических типов данных.

Два из них соответствуют отношениям «И» и «ИЛИ».Они служат типами для составления любого другого типа. Первый называется , продукт , в основном известный как кортеж. Он соединяет вместе любые другие типы. Так, например, RelativePrice - это продукт из Продукт и Процент . Или Продукт является продуктом из Цена и Доставка .

Тот, который представляет «ИЛИ», называется копродуктом , также известным как тип суммы или размеченное объединение.Это менее известный среди программистов, но настоящий источник энергии. Он берет несколько других типов и создает один тип, который может быть только одним из них. Цена из примера: RelativePrice или FixedPrice . Не может быть и того, и другого, но должен быть хотя бы один. C # изначально не поддерживает типы сумм (пока) , но, например, в F # они есть с первого дня. Чтобы использовать их в C #, вы можете смоделировать их с наследованием, как мы это делали в примере, и будьте осторожны, чтобы поддерживать иерархию в хорошем состоянии или использовать какую-либо библиотеку.Используя нашу библиотеку FuncSharp, Price будет выглядеть как (более подробный пример см. В документации и коде) .

Настоящая сила алгебраических типов данных в том, что они заставляют композицию, заставляя нас вести себя.

Исчерпание

Теперь давайте изменим наш PricingService , чтобы использовать нашу новую Price .

У каждого сопродукта есть функция Match , которая принимает функцию для каждого случая. Он имитирует концепцию, называемую сопоставлением с образцом.Важно то, что количество функций равно количеству типов. Это означает, что если мы теперь добавим новый тип Price и расширим его с Coproduct2 до Coproduct3, этот код не будет компилироваться. Компилятор заставит нас проверять все места и заставит их работать также с недавно добавленным типом Price .

Уловы?

Во всем остальном в программировании есть свои минусы.

Что делать, если вы хотите написать функцию, которая принимает Продукт с относительной ценой в качестве аргумента? Это невозможно, но мы потеряли, что при изменении отношения с на на получается .Иногда имеет смысл выбрать один из них и сказать, что Product - это RelativePricedProduct или FixedPricedProduct и поделиться кодом внутри них с некоторой общей структурой данных (или даже через наследование) . Однако будьте осторожны и используйте его только при необходимости.

Другая проблема дискриминируемых союзов - их полнота. Если вы расширите объединение еще на один тип, вся ваша кодовая база не будет компилироваться, и компилятор заставит вас решать этот новый случай при каждом использовании.Это отличная функция и одна из основных причин их использования. Это может быть проблематично при работе со сборками и их раскрытии в общедоступном API ваших библиотек. Невозможно перейти на новую версию постепенно, так как вы должны решить все случаи, чтобы скомпилировать свое решение с расширенным дополнительным продуктом. Эта проблема известна как проблема выражения, и в ней обсуждаются способы добавления нового типа или функциональности без прерывания работы.

Что дальше?

Некоторые ресурсы, которые могут оказаться полезными:


Техническая группа Mews предоставила вам дополнительную информацию об инженерных решениях:

.

Оставить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *