Читать не буду, потому что неинтересно. А вот один момент отмечу. Независимо от того, прав автор или нет.
В названии статьи используется весьма не новый демагогический прием. "Почему оно провалилось...". Тезис, который по меньшей мере спорный, подается как бесспорный (оно провалилось, вне сомнения), и остается лишь выяснить — почему ?
Этот прием совсем не нов и аппелирует не к сознанию, а к подсознанию. Его цель — заставить читающего подсознательно согласиться с высказываемой точкой зрения. Для многих высказаться вопреки общепринятой точке зрения очень нелегко, поэтому когда ему что-то подается как общепринятая точка зрения, он подсознательно вынужден с ней согласиться.
Почему все вкладчики доверяют ABC банку ? Почему все домохозяйки используют стиральный порошок XYZ ? Это все тот же подход, и целью его является вовсе не выяснение, почему они доверяют или используют, а стремление на подсознательном уровне внедрить убеждение, что доверяют или используют. Все. А ты почему не бежишь в этот банк или за этим порошком в таком случае ?
Не хочу обсуждать, насколько такой прием явлвется корректным при рекламе банковских услуг или стиральных порошков, но в научной и технической литературе он должен быть безусловно и категорически осужден.
With best regards
Pavel Dvorkin
Почему объектно-ориентированное программирование провалилось
Но факт остаётся фактом: сторона представлявшая объектно-ориентированное программирование, во время открытой дискуссии с противниками под смех зала, даже запуталась в своих же концепциях. Люди вспоминают, что у всех создалось стойкое впечатление, что аргументация Lisp'еров была куда убедительней и последовательней, чем сторонников ООП
Факт того, что два мужика с красной половины стола были более убедительны, чем два два путающихся в терминах мужика с синей половине стола говорит о... Только о том, что мужики с красной половины были более убедительны а с синей путались в терминах. Ничего больше. Странно по мастерству оратора определять какие-то характеристики технологии. Может те кто ООП поддерживал вообще первый раз в жизни в шоу участвовали и напились ночью до этого.
В восьмидесятых годах метод повторного использования каким-то неясным мне образом связали с объектно-ориентированным программированием, и сколь угодно многочисленные имеющиеся доказательства обратного, по-видимому, уже не избавят этот метод от этого клейма. Хотя иногда объектно-ориентированный код действительно годится для повторного использования, таким его делает вовсе не объектно-ориентированность, а программирование в стиле "снизу вверх". Возьмём, например, библиотеки: их можно подгружать и повторно использовать сколько угодно, потому что, по сути, они представляют собой отдельный язык. И при этом, совсем неважно, написаны ли они в объектно-ориентированном стиле или нет."
Пустой аргумент, ни в пользу ООП ни против. Какая разница что с чем связали?
Я уверен, что ООП методологически неверна. Она начинает с построения классов. Это как если бы математики начинали бы с аксиом. Но реально никто не начинает с аксиом, все начинают с доказательств. Только когда найден набор подходящих доказательств, лишь тогда на этой основе выводится аксиома. Т.е. в математике вы заканчиваете аксиомой. Тоже самое и с программированием: сначала вы должны начинать развивать алгоритмы, и только в конце этой работы приходите к тому, что вы в состоянии сформулировать четкие и непротиворечивые интерфейсы
Проведение аналогии программирования с математикой без обоснования данной аналогии. Они бы еще популярную аналогию с архитектурой вспомнили или менее популярную с сексом. Особенно мне понравилась фраза — "сначала вы должны начинать развивать алгоритмы". Прямо вот везде. Пишем word — сначала развивать алгоритмы, куда без них. Что в операционной системе самое важное? Ну алгоритмы естественно, что же еще . Мда. Народ смотрит со своих университетских колоколен и свято верит, что все программирование — это решение систем уравнений и рисование фракталов. А операционные системы и прикладное ПО — это так, мелочи.
Именно из-за этой неразберихи в ООП так популярен рефакторинг — из-за ущербности парадигмы вы просто обречены на переписывание программы, уже в тот самый момент, когда только задумали её спроектировать в ООП-стиле
А еще они наверняка собрали репрезентативную статистику по рефакторингу при всех остальных парадигмах программирования, аха. Меня всегда умиляют заявления вида "большинство использует..." или "здесь так популярно, а вон там — нет". При этом единственный источник фактов — это пяток некоммерческих проектов, в которых учавствовал автор и два десятка его студентов
ООП ради самой ООП уже давно превратилось в замкнутый круг. Конечно, можно попытаться считать C# в .NET 3.5 с более чем 50,000 реализованных классов "венцом эволюции". Добавить в следующей версии .NET ещё миллион классов – что может быть более правильным и более вожделенным, с точки зрения ООП-программиста? Так вы говорите, это и есть то самое бегство от сложности?
Я, конечено, очень уважаю Столлмана. Могучий товарищь. Gcc. Emacs. Но тут как бы ничего не говорится о том, как именно большое или малое количество классов является сильной или слабой стороной парадигмы. Если вспомнить, сколько функций в том же emacs...
Томас Поток из Oak Ridge National Laboratory даже провел масштабное прикладное исследование (9), которое продемонстрировало, что нет никакой заметной разницы в производительности между программистами, работающими в ООП и в обычном процедурном стиле программирования.
Тут можно даже не кликать на оигинальный документ и не смотреть, что исследование проводилось в одной (!!!) лаборатории IBM с шестьюстами пятьюдесятью сотрудниками. Разве в парадигме ООП что-нибудь декларировалось что "мы ускорим написание кода в 20 раз"? ООП — это парадигма написания, которая упрощает поддержку и модификацию БОЛЬШИХ систем. Понятно что консольную утилиту пофг в каком стиле писать — хоть ООП, хоть процедурном, хоть функциональном без спецэффектов.
Re: Почему объектно-ориентированное программирование провали
Здравствуйте, Игорь САВЧУК, Вы писали:
ИС>Аннотация: ИС>Среди множества идей, которые звучат красиво скорее в теории, чем на практике, объектно-ориентированное программирование занимает особое место. Попробуем разобраться и ответить на главный вопрос, почему всё же объектно-ориентированное программирование провалилось?
Раз тут все такие обобщатели, я тоже хочу оттянуться и обобщить. Чем я хуже?
Изменения (какие бы то ни было) часто происходят скачком. В ходе этого скачка изменения, бывает, заходят слишком далеко и наступает то, что на советском русском называлось "реакция". В википедии я нашел только политическое значение этого термина. А оно гораздо шире. Пример из области доткомов (и тоже с обобщением) приводит Игорь Ашманов. Другой пример — религиозная реакция. Общество переходит от религиозного прошлого к игностическому будущему, его заносит в ярое богоборчество, в настоящее время происходит откат (религиозная реакция). Ну вот, его поколбасит еще немного на стрелках и переход на новые рельсы состоится.
То, что мы видим с ООП, по-моему, отлично укладывается в эту схему. Переход от лапши к ООП сопровождался таким нездоровым hype, его всовывали в такие дыры... Да вот же, рядом пример: Так ли нужны делегаты и лямбды?
. По мне, так сама Джава — еще один готовый пример. После чего происходит реакция на overhype. Голоса против громко зазвучали. Повышенный интерес к ФП появился. Это значит, что мы (только теперь!) проходим неизбежный откат, теряем иллюзии и отучаемся совать ООП не в те дыры. Обсуждаемый текст (скорее, его первоисточники) — манифестация реакционеров.
Вопрос, следовательно, в том, каково оно — программирование на productivity plateau этой технологии? Мой личный ответ: подобающее ООП место — "скелет" проектов. Набор классов, который описывает предметную область, позволяя проектным нубам быстрее врубаться. Набор интерфейсов, который показывает, какие роли какие сущности могут играть. Не больше и не меньше. При этом "мясо", то есть реализация и алгоритмы, может быть замешано на чем угодно — на процедурном подходе, на ФП, на лямбдах, делегатах etc. etc.
Лично мне очень печально бывает наблюдать реакционеров, которые отрицают объектность как таковую, не пытаются провести декомпозицию... и при этом мнят себя прогрессивными силами. Поэтому, идею реакционности следовало бы знать и уметь применять.
Re: Почему объектно-ориентированное программирование провали
Здравствуйте, samius, Вы писали:
V>>ИМХО, это объяснимо, т.к. объект в ООП — это группировка в "одно целое" относительно большого кол-ва элементов программы. S>Согласен лишь с тем что при группировке относительно большого кол-ва элементов необходимость рефакторинга возрастает. Но кто заставляет группировать много элементов?
А ты сторонник объектов с одним полем и одним методом? Если нет, то сказанное в силе.
V>>И весь рефакторинг, по-сути, это перетасовка элементов таких групп. Пройдись по формальным методам рефакторинга: 90% рефакторинга — это способы перемещения методов и полей м/у объектами таким образом, чтобы не поломать случайно исходное поведение программы. S>Все же здесь проблеммы не в самом ООП, а в отсутствии четких критериев группировки полей и методов.
Не может быть никаких четких критериев. Объекты — это проекция дизайна программы, а дизайн не может вестись по четким критериям. Он может вестись лишь по четким требованиям к функциональности, а не к способу мышления и как результата — решения. Тем более, что этих способов решения, можно считать, что бесконечное кол-во. Потому здесь есть-таки творческий элемент, как и в любой инженерной работе.
S>Согласен. Но все же ООП не запрещает свободные функции. В рамках ООП их можно рассматривать их как объект с одним методом. Т.е. если мы возьмем ФП программу и свободные функции преобразуем в объекты, необходимости к рефакторингу не прибавится.
В какие объекты? Функциональные? Я их тоже за ф-ии считаю.
А по существу... Не проблема преобразовать. Проблема в том, что дается механизм, достаточно легкий для дизайна "верхнего уровня", который практически сразу позволяет набросать основной скелет программы и всё выходит красивым и очевидным. Это ООП, и это его несомненное достоинство. От этого трудно отказаться, поэтому это используют. Не зря коллеги говорят, что дизайн верхнего уровня в ООП смотрится лучше всего. Так в чем засада? ИМХО, проблемы в ООП начинаются там, где объекты начинают "тяжелеть", а иерархии разрастаться. А они это делают не потому что кто-то дурак, а по объективным мотивам: уточняется функциональность, растет список сценариев и т.д. Что мы делаем в ответ на разбухание кода? Мы вводим новые "слои" в наш ООП, выделяем "хелперы" и целые "независимые подсистемы" и так до бесконечности. Вот что имелось ввиду, когда утверждалось, что ООП обречен на постоянный рефакторинг, то бишь на постоянное переписывание кода.
При большом объеме функционала нужно что-то легковесное, чтобы была возможность легко и непринужденно этой функциональностью ворочать, без рефакторинга на каждый чих. В ФП нет возможности вот так красиво описать статическую структуру участников. фП думает от данных и потоков их обработки. Им всю программу приходится писать в терминах "хелперов" и "подсистем" с самого начала. Плюс продумывать тщательно, как "протаскиваются" эти данные и прочий контекст в процессе вычисления. Вот и выходит, что по мере роста функционала им ничего переписывать не приходится, всё уже переписано с самого начала и заведомо декомпозировано до уровня плинтуса. В отличие от "черных ящиков" ООП.
Справедливости ради, в ООП тоже сей подход можно использовать. Т.е. брать у ФП не только модную здесь иммутабельность и замыкания (порой до экстаза), но саму программу плясать от данных и небольших объектов, представляющих эти данные с одной стороны, и осуществляющие обработку этих данных с другой стороны. Заметь, это отход от парадигмы общепринятой парадигмы ООП, хотя используются ООП ср-ва. Итоговый дизайн должен представлять из себя большое кол-во легковесных объектов минимальнейшей функциональности, которые не потребует рефакторинга ни при каких обстоятельствах. ИМХО, такой стиль — дело привычки. Типичная "лакмусовая бумажка" для ситуации, когда такой стиль не только стоит применять из сображений "хорошего тона", но когда только он и спасает проект — это если подмечаешь объекты, в которых относительно мало полей, но очень много методов. Применять ООП-декомпозицию тут бессмысленно, ибо в таких случаях обычно невозможно декомпозировать состояние. Поэтому поступаешь просто — объект превращаешь в "контекст". Остальное разбивается либо на маленькие объекты, которые используются как временные "стековые" при вычислении (value-type в дотнете просто рулез для такого), а что не требует промежуточного состояния при вычислении — вовсе разносишь на свободные ф-ии.
S>Проблема ООП в отношении рефакторинга лишь в том, что существует тенденция лепить все в существующие уже классы дабы "не плодить сущности".
Ну дык правильно. Ведь эти классы обычно отражают первоначальное видение дизайна, т.е. не случайны. И в этих классах могут находится нужные нам данные, поэтому мы и пихаем функциональность в них, дабы не нарушать нашу любимую "инкапсуляцию". А ее по мере роста программы нарушать все-равно придется. Правда, не факт, что при этом пострадает надежность, ведь по-прежнему можно обеспечить безопасный набор любых операций, просто этот набор после декомпозиции будет более "мелкогранулирован".
S>Все ИМХО, без претензий на абсолютную истину.
Окстись, мы тут максимум личными наблюдениями делиться можем, а они субъективны априори.
Re: Почему объектно-ориентированное программирование провали
вот именно "разобраться и ответить на главный вопрос" — не получилось. Вся статья — исключительно пересказ чужих высказываний (отнюдь не первой свежести, кстати), собственных же тезисов, их доказательства и выводов автора — ноль целых, ноль десятых. Если RSDN Magazine считает возможным опубликовать такую статью — стыдно за RSDN.
Re[3]: Почему объектно-ориентированное программирование пров
PD>>В названии статьи используется весьма не новый демагогический прием. "Почему оно провалилось...". Тезис, который по меньшей мере спорный, подается как бесспорный (оно провалилось, вне сомнения), и остается лишь выяснить — почему ?
I>Этот прием в зависимости от контекста может быть как демагогическим, так и полемическим. На мой взгляд в данном случае имеем дело с полемическим.
Корректная полемика предполагает как минимум в начале формулировку разных точек зрения, после чего можно перейти к своим аргументам в пользу одной из них. Когда же с самого начала спорное утверждение подается как бесспорное и не объясняется почему (а в заголовке этого сделать нельзя) — это именно демагогия.
Если бы автор выбрал нейтральное название (ООП — успех или неудача, к примеру), а в тексте статьи начал доказывать, что это не только неудача, но и просто провал — никаких возражений не было бы с моей стороны.
With best regards
Pavel Dvorkin
Re[4]: Почему объектно-ориентированное программирование пров
Здравствуйте, SV., Вы писали:
SV.>Здравствуйте, gandjustas, Вы писали:
SV.>>>Вопрос, следовательно, в том, каково оно — программирование на productivity plateau этой технологии? Мой личный ответ: подобающее ООП место — "скелет" проектов. Набор классов, который описывает предметную область, позволяя проектным нубам быстрее врубаться. Набор интерфейсов, который показывает, какие роли какие сущности могут играть. Не больше и не меньше. G>>А есть ли там вообще ООП? Те самые наследование реализации, инкапсуляция, полиморфизи, объекты с идентичностью и поведением. G>>Или это всетаки больше SOA, где выкинуты сомнительные свойства вроде идентичности и наследования реализации?
SV.>Сама "сомнительность" наследования реализации — следствие тех самых overhype и втыкания во все дыры. Сомнительным может быть конкретное применение, но не прием. Почему? Потому, что наследование реализации — объективное явление (вне нашего сознания и интерпретаций). И если оно наблюдается в моделируемом куске жизни, повторение его в модели (а любой софт это модель) делает ее полезнее.
Но далеко не любая программа является моделью части реального мира. Даже наоборот, программ где такой подход оправдан исчезающе мало.
SV.>Например, и "воробьи", и "вороны" (обобщенно — "птицы") имеют в своем составе "крылья" и летает, "махая" ими. "Воробьи" являются "птицами", и летают как любая другая "птица" — "махая" (по-птичьи) "крыльями" (птичьими). НЕ ПОТОМУ, что внутри у "воробья" сидит абстрактная "птица" или какой-нибудь вполне конкретный "летатель", и летает за него (при этом, имеет форму черного ящика, то есть летает неизвестно как). При написании софта, надо повторять это объективное отношение (подкласс <вид "воробей"> наследует такое поведение, как полет, у суперкласса <класс "птиц">), потому, что такой софт проще писать, читать и понимать, а также потому, что дурацких противоречий ("Ва-а-ась, как оно теперь у нас будет плавать, с такими-то крыльями?!") гарантированно не возникнет.
Отношение is-a отлично достигается без наследования реализации. Интерфейсы (выше ты привел именно наследование интерфейсов), typeclasses в хаскеле, ducktyping в динамических языках. Это все позволяет выстраивать отношения is-a.
SV.>Грамотная декомпозиция на значимые сущности должна быть переложена на ЯП без изменений, с сохранением всех отношений, в т.ч. наследования реализаций.
Выделенное необоснованно.
Ты в принципе попал в ту же проблему, куда попадают все "философы ооп". Они поголовно считают что все достижения ООП недоступны в других парадигмах, а на деле даже наоборот.
Re[14]: Почему объектно-ориентированное программирование про
Здравствуйте, DarkGray, Вы писали: DG>>>что в этом такого странного? и в чем противоречие с ООП? S>>Противоречие не с ООП. Противоречие — с идиотским предположением о том, что ООП предлагает лепить классы с сущностей модели. Если у вас встанет задача смоделировать управление стройкой, то в вашем коде не будет никаких TКран, ТБульдозер, ТКаменщик или ТЦементМарки400.
DG>не будет, если будет абстрактное моделирование стройки — например, на уровне проектных граней, например, распределения ресурсов или там начисление зарплаты DG>но если будет моделирование именно стройки, например, игра-стройка, то все эти объекты появятся.
В том-то и дело, что моделирования "именно стройки" в природе почти не бывает. И даже в игре большая часть кода посвящена моделированию игры, а не того, что игра моделирует.
DG>но если речь идет о моделировании взаимодействия между прорабом и бригадиром, то прорабы и бригадиры появятся.
И кто из них от кого будет отнаследован? Не смешите меня — будет в лучшем случае один класс на всех, при этом в нём не будет никакого поведения.
DG>разные классы появляются, когда необходимо описать разное поведение. DG>если мы при моделировании отойдем слишком далеко, что нам уже будет пофигу — это стройка, магазин или дет.сад — то да, никаких объектов прораб, кирпич и арматура не будет.
Да, будет 1с. DG>если мы при моделировании подойдем слишком близко, и будет моделировать мир на уровне атомов — то да, тоже никаких объектов прораб, кирпич или арматура не будет. DG>да, все эти объекты появятся лишь только если мы будем моделировать именно саму стройку, а не что-то еще.
Вы вообще реальные программы когда-нибудь писали? К чему эти абстрактные рассуждения про атомы и арматуру? Программа является моделью решаемой задачи не в большей степени, чем токарный станок является моделью вытачиваемого изделия.
ООП обманывает людей, обещая им решить задачу через построение модели. Да нихрена!
Если вы пишете программу для расчёта падения камня на луну, у вас не будет модели камня, модели луны, и модели вакуума. У вас будет квадратное уравнение и код, который его решает.
DG>имхо, ты на основе задач — а давайте мы напишем еще одну программу для начисления зарплаты на стройке, делаешь вывод о том, что для описания модели стройки — не нужны объекты прораб, бригадир или кирпич. DG>а это логически неверный вывод.
Я говорю, что для решения задач, связанных со стройкой, модель стройки не нужна. Вы устанете придумывать задачу, для решения которой нужна именно модель стройки.
Это не делает ООП плохим. ООП прекрасно подходит; только нужно помнить, что объекты будут моделировать решение, а не задачу. DataSet/DataRow — это элементы решения; никто не спорит, что они прекрасно описываются в терминах ООП.
Большинство книжек про ООП вводят людей в заблуждение. "О, у нас есть теплица, датчики и нагреватели. Давайте заведём ТТеплица, ТДатчик, ТНагреватель и посмотрим, не удастся ли нам нарисовать какую-нибудь забавную иерархию наследования". Это — бред. Гораздо более конструктивный способ — это сосредоточиться на решении: что именно мы хотим сделать. Из каких частей должен состоять автомат, управляющий теплицей? И вот эти части уже можно моделировать в ООП.
Понимаете? Выключатель не должен содержать в себе модель лампочки, которой он управляет. Он должен содержать разумно устроенную модель выключателя.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[3]: Почему объектно-ориентированное программирование пров
rem Параметры воспринимаются вместе с кавычками (то есть они тоже передаются как часть параметра)
IF NOT EXIST myfolder (
call :MyFunction "param1" param2
rem после вызова MyFunction, управление вернётся обратно на эту строчку
)
rem bla-bla
goto :EOF
rem :EOF определена по умолчанию для goto
:MyFunction
rem смотрите описание call, там сказано, что кавычки можно убирать так: %~1
IF EXIST %1 bla-bla
IF EXIST %2 bla-bla
rem всё, уходим вконец файла и автоматически возвращаемся в то место, откуда вызвали
goto :EOF
: MyFunction2
goto :EOF
Здравствуйте, gandjustas, Вы писали:
SV.>>Вопрос, следовательно, в том, каково оно — программирование на productivity plateau этой технологии? Мой личный ответ: подобающее ООП место — "скелет" проектов. Набор классов, который описывает предметную область, позволяя проектным нубам быстрее врубаться. Набор интерфейсов, который показывает, какие роли какие сущности могут играть. Не больше и не меньше. G>А есть ли там вообще ООП? Те самые наследование реализации, инкапсуляция, полиморфизи, объекты с идентичностью и поведением. G>Или это всетаки больше SOA, где выкинуты сомнительные свойства вроде идентичности и наследования реализации?
Сама "сомнительность" наследования реализации — следствие тех самых overhype и втыкания во все дыры. Сомнительным может быть конкретное применение, но не прием. Почему? Потому, что наследование реализации — объективное явление (вне нашего сознания и интерпретаций). И если оно наблюдается в моделируемом куске жизни, повторение его в модели (а любой софт это модель) делает ее полезнее.
Например, и "воробьи", и "вороны" (обобщенно — "птицы") имеют в своем составе "крылья" и летает, "махая" ими. "Воробьи" являются "птицами", и летают как любая другая "птица" — "махая" (по-птичьи) "крыльями" (птичьими). НЕ ПОТОМУ, что внутри у "воробья" сидит абстрактная "птица" или какой-нибудь вполне конкретный "летатель", и летает за него (при этом, имеет форму черного ящика, то есть летает неизвестно как). При написании софта, надо повторять это объективное отношение (подкласс <вид "воробей"> наследует такое поведение, как полет, у суперкласса <класс "птиц">), потому, что такой софт проще писать, читать и понимать, а также потому, что дурацких противоречий ("Ва-а-ась, как оно теперь у нас будет плавать, с такими-то крыльями?!") гарантированно не возникнет.
Что делали оверхайперы? Одни засирали эту простую и понятную схему тысячами типов-терминаторов (воробьи — воробьиноклювые — воробьинообразные — ... — серокрылые — птицевидные — ... — зерноядные — ... — летающие динозавры) до полной нечитаемости. Другие засирали эту простую и понятную схему неумеренной детализацией ("воробей" состоит из костей 100 видов, примерно 1.314 костей каждого вида, тканей 100 видов, а расфазовка отдельного "маха" приведена на той же схеме) до полной нечитаемости. Третьи, совсем никчемные, выводили бескрылых воробьев, оброщенных мехом, и получали таким образом белку-летягу (хороший пример из жизни — если повар наш не врет — можно найти тут: http://burrarum.livejournal.com/32707.html).
Грамотная декомпозиция на значимые сущности должна быть переложена на ЯП без изменений, с сохранением всех отношений, в т.ч. наследования реализаций.
Re[2]: Почему объектно-ориентированное программирование пров
Здравствуйте, gandjustas, Вы писали:
SV.>>>>Коль скоро это так, вас, конечно же, не затруднит привести пример программы, которая не является моделью? G>>>Вот сейчас занимаюсь веб-приложением для автоматизации проектного управления. У меня там нет ни одного объекта, который является моделью объекта реального мира. SV.>>Техзадание на ваше приложение имеется? Оно — модель реальности, а ваш код — перевод этой модели с русского или английского языка на ЯП, а, следовательно, тоже модель. G>См выделенное. SV.>>В то, что при переводе ключевые сущности оказались заменены другими, я не очень верю, но если поверить, то гордиться тут нечем. А если считаете, что есть чем, расскажите больше. G>Спокойно. Проект на sharepoint, основные объекты с которым приходится работать это "сайт", "список" и "элемент списка". Причем ни один из них никак не фигурирует ни в каких ТЗ.
Это как с утиной типизацией — контракт задается неявно, но это не значит, что его нет. Чтобы в этом убедиться, попробуйте пасхалкой встроить тетрис. Это к вопросу о ТЗ.
Что касается SPWeb, SPList и SPListItem. Вы, как опытный специалист, конечно же, не будете спорить, что с инженерной точки зрения ШП — это не какой-то там "портал" (это маркетинговое блаблабла), а база с человеческим лицом? Сетевая, многоклиентская, за имением GUI не требующая SQL для внесения/редактирвоания/удаления записей, обладающая адаптированными типами (например, нормальный документ вместо неясного БЛОБа). Ну и, конечно, с недоразвитой реляционностью. База данных же сама по себе очень старая модель писчебумажных архивов. Которые, в свою очередь, используются для моделирования: выявление ключевых значений для колонок — это выявление значимых сущностей модели.
Короче, возьмите рулон листов ширины А0. Расчертите на первом листе рулона таблицу с пустыми графами (меньше 100 колонок, считать лень — точное количество можно узнать из [AllUserData]). Поздравляю, только что вы создали "объект реального мира", который моделируется классом SPList. По мере заполнения таблицы, крутите рулон и дочерчивайте колонки. Разработчикам ШП удалось очень точно смоделировать эффект "зае@#$ся", который при этом возникает — я имею в виду дикие тормоза при обработке нескольких тысяч элементов. Каждый раз, когда вы будете вписывать в название колонки текст "размер, мм", вы опять же создаете объект реального мира — SPField. Одна строка на бумаге поперек колонок — SPListItem, а чулан с рулонами — SPWeb.
Нет такого софта, который не является моделью чего-то. Иначе он бесполезен.
SV.>>Каким образом обеспечивается is-a, вот о чем речь. G>Именно, я тебе выше написал что много других способов. Причем наследование реализации — далеко не самый лучший.
Это утверждение бессмысленно вне контекста. В контексте одних объектов — не самый лучший, других — самый лучший, третьих — худший. Должен ли я приводить соответствующие примеры?
SV.>>Должны, конечно, если мы хотим иметь код, который проще писать, читать и понимать. G>стати практика показывает обратное, если мы на этапе проектирования будет модели 1-в-1 перекладывать в структуры классов то получится *опа. G>Возникают type-test там где не надо, double dispatch, визиторы и прочие гадости.
Ваша практика показывает?
Re[26]: Почему объектно-ориентированное программирование про
Здравствуйте, samius, Вы писали: S>Эквивалентным по какому признаку? S>Я не очень понимаю, к чему вопрос.
Вы понимаете, что значит identity в ООП? Это гарантированный способ идентифицировать конкретный объект.
В обычной архитектуре достигается благодаря понятию ссылки на объект. Для ссылок определена такая операция сравнения, которая даёт истину в том случае, если ссылки указывают на один и тот же объект, и ложь в противном случае.
Именно благодаря идентичности вообще есть возможность послать сообщение заданному объекту.
Кроме того, очень важным моментом является то, что идентичность всегда сохраняется. То есть если мы получили ссылку r1 на объект о1, а через произвольное "время" мы получили ссылку r2 на тот же объект, то r1 == r2. Независимо от того, изменилось ли состояние o1 или нет.
Если у нас нет такого свойства, то это однозначно не ООП.
S>Сомневаюсь S>Один из основных инструментов ООП — возможно. Но не основа. S>>Если у нас нет идентичности (т.е. identity, которая, имхо, на самом деле идентифицируемость) то это вообще не ООП а непонятно что. S>Откуда это следует?
Из определения. В ООП программа представляется набором объектов, обладающих
— идентичностью, т.е. возможностью послать сообщение конкретному объекту
— поведением, т.е. возможностью реагировать на сообщения некоторым образом
— состоянием, т.е. возможностью варьировать своё поведение в зависимости от истории принятых сообщений.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re: Почему объектно-ориентированное программирование провали
Здравствуйте, Игорь САВЧУК, Вы писали:
ИС>Среди множества идей, которые звучат красиво скорее в теории, чем на практике, объектно-ориентированное программирование занимает особое место. Попробуем разобраться и ответить на главный вопрос, почему всё же объектно-ориентированное программирование провалилось?
А что, какое-то другое программирование не провалилось? По крайней мере ООП победила популярностью и коммерциализацией. А где другие парадигмы? ФП только-только набирает популярность да и то только в своих специфических направлениях.
Может быть вообще любое программирование какое мы знаем провалилось, как таковое?!
Может быть кроме парадигмы нужна ещё методология разработки проекта!? — какие-то правила, дисциплина, общие стандарты и т.п. ?
Бди!
Re[2]: Почему объектно-ориентированное программирование пров
G>Наследование реализации создает отношение is-a (кроме приватного наследования в C++), тогда как композиция не создает.
это есть часто повторяемое заблуждение.
если брать пару: круг и эллипс, то можно для круга наследовать реализацию от эллипса и "открутить лишнее", а можно
для эллипса наследовать реализацию от круга и "прикрутить дополнение".
и оба подхода будет верными в том, или ином контексте.
проблема начинается, когда люди начинают считать, что наследуя реализацию — они при этом автоматически получают наследование внешнего контракта, а также что получили отношение is-a.
Re[13]: Почему объектно-ориентированное программирование про
V>>Ну так в ООП объект и представляет из себя элемент модели. Класс — это уже термин из области типов, к понятию "объект" в общем случае ортогональный. G>Ага, только в типизированных языках каждый объект имеет некоторый класс. Так что не ортогональный.
Каша.
Какая именно типизация имеется ввиду, статическая или динамическая? И при чем тут эта частность с типизацией, если полно не ОО-языков с обоими видами типизации и без типизации вообще, точно так же как полно ОО-языков опять же с обоим видами типизации и без типизации вообще. Классы могут быть поддержаны системой типов, а могут быть и нет. Класс — это "шаблон" объекта и одновременно type identity для целей типизации. Но если типизации нет, то и классы зачастую не нужны. И тогда мы наблюдаем "шаблоны" объектов в чистом виде, как в JavaScript. Фактически там нет классов, там есть "образцы" объектов.
G>Наследование и агрегирование — разные вещи.
Двойка тебе, коллега. Иди учи уроки.
V>>В общем, ты опять попутал причину и следствие. Миксины не самоцель, а инструмент, пригодный для обхода ограничений языка. G>Для обхода ограничений ООП. Ну об этом я и говорю.
Ничего-то ты не понимаешь.
Re: Почему объектно-ориентированное программирование провали
Здравствуйте, Игорь САВЧУК, Вы писали:
ИС>Среди множества идей, которые звучат красиво скорее в теории, чем на практике, объектно-ориентированное программирование занимает особое место. Попробуем разобраться и ответить на главный вопрос, почему всё же объектно-ориентированное программирование провалилось?
Допустим, что ООП таки провалилось, или не состоялось. Так почему же собственно?
В итоге, как я понимаю, в качестве ответа на вопрос "почему" предлагается следующее:
Грэм:
половина всех концепций ООП являются скорее плохими, чем хорошими, в связи с чем он искренне сочувствует ООП-программистам, тогда как вторая половина от оставшихся концепций — и вовсе не имеет никакого отношения к ООП,
Я с ним согласен в отношении второго. Но причину провала это не объясняет.
Степанов:
Но реально никто не начинает с аксиом, все начинают с доказательств....
Именно из-за этой неразберихи в ООП так популярен рефакторинг — из-за ущербности парадигмы вы просто обречены на переписывание программы, уже в тот самый момент, когда только задумали её спроектировать в ООП-стиле"
разве в других парадигмах рефакторинг исключен? Я вообще думаю что рефакторинг это следствие отношения к предварительному проектированию и собственно самому коду.
Гэбриел:
По мнению Ричарда, абсолютно с точностью тоже самое произошло и с ООП, которая в 80-ых годах была провозглашена "серебряной пулей" в "борьбе со сложностью программистского бытия", была искусственно и безальтернативно навязана в академической среде, причем мифы, которые кочуют из учебника в учебник по ООП "часто забавны и высосаны буквально из пальца".
(Кстати, там бардак с окончаниями, если под ООП подразумевается программирование, а не парадигма. А в заголовке именно программирование — оно)
Да, возможно было навязано. Некрасиво, согласен. Но это не причина провала.
Возможно стоит сменить название на следущее: Что считают гуру причиной провала ООП?
Re[4]: Почему объектно-ориентированное программирование пров
Здравствуйте, Ikemefula, Вы писали:
V>>Нужен меньше. По опыту плюсов, чем меньше создаешь классов, т.е. чем больше функциональности удается разнести в свободные ф-ии, тем меньше надобность рефакторинга.
I>И наоброт — чем больше функциональности в свободных функций, тем сильнее нужен рефакторинг, например из за того, что слишком много функций зависит от одного класса.
Здравствуйте, gandjustas, Вы писали:
SV.>>Сама "сомнительность" наследования реализации — следствие тех самых overhype и втыкания во все дыры. Сомнительным может быть конкретное применение, но не прием. Почему? Потому, что наследование реализации — объективное явление (вне нашего сознания и интерпретаций). И если оно наблюдается в моделируемом куске жизни, повторение его в модели (а любой софт это модель) делает ее полезнее. G>Но далеко не любая программа является моделью части реального мира. Даже наоборот, программ где такой подход оправдан исчезающе мало.
Коль скоро это так, вас, конечно же, не затруднит привести пример программы, которая не является моделью?
SV.>>Например, и "воробьи", и "вороны" (обобщенно — "птицы") имеют в своем составе "крылья" и летает, "махая" ими. "Воробьи" являются "птицами", и летают как любая другая "птица" — "махая" (по-птичьи) "крыльями" (птичьими). НЕ ПОТОМУ, что внутри у "воробья" сидит абстрактная "птица" или какой-нибудь вполне конкретный "летатель", и летает за него (при этом, имеет форму черного ящика, то есть летает неизвестно как). При написании софта, надо повторять это объективное отношение (подкласс <вид "воробей"> наследует такое поведение, как полет, у суперкласса <класс "птиц">), потому, что такой софт проще писать, читать и понимать, а также потому, что дурацких противоречий ("Ва-а-ась, как оно теперь у нас будет плавать, с такими-то крыльями?!") гарантированно не возникнет. G>Отношение is-a отлично достигается без наследования реализации. Интерфейсы (выше ты привел именно наследование интерфейсов), typeclasses в хаскеле, ducktyping в динамических языках. Это все позволяет выстраивать отношения is-a.
Откуда взялась такая странная цель — отношение is-a? Моя цель, извините, это код, который проще писать, читать и понимать, и с гарантированным уничтожением риска противоречий (если какие-то отношения непротиворечивы в природе, значит в модели они тоже будут такими же). Если не подменять прагматические цели фантомными, то я же на все ответил, прочитайте еще раз.
Возьмем, например, старый добрый COM. Он регламентирует только наследование интерфейсов. Дальнейшее — дело ваше. Можно строить параллельную иерархию классов с (возможно, множественным) наследованием реализаций, можно прибегнуть к агрегированию. Специально этот случай я и рассмотрел:
>НЕ ПОТОМУ, что внутри у "воробья" сидит абстрактная "птица" или какой-нибудь вполне конкретный "летатель", и летает за него (при этом, имеет форму черного ящика, то есть летает неизвестно как).
Что касается утиной типизации, то это способ перейти от явных контрактов к неявным, сэкономив на объявлении контракта, и к делу (способу выполнения контракта) не относится.
SV.>>Грамотная декомпозиция на значимые сущности должна быть переложена на ЯП без изменений, с сохранением всех отношений, в т.ч. наследования реализаций. G>Выделенное необоснованно.
Очень странно, что именно выделенное, поскольку это пример. Как может быть обосновано утверждение, но пример к нему — нет?
G>Ты в принципе попал в ту же проблему, куда попадают все "философы ооп". Они поголовно считают что все достижения ООП недоступны в других парадигмах, а на деле даже наоборот.
А это смотря что считать достижениями. Если is-a, то это не достижение, а тип отношения. Если код, который проще писать, читать и понимать, и с гарантированным уничтожением риска противоречий, то парадигма ООП может работать как на него, так и против. Примеры и того, и другого я привел.
Re[2]: Почему объектно-ориентированное программирование пров
Здравствуйте, Vlad_SP, Вы писали:
V_S>вот именно "разобраться и ответить на главный вопрос" — не получилось. Вся статья — исключительно пересказ чужих высказываний (отнюдь не первой свежести, кстати), собственных же тезисов, их доказательства и выводов автора — ноль целых, ноль десятых. Если RSDN Magazine считает возможным опубликовать такую статью — стыдно за RSDN.
Ну, как познавательная (стартовая) инфа — сойдёт.
Вселенная бесконечна как вширь, так и вглубь.
Re[2]: Почему объектно-ориентированное программирование пров
Здравствуйте, shrecher, Вы писали:
S>Здравствуйте, Игорь САВЧУК, Вы писали:
ИС>>почему всё же объектно-ориентированное программирование провалилось? S>Громкое и бессмысленное название, скорее подходящее для Грета.вру. Да и сама стая это жонглирование именами и цитатами, которые вырваны из контекста. S>На деле, мейнстримные языки -- C++, Java пр, вовсю используют объектно-ориентированное программирование. Куда же оно проволилось-то?
писать в стиле ООП можно и на чистом Си. я так и поступаю. вот на плюсах есть класс с публичным контрактом, а "унутрення" имплементация скрыта. у меня все точно так и есть. вот h файл. в нем pubic функции. эти функции вызывают другие функции. у меня они вызываются по указателю, и потому они обладают всеми чертами виртуальных функций и легко перегружаются. так что концепции ООП не требуют специальной языковой поддержки, и могут быть реализованы и на чистом си.
кстати, в bat файлах нету функций. а мне нравится процедурное программирование. средствами bat файлов (без вовлечения exe) дописал языковое расширение, позволяющее программировать командные файлы в процедурном стиле. а отсюда уже и до ООП недалеко, что и неудивительно, т.к. ООП программы все равно транслируются в машинный код, который ничего об ООП не знает.
вопрос о провале ООП действительно встает на манагеровских митингах. и вердикт выносится один -- вот обещали нам, что ООП решит проблемы программирования и что программировать станет проще, качественнее, быстрее. но... этого не произошло. в тоже время сейчас набирает популярность рубин, который хоть и тормозит как асфальтовый каток, но действительно ускоряет программирование, попутно понижая порог входимости (плюсы, наоборот, его повышают). а рубин это как бы не ООП. и он набирает силу...
americans fought a war for a freedom. another one to end slavery. so, what do some of them choose to do with their freedom? become slaves.
Re: Почему объектно-ориентированное программирование провали
ИС>Авторы: ИС> Игорь САВЧУК
ИС>Аннотация: ИС>Среди множества идей, которые звучат красиво скорее в теории, чем на практике, объектно-ориентированное программирование занимает особое место. Попробуем разобраться и ответить на главный вопрос, почему всё же объектно-ориентированное программирование провалилось?
"Lisp-еры наступают: ООП-шники остались выброшенными на улицу".
Такой заголовок я бы дал этой статье, будь я ее автором.
Гэбриэлу в оппоненты нужно было кого-нибудь с форумов RSDN поставить.
От была бы дискуссия !
Re[2]: Почему объектно-ориентированное программирование пров
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>Этот прием совсем не нов и аппелирует не к сознанию, а к подсознанию. Его цель — заставить читающего подсознательно согласиться с высказываемой точкой зрения. Для многих высказаться вопреки общепринятой точке зрения очень нелегко, поэтому когда ему что-то подается как общепринятая точка зрения, он подсознательно вынужден с ней согласиться.
Это в том случае когда сам тезис (провалилось) спорен или вовсе не верен. А если — нет, например "Почему X провалился на выборах?" До выборов, такой вопрос будет некорректен, но после — вполне, если X и в самом деле их не выиграл.
Re[5]: Почему объектно-ориентированное программирование пров
Здравствуйте, Undying, Вы писали:
U>С точки зрения науки совершенно не важно с чем согласны или нет Гофман и Хатч, важно то, что объяснение предлагаемое Гофманом противоречит фактам, а, значит, является неверным.
Вот так вот греки и отвергли гелиоцентрическую систему...
ЗЫ Разбудили во мне тролля. Хотя, под такой статьёй — можно.
Re[15]: Почему объектно-ориентированное программирование про
Здравствуйте, gandjustas, Вы писали:
SV.>>Ну что, опять самоцитироваться? Я уже написал, какому объекту реального мира сответствует список. G>Нет, ты придумал этот объект. Список не является результатом моделирования.
Как по-вашему работали отделы статистики до изобретения компьютеров?
SV.>>Если у нас появился другой прибор, значит поменялся окружающий мир. И наша ООП-модель ему больше не соответствует. Разумеется, не надо пытаться натягивать ее до конца, а надо взять и отрефакторить ОМ в очередной версии. Рефакторинг, конечно, сведется к тому, что ILightDevice и ISoundDevice будут разнесены и не связаны между собой.
G>А зачем что-то делать, а потом рефакторить, если можно заранее избежать проблем? Ведь способ с двумя интерфейсами решает все проблемы, про которые ты тут рассказываешь, а наследование эти проблемы создает.
Затем, что мой пример — из жизни, а ваш — из области фантастики. Зная, однако, что некоторые клиенты/менеджеры рождены, чтоб сказку сделать былью, я не стал отнекиваться, а написал, что должен делать хороший ООПер в такой ОЧЕНЬ маловероятной ситуации.
Избегать заранее проблем и портить при этом хороший код не надо.
G>Кстати выделенное — бред. Мир не меняется, меняется набор наших знаний о нем.
Мы его меняем.
SV.>>Но даже при этом сохранится смысл наследования реализаций (а о нем мы спорим, как о самом спорном приеме ООП, не так ли?), поскольку оба прибор по-прежнему имеют датапорт и умеют принимать в него строки (то есть, имеют объект класса Port и метод Send(string) к нему).
G>А зачем тогда класс прибора нужен вообще? Создаются объекты, которые получают на вход Port (вернее IPort) и отправляют команды.
Затем, чтобы ваш пользователь мог включать и выключать лампочки и бикать спикером, не создавая объекта Port и не отдавая его на вход. Этим занимается фабрика, как я и написал. Возлюбите своего пользователя, дабы он не возлюбил вас через саппорт.
G>Ну и все. Связь с "реальным миром" (который фактически набор знаний) мы потеряли, от этого программа стала более устойчивой к изменениям этого "реального мира".
Re[10]: Почему объектно-ориентированное программирование про
Здравствуйте, SV., Вы писали:
SV.>Чтобы не разводить пустословие, предлагаю вернуться к моему примеру с приборами. У ganjustas'а, как оказалось, "нет времени" приводить пример API без наследования реализаций, а я бы с удовольствием обсудил.
Это лишено какого либо смысла. Потому что говорим мы о разном. Я о том, что, де-факто, так сложилось, что наследование реализации приносит больше вреда, чем пользы, а ты пытаешься доказать, что все таки иногда можно применить и по делу. Да, можно. Особенно учитывая, что в большинстве мейнстрима альтернативы приводят к громоздкому синтаксису. Но, если разнести наследование интерфейсов и реализаций по независимым механизмам, языки от этого только выиграют.
... << RSDN@Home 1.2.0 alpha 5 rev. 1495 on Windows 7 6.1.7600.0>>
Здравствуйте, AndrewVK, Вы писали:
AVK>Здравствуйте, Zontin, Вы писали:
Z>>А в чем, де-факто, по-твоему, выражается этот вред?
AVK>Неоправданное повышение связности, уменьшение гибкости API.
Ясно. Значит можно не волноваться и продолжать использовать наследование реализации.
Re[24]: Почему объектно-ориентированное программирование про
V>>Ты уже заблудился. В приведенном тобой примере ты тестируешь PreAndPostDoerDecorator, т.е. вот этот код:
I>Конечно. Его и надо тестировать, а не ThirdParty. Это называется поведенческое тестирование
А мужики-то не в курсе.
Ты пока проверил сам факт вызова методов целевого класса. Вместо целевого класса была заглушка. Мои поздравления, это было впечатляюще! Тестирования целевого класса не будет? Коль методы находятся в наследнике, они не пусты, что-то делают. Где тестовое покрытие этих методов? А базовый класс заведомо надежен?
V>>Ты напиши изолированный тест для PreAndPostDecorator, который, например, нетривиально пользует базовый ThirdPartyClass. Вот что представляет интерес для тестирования.
I>Точно такой же подход.
Дык, покажи.
Re[22]: Почему объектно-ориентированное программирование про
Здравствуйте, samius, Вы писали:
S>>Тогда бы за хранение состояния отвечал бы клиентский код, вместо $iterator.MoveNext было бы $iterator=$iterator.MoveNext. S>Задача перебора будет решена, но это уже не паттерн Iterator
В узком смысле — да. В широком смысле — паттерн по-прежнему имеет смысл.
S>>Классика жанра — результатом вызова модифицирующих методов является новый объект. S>>См. напр. System.String. S>Но при этом исходный объект свое наблюдаемое состояние не меняет. Классика жанра основана именно на этом.
В принципе, да. С другой стороны, философия классики в том, что объект имеет право реагировать на сообщения с учётом своего состояния, и в том что другого способа узнать состояние объекта нет.
Вопрос, является ли неизменяемое состояние вообще состоянием или нет — весьма философский. Ну, то есть мы могли бы с тем же успехом считать объект вместе со встроенным состоянием объектом отдельного "класса" — ведь именно класс диктует поведение объекта. Итератор, показывающий на последний элемент списка, всегда вернёт null из MoveNext.
Есть ещё один щекотливый момент: что считать идентичностью в этом случае.
Два объекта в одинаковом состоянии неразличимы — нет способа "изменить" только один из них. Считать ли два состояния одного и того же объекта идентичными или нет?
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[8]: Почему объектно-ориентированное программирование пров
Здравствуйте, DarkGray, Вы писали:
G>>Вот сейчас занимаюсь веб-приложением для автоматизации проектного управления. У меня там нет ни одного объекта, который является моделью объекта реального мира.
DG>но значит у тебя модель другого мира. модель проекта, например.
Ничего не получится. ООП так же плохо подходит для описания "моделей первого порядка", как и для описания реального мира.
Возьмём тот же проект. Он обладает идентичностью и состоянием. Можем ли мы построить класс, описывающий объект "проект"?
Очень сомнительно. "Поведение" проекта не является прямой реакцией на происходящие с ним события; окажется, что детали того, как проект меняет своё состояние не являются для него "внутренне присущими". Ровно наоборот: ограничения на эволюцию состояний проекта определяются внешними по отношению к нему бизнес-правилами. Попытка инкапсулировать бизнес-правила внутрь класса "проект" обречена на провал.
Кроме того, на разных стадиях жизненного цикла поведение проекта настолько отличается, что мы затруднимся построить единый класс для описания этого поведения. С точки зрения ООП проект выглядит так, как будто его класс меняется радикальным образом. А в ООП связь класса с объектом является священной и неизменной.
Конечно же, паттерны для разрешения этого (и других) противоречия существуют и хорошо известны. Но их применение неизбежно приводит к тому, что мы получаем катастрофически далёкое от оригинальной модели описание.
В том же управлении проектами вместо "проекта" появятся какие-то абстрактные "issue", "transition", "attribute", "requirement" и мы быстро перейдём к программированию собственно прикладной логики на основе совсем другого "языка", в котором нет никакого ООП.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[6]: Почему объектно-ориентированное программирование пров
Здравствуйте, samius, Вы писали:
S>Получается что ООП — это сверху вниз, а ФП — снизу вверх? S>ИМХО, ООП не мешает продумывать тщательно как "протаскиваются" данные. Или можно сказать что мешает не ООП, а проектирование сверху в какой-то мере, или даже не проектирование а реализация сверху. Именно она обеспечивает нас неизбежным рефакторингом.
Не так. Оба подхода применимы для разработки снизу и сверху. Акцент не на "снизу vs сверху", а на "данные vs акторы". Что происходит при отталкивании от данных? Очень простая, но важная вещь: мы выполняем гораздо больший анализ происходящего ДО созревания цельной картинки, то бишь дизайна, в голове. Мы банально начинаем обладать большей информацией. В советской школе программирования учили разрабатывать сначала данные и алгоритмы их обработки. А выделение в модули — это уже результат анализа получаемого решения, фактически выходит автоматически из анализа кол-ва связей по передаче данных, и деления программы по принципу наибольшей связанности внутри модуля и наименьшей — м/у модулями (древнейший принцип, идет еще из электроники/автоматики). Разве можно это разделение выполнить, не обладая достаточно подробным списком этих самых связей, то бишь не обладая достаточно полным списком используемых алгоритмов и структурами оперируемых данных? В общем, разработка сверху в ООП в клиническом своем варианте, за который его критикуют — это предварительное разделение на "модули" то бишь относительно независимые единицы — объекты, без обладания достаточной информацией о подробностях реализации. Ну и потом, по мере реализации, эти подробности всплывают, уточняется наше собственное видение решения, и мы наше первоначальное решение вынуждены модифицировать.
В общем, проблема не в ООП, а в заблуждении относительно того, что предварительная стадия анализа может быть минимальной для большой задачи. Не обращал тут внимание на мнения коллег, что иерархии/системы ООП относительно неплохо работают на небольших и средних задачах (уточнять размеры сейчас не будем)? ИМХО, это от того, что вероятность допустить ошибку при "беглом" анализе на небольших системах меньше.
Я, размеется, не призываю всех тут же удариться в глубокий анализ и прочее. Тем более, что на некоторых языках/средах/IDE пошаговый рефакторинг может оказаться более дешевым решением, чем углубленный предварительный анализ. Опять же, пошаговость разработки позволяет получать успешные результаты на каждом шаге, что тоже есть гут, бо позволяет уточнять функциональные требования через обратную связь с заказчиком. Но описанные наблюдения "удачных кейзов" стоит держать в голове, и пытаться формировать в ООП заведомо относительно небольшие "экосистемы" типов, дабы переделки внутри этой экосистемы как можно меньше задевали окружающее. Мое замечание относительно ФП в предыдущем посте лишь показывало, что такая независимость при проектировании от данных получается автоматически, т.е. каждая такая экосистема сама формируется вокруг конкретной структуры данных и алгоритмов по трансформации/обработки этих данных.
S>Да, т.е. двумя словами — рефакторинг в ООП может быть сведен к минимуму при некоторых правильных привычках. И обилие рефакторинга в ООП не может быть предъявлено как причина его провала в качестве серебрянной пули. Это я и имел ввиду изначально.
Разумеется! Проблема не может быть в ООП-языках, предоставляющих "три кита", наивно жаловаться на молоток, если гвоздь криво вбил. Проблема в руках. А называя вещи своими именами — проблема в том, что в последние лет 10-15 особенно заметна попытка игнорировать, скажем так, академические вещи из разработки ПО. Народ бросается на поверхностность, типа ООП-паттернов GOF, контейнеров IOC и XML. Овладев ими, начинает считать что всё знает и всё умеет. Сему способствовал бешенный рост спроса на программистов все 90-е, который продолжается до сих пор и объективно предъявляет к массе программистов сейчас заниженные требования. Например, основные требования — знать что есть ООП (если набирают програмистов на ООП-языки), знать основные паттерны ООП и библиотеки целевого языка. И еще этот, как его... XML. Это что, требования к профессионалу-программисту? Блин, сегодня рядовые программисты самостоятельно проектируют доверенные им куски ПО такой сложности, которые раньше проходили через руки аналитиков и архитекторов. ИМХО, требования к программистам ввиду этого должны были вырасти, а не понизиться. И удобные IDE не сей разрыв компенсировать не способны, увы. В общем, що маємо то маємо.
V>>Ну дык правильно. Ведь эти классы обычно отражают первоначальное видение дизайна, т.е. не случайны. И в этих классах могут находится нужные нам данные, поэтому мы и пихаем функциональность в них, дабы не нарушать нашу любимую "инкапсуляцию". S>Меняется видение — нужно менять класс, а не пихать в него пока он не лопнет. Менять проще пока класс и его ответственность обозримы.
Это ты подтверждаешь верность исходного постулата. Конечно, классы меняют, модернизируют. Но не заранее, а когда налицо симптомы такой надобности. Не факт, что перед каждым добавлением новой функциональности стоит заранее всё рефакторить. Может так оказаться, что это была последняя добавленная функциональность в класс, и нафига тогда делать работу, которую никто не оценит? В том смысле, что результаты декомпозии не будут востребованы т.е. не будет последующего добавления функциональности в этот участок кода.
S>Правильное слово какое. По поводу размеров грануляции соображения следующие: крупная грануляция тяготеет к рефакторингу, а мелкая — к усложнению композиции на верхнем уровне. И это вне парадигм. Решение может быть в ведении дополнительных уровней/этажей абстракции.
Они и так сами получаются. Деление на слои процесс как бы автоматический, управляется сложностью единичного элемента, которую может обозреть человек. Какое там правило для ф-ий и методов — не больше 1-2 экранов кода? Примерно так.
S>Просто эти 4 буквы отпугивают любителей разоблачать, понижают температуру дебатов и дают понять что я не настроен воинственно. В общем, на всякий случай
Почему нет, кстати? Если воинственность будет означать большее желание что-то доказать и в итоге означает большую аргументированность и полезность информации — это даже кул. Спор с интересным собеседником во-первых, раскручивает его на дележ информации, которую он бы в ответ на простой вопрос давать бы не стал (хотя бы из-за лени или снобизма). Ну и построение собственных аргументов всегда способсвует наведению порядка в собственной же голове, что тоже всегда гут. Так что если до обкладывания органами не доходит, то ради бога. Для поддержания формы и ясности мысли, так сказать.
Re[2]: Почему объектно-ориентированное программирование пров
Здравствуйте, samius, Вы писали:
S>Возможно стоит сменить название на следущее: Что считают гуру причиной провала ООП?
Не берусь говорить за гуру, на мой взгляд основная причина провала это наследование реализации.
Простейшая задача имеет порой заумную реализацию в ООП. Например требуется реализовать сравнение на равенство определенное следующим образом: два объекта равны, если все их составные части попарно равны. На шаблонах C++ реализация записывается буквально в соответствии с определением и в одну строку, в ООП, на том же C++, или на Java, или на С# начинаются пританцовывания на ровном месте с проверкой типа и т.п.
Re[13]: Почему объектно-ориентированное программирование про
S>Никакой грани того проекта, в терминах которго мыслит пользователь эти объекты соответствовать не будут.
голословное утверждение
S>Упрощённый пример на ту же тему — детям всегда рассказывают про прямоугольники и квадраты при иллюстрации ООП. А в жизни там ровно один тип данных — Polyline, никакого красивого наследования и полиморфизма.
не будет, если прямоугольники и квадраты не предлагает специфичного поведения, по сравнению с polyline
и будет — если предлагает.
при этом ты говоришь, о каких-то своих заморочках, если брать реальные реализации, то там есть и прямоугольники, и polyline-ы.
в wpf — есть и то, и другое,
в svg — тоже есть
DG>>спорно. DG>>например, operator + , в общем случае, описывает поведение не только своего объекта, но при этом operator + является частью класса и частью ООП. S>Догадываюсь, что вы имеете в виду, но всё же покажите код этого оператора, чтобы показать, как он влияет на поведение чужих объектов. Желательно ещё чтобы это всё-таки были объекты, а не экземпляры АТД с value-семантикой.
допустим мы описываем тип int с насыщением
тогда такой тип удобнее описать как
class BoundedInt<Range>
{
public BoundedInt(int value)
{
if (value < Range.MinValue)
value = Range.MinValue;
else if (value > Range.MaxValue)
value = Range.MaxValue;
this.value = value;
}
public int value;
static BoundedInt<Range> operator + (BoundedInt<Range> v1, BoundedInt<Range> v2)
{
return new BoundedInt<Range>(v1.value + v2.value);
}
}
DG>>что в этом такого странного? и в чем противоречие с ООП? S>Противоречие не с ООП. Противоречие — с идиотским предположением о том, что ООП предлагает лепить классы с сущностей модели. Если у вас встанет задача смоделировать управление стройкой, то в вашем коде не будет никаких TКран, ТБульдозер, ТКаменщик или ТЦементМарки400.
не будет, если будет абстрактное моделирование стройки — например, на уровне проектных граней, например, распределения ресурсов или там начисление зарплаты
но если будет моделирование именно стройки, например, игра-стройка, то все эти объекты появятся.
S>Ничего из того, во что можно ткнуть пальцем на стройке, не проникнет в реальную модель вашей программы. Зато будет дохрена всяких штук типа TEditingSession, TChange, TMainWindow и прочего, что моделирует устройство исключительно самой программы. Никто в здравом уме не будет наследовать TПрораба от ТБригадира. Будет (в лучшем случае!) класс TEmployee. А то и его не будет — прекрасно обойдёмся тупо DataSet/DataRow, потому что никакого полиморфизма поведения у работников на стройке не предусмотрено.
понятно, если речь идет чисто о задаче начисления зарплаты на стройке, то да — никаких прорабов и бригадиров не будет.
но если речь идет о моделировании взаимодействия между прорабом и бригадиром, то прорабы и бригадиры появятся.
разные классы появляются, когда необходимо описать разное поведение.
если мы при моделировании отойдем слишком далеко, что нам уже будет пофигу — это стройка, магазин или дет.сад — то да, никаких объектов прораб, кирпич и арматура не будет.
если мы при моделировании подойдем слишком близко, и будет моделировать мир на уровне атомов — то да, тоже никаких объектов прораб, кирпич или арматура не будет.
да, все эти объекты появятся лишь только если мы будем моделировать именно саму стройку, а не что-то еще.
имхо, ты на основе задач — а давайте мы напишем еще одну программу для начисления зарплаты на стройке, делаешь вывод о том, что для описания модели стройки — не нужны объекты прораб, бригадир или кирпич.
а это логически неверный вывод.
Re[4]: Почему объектно-ориентированное программирование пров
Здравствуйте, samius, Вы писали:
S>Откуда фраза, кстати? Что там было вышесказанного?
Да вот, из списка литературы.
S>Т.е. Гэбриэл ожидал что использование объектной парадигмы приведет к чему-то важному для него, но этого не случилось. Причин этому может быть несколько: Гэбриэл что-то делал не так, либо действительно парадгима не в состоянии обеспечить это. Вот это последнее, наверное и может быть причиной утраты доверия. Но не тот факт что ООП была навязана или свалилась с неба в качестве откровения.
Провал кукурузы в 60-х был обусловлен не какими-то имманентными свойствами кукурузы, а как раз тем, что она свалилась с неба.
Здравствуйте, Pavel Dvorkin!
PD>В названии статьи используется весьма не новый ... приём... Тезис, который по меньшей мере спорный, подается как бесспорный...
PD>Этот приём совсем не нов...
Dijkstra: "A case against the goto statement" => Wirth: "The goto statement considered harmful"
Архив Дейкстры
PD>...в научной и технической литературе он должен быть безусловно и категорически осуждён.
Здравствуйте, Vlad_SP, Вы писали:
V_S>вот именно "разобраться и ответить на главный вопрос" — не получилось. Вся статья — исключительно пересказ чужих высказываний (отнюдь не первой свежести, кстати), собственных же тезисов, их доказательства и выводов автора — ноль целых, ноль десятых. Если RSDN Magazine считает возможным опубликовать такую статью — стыдно за RSDN.
Мы считаем, что полезны различные точки зрения. Тем более, что данной точки зрения придерживаются не мало людей многие из которых весьма авторитетны.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[2]: Почему объектно-ориентированное программирование пров
W>Кстати, в науке такое "повторное использование" не очень приветствуется — нужна фальсифицируемость. А вот при построении практических систем это часто нужно...
Ну судя по http://elementy.ru/lib/430484 физики "повторным использованием" все-таки занимаются, правда стыдливо обзывают эфир "скалярным полем"
Re[3]: Почему объектно-ориентированное программирование пров
Здравствуйте, мыщъх, Вы писали:
М> в тоже время сейчас набирает популярность рубин, который хоть и тормозит как асфальтовый каток, но действительно ускоряет программирование, попутно понижая порог входимости (плюсы, наоборот, его повышают). а рубин это как бы не ООП. и он набирает силу...
Ruby что-ли (или РубиН :D)? Ну и в каком месте он не ООП? там всё объекты и методы...
Re[2]: Почему объектно-ориентированное программирование пров
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>В названии статьи используется весьма не новый демагогический прием. "Почему оно провалилось...". Тезис, который по меньшей мере спорный, подается как бесспорный (оно провалилось, вне сомнения), и остается лишь выяснить — почему ?
Этот прием в зависимости от контекста может быть как демагогическим, так и полемическим. На мой взгляд в данном случае имеем дело с полемическим.
PS. Встречается еще такой демагогический прием, когда полемический прием объявляется демагогическим. И этот прием полемическим уже не бывает никогда.
Re[3]: Почему объектно-ориентированное программирование пров
Здравствуйте, igna, Вы писали:
I>PS. Встречается еще такой демагогический прием, когда полемический прием объявляется демагогическим. И этот прием полемическим уже не бывает никогда.
По-моему, это утверждение является демагогическим по твоему же определению.
Re: Почему объектно-ориентированное программирование провали
"Ну и где мы теперь, с этой вашей красивой теорией относительности, кто-нибудь может мне назвать хоть какие-то реально-практические результаты её применения в вашей обыденной жизни после целого века её ковыряния и массового насаждения?"- как всегда язвительно вопрошает Гэбриел.
Гэбриел не в курсе про существование GPS что ли?
Re[7]: Почему объектно-ориентированное программирование пров
Если спросишь , в чем разница, то ответ прост — в акценте. В первом случае акцент на то, что оно провалилось, это вне сомнения, и остается лишь выяснить, почему. Во втором случае такого акцента нет, просто делается некоторое утверждение, которое автор намерен аргументировать.
Здравствуйте, мыщъх, Вы писали:
S>>На деле, мейнстримные языки -- C++, Java пр, вовсю используют объектно-ориентированное программирование. Куда же оно проволилось-то? М>писать в стиле ООП можно и на чистом Си. я так и поступаю. вот на плюсах есть класс с публичным контрактом, а "унутрення" имплементация скрыта. у меня все точно так и есть. вот h файл. в нем pubic функции. эти функции вызывают другие функции. у меня они вызываются по указателю, и потому они обладают всеми чертами виртуальных функций и легко перегружаются. так что концепции ООП не требуют специальной языковой поддержки, и могут быть реализованы и на чистом си.
Если тебе нравится процедурное программирование, зачем ты пытаешься кирпичом гвозди заколачивать, реализуя ООП практики "на чистом Си"?
М>кстати, в bat файлах нету функций. а мне нравится процедурное программирование. средствами bat файлов (без вовлечения exe) дописал языковое расширение, позволяющее программировать командные файлы в процедурном стиле. а отсюда уже и до ООП недалеко, что и неудивительно, т.к. ООП программы все равно транслируются в машинный код, который ничего об ООП не знает.
А почему именно ООП? Разве программы, написанные в процедрном стиле, не транслируются в машинный код?
М>вопрос о провале ООП действительно встает на манагеровских митингах. и вердикт выносится один -- вот обещали нам, что ООП решит проблемы программирования и что программировать станет проще, качественнее, быстрее. но... этого не произошло. в тоже время сейчас набирает популярность рубин, который хоть и тормозит как асфальтовый каток, но действительно ускоряет программирование, попутно понижая порог входимости (плюсы, наоборот, его повышают). а рубин это как бы не ООП...
Автор Ruby с тобой не согласен:
Yukihiro Matsumoto has stated, "I wanted a scripting language that was more powerful than Perl, and more object-oriented than Python. That's why I decided to design my own language". Он явно пишет то хотел more object-oriented язык.
Если руки золотые, не важно из какого места они растут.
Re[3]: Почему объектно-ориентированное программирование пров
Здравствуйте, мыщъх, Вы писали:
М>Здравствуйте, shrecher, Вы писали:
М>вопрос о провале ООП действительно встает на манагеровских митингах.
Итересно, почему вопрос встает на манагеровских митингах, не должны ли программисты или архитекты об этом заботится? Или в Макафи манагеры лучше рабираются на чем код писать? Хе-хе.
Re[3]: Почему объектно-ориентированное программирование пров
Здравствуйте, Michael7, Вы писали:
M>Здравствуйте, Pavel Dvorkin, Вы писали:
PD>>Этот прием совсем не нов и аппелирует не к сознанию, а к подсознанию. Его цель — заставить читающего подсознательно согласиться с высказываемой точкой зрения. Для многих высказаться вопреки общепринятой точке зрения очень нелегко, поэтому когда ему что-то подается как общепринятая точка зрения, он подсознательно вынужден с ней согласиться.
M>Это в том случае когда сам тезис (провалилось) спорен или вовсе не верен. А если — нет, например "Почему X провалился на выборах?" До выборов, такой вопрос будет некорректен, но после — вполне, если X и в самом деле их не выиграл.
Да, но на выборах есть арбитр и объективный критерий -- подсчет голосов. В утверждении про ООП сплошной субъективизм.
Re[2]: Почему объектно-ориентированное программирование пров
М>>кстати, в bat файлах нету функций.
В>как это нет — есть. Вот пример:
афигеть! я и не знал даже. у меня попроще было.
call %0 --func func_name arg1...argN
а в начало файла воткнут фрейморк, который видит в первом аргументе '--func' и вызывает функцию func_name с аргументами, возвращаясь на место вызова автоматом. работает со всеми версиями даже с древней досей. а под досей функций не было ;+(
americans fought a war for a freedom. another one to end slavery. so, what do some of them choose to do with their freedom? become slaves.
Re[2]: Почему объектно-ориентированное программирование пров
Здравствуйте, Eye of Hell, Вы писали:
EOH>Пустой аргумент, ни в пользу ООП ни против. Какая разница что с чем связали?
Разница в том, что многие под достоинствами ООП понимают другие вещи. Например, я считаю достоинством ООП — удобное создание Абстрактных Типов Данных (АТД). Но нельзя не согласиться с Грэмом, что это фишка есть и вне ООП. А раз так, то относить ее к достоинствам ООП уже некорректно.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[3]: Почему объектно-ориентированное программирование пров
Здравствуйте, igna, Вы писали:
I>Простейшая задача имеет порой заумную реализацию в ООП. Например требуется реализовать сравнение на равенство определенное следующим образом: два объекта равны, если все их составные части попарно равны.
Это не верная формулировка при наличии подтипов (что возможно и без наследования).
I> На шаблонах C++ реализация записывается буквально в соответствии с определением и в одну строку,
Если это так просто, то просьба продемонстрировать эту реализацию прямо здесь.
I> в ООП, на том же C++, или на Java, или на С# начинаются пританцовывания на ровном месте с проверкой типа и т.п.
Дык причем тут ООП? Это будет в любой системе поддерживающей подтипы (например, интерфейсы или типы классов). Это обратная сторона полиморфизма. Два объекта имеющих один статический тип могут на самом деле быть подтипами этого типа. Наследование реализации тут никаким боком.
Что до определения таких методов, то вот как данная задача решается в Немерле (выделено жирным):
using System;
using System.Linq;
using Nemerle.Collections;
using Nemerle.Text;
using Nemerle.Utility;
using Nemerle.Extensions;
namespace Tests
{
using NorthWind;
/// <summary>Description of Customer.</summary>
[Record, StructuralEquality, StructuralHashCode]
class Customer
{
[Accessor] _customerID : int;
[Accessor] _name : string;
[Accessor] _country : string;
[Accessor] _city : string;
public override ToString() : string
{
$"Customer(CustomerID=$CustomerID; Name=$Name)"
}
public Orders : IQueryable[Order]
{
get { _orders.Where(o => o.CustomerID == CustomerID).AsQueryable() }
}
}
}
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[4]: Почему объектно-ориентированное программирование пров
Здравствуйте, SV., Вы писали:
SV.>Вопрос, следовательно, в том, каково оно — программирование на productivity plateau этой технологии? Мой личный ответ: подобающее ООП место — "скелет" проектов. Набор классов, который описывает предметную область, позволяя проектным нубам быстрее врубаться. Набор интерфейсов, который показывает, какие роли какие сущности могут играть. Не больше и не меньше.
А есть ли там вообще ООП? Те самые наследование реализации, инкапсуляция, полиморфизи, объекты с идентичностью и поведением.
Или это всетаки больше SOA, где выкинуты сомнительные свойства вроде идентичности и наследования реализации?
Re[9]: Почему объектно-ориентированное программирование пров
DG>>но значит у тебя модель другого мира. модель проекта, например. G> G>Ты всегда сводишь к абсурду. У тебя получается что объект — модель какого-то "мира".
объект — это слово(понятие) модели обычно.
DG>наследовать реализацию обычно проще, чем писать ее заново. G>Есть другие способы повторного использования кода.
например?
DG> стати практика показывает обратное, если мы на этапе проектирования будет модели 1-в-1 перекладывать в структуры классов то получится *опа.
значит не надо так делать.
Re[10]: Почему объектно-ориентированное программирование про
Здравствуйте, SV., Вы писали:
SV.>Здравствуйте, gandjustas, Вы писали:
SV.>>>>>Коль скоро это так, вас, конечно же, не затруднит привести пример программы, которая не является моделью? G>>>>Вот сейчас занимаюсь веб-приложением для автоматизации проектного управления. У меня там нет ни одного объекта, который является моделью объекта реального мира. SV.>>>Техзадание на ваше приложение имеется? Оно — модель реальности, а ваш код — перевод этой модели с русского или английского языка на ЯП, а, следовательно, тоже модель. G>>См выделенное. SV.>>>В то, что при переводе ключевые сущности оказались заменены другими, я не очень верю, но если поверить, то гордиться тут нечем. А если считаете, что есть чем, расскажите больше. G>>Спокойно. Проект на sharepoint, основные объекты с которым приходится работать это "сайт", "список" и "элемент списка". Причем ни один из них никак не фигурирует ни в каких ТЗ.
SV.>Это как с утиной типизацией — контракт задается неявно, но это не значит, что его нет. Чтобы в этом убедиться, попробуйте пасхалкой встроить тетрис. Это к вопросу о ТЗ.
Вообще не понял причем тут пасхалки.
SV.>Что касается SPWeb, SPList и SPListItem. Вы, как опытный специалист, конечно же, не будете спорить, что с инженерной точки зрения ШП — это не какой-то там "портал" (это маркетинговое блаблабла), а база с человеческим лицом? Сетевая, многоклиентская, за имением GUI не требующая SQL для внесения/редактирвоания/удаления записей, обладающая адаптированными типами (например, нормальный документ вместо неясного БЛОБа). Ну и, конечно, с недоразвитой реляционностью. База данных же сама по себе очень старая модель писчебумажных архивов. Которые, в свою очередь, используются для моделирования: выявление ключевых значений для колонок — это выявление значимых сущностей модели.
Мы же не о моделировании вообще говорим, а о коде.
SV.>Короче, возьмите рулон листов ширины А0. Расчертите на первом листе рулона таблицу с пустыми графами (меньше 100 колонок, считать лень — точное количество можно узнать из [AllUserData]). Поздравляю, только что вы создали "объект реального мира", который моделируется классом SPList. По мере заполнения таблицы, крутите рулон и дочерчивайте колонки. Разработчикам ШП удалось очень точно смоделировать эффект "зае@#$ся", который при этом возникает — я имею в виду дикие тормоза при обработке нескольких тысяч элементов. Каждый раз, когда вы будете вписывать в название колонки текст "размер, мм", вы опять же создаете объект реального мира — SPField. Одна строка на бумаге поперек колонок — SPListItem, а чулан с рулонами — SPWeb.
А здесь уже какой-то обратный процесс пошел. Ты пытаешься натянуть класс натянуть на какие-то объекты реального мира. Зачем?
SV.>Нет такого софта, который не является моделью чего-то. Иначе он бесполезен.
Да вот я тебе привел пример что программа не является никакой моделью. Ты в оправдание начал выдумывать модель там где её не было.
Я не спорю что ты можешь выдумать модель для любого класса, только это никак не обосновывает твою точку зрения.
SV.>>>Каким образом обеспечивается is-a, вот о чем речь. G>>Именно, я тебе выше написал что много других способов. Причем наследование реализации — далеко не самый лучший.
SV.>Это утверждение бессмысленно вне контекста. В контексте одних объектов — не самый лучший, других — самый лучший, третьих — худший. Должен ли я приводить соответствующие примеры?
Попробуй.
SV.>>>Должны, конечно, если мы хотим иметь код, который проще писать, читать и понимать. G>>стати практика показывает обратное, если мы на этапе проектирования будет модели 1-в-1 перекладывать в структуры классов то получится *опа. G>>Возникают type-test там где не надо, double dispatch, визиторы и прочие гадости. SV.>Ваша практика показывает?
Нет, читаю книги всяких бутчей и мейеров. Правда они там преподносят это как достижение, а на деле усложнение на ровном месте.
Re[11]: Почему объектно-ориентированное программирование про
Здравствуйте, gandjustas, Вы писали:
SV.>>>>Техзадание на ваше приложение имеется? Оно — модель реальности, а ваш код — перевод этой модели с русского или английского языка на ЯП, а, следовательно, тоже модель. G>>>См выделенное. SV.>>>>В то, что при переводе ключевые сущности оказались заменены другими, я не очень верю, но если поверить, то гордиться тут нечем. А если считаете, что есть чем, расскажите больше. G>>>Спокойно. Проект на sharepoint, основные объекты с которым приходится работать это "сайт", "список" и "элемент списка". Причем ни один из них никак не фигурирует ни в каких ТЗ.
SV.>>Это как с утиной типизацией — контракт задается неявно, но это не значит, что его нет. Чтобы в этом убедиться, попробуйте пасхалкой встроить тетрис. Это к вопросу о ТЗ. G>Вообще не понял причем тут пасхалки.
Пасхалки тут вот причем. Вы говорите, что сайты, списки и айтемы не фигурируют в ТЗ. Я говорю: хорошо, тетрис в вашем ТЗ наверняка тоже не фигурирует. Но если вы займетесь тетрисом, а не списками и сайтами, то почувствуете разницу. А если разница есть, может ваше ТЗ просто недостаточно детализировано и они там подразумеваются? Или, как я написал выше, "контракт задается неявно, но это не значит, что его нет".
Если кто-то еще читает, и забыл уже, откуда пошел этот спор, я напомню. Я написал, что любой софт — модель. Слово неоднозначное, поэтому я оговорюсь, что имел в виду abstract (aka conceptual) model (http://en.wikipedia.org/wiki/Abstract_model). Согласно определению, "a model is anything used in any way to represent anything else". Чтобы эффективно represent, отбираются субъективно важные свойства моделируемого объекта, которые воспроизводятся. Для листа бумаги в Word'e это белый цвет и размер. Остальные, типа, структуры волокон, херятся. Далее, represent'овать можно, строя модель из каких-то имеющихся блоков. Из пикселей, например. Из окон. Из хендлов.
Ну вот, gandjustas'у дают грубую модель, ТЗ вида "сайт с услугами и прейскурантом штоп все работало" имея в виду, например, магазин, а он должен довести моделирование до конца — составить полный набор моделируемых свойств и приземлить их на строительные блоки SPList/SPWeb/SPSite. Это его added value, то, за что он получает хлеб насущный. А он же, упирая на то, что в исходном ТЗ нет SPList/SPWeb/SPSite, говорит, что софт, якобы, не модель!
На этом я предлагаю тему моделирования закруглить.
SV.>>Это утверждение бессмысленно вне контекста. В контексте одних объектов — не самый лучший, других — самый лучший, третьих — худший. Должен ли я приводить соответствующие примеры? G>Попробуй.
У вас есть прибор А, который управляются через двунаправленный dataport потоком команд. Допустим, с набором из 3 лампочек — красной, синей и зеленой. Послали в порт turn green on — зеленая лампочка зажглась. Послали turn green off — она же погасла. А вам надо получить API, который абстрагирует вашего пользователя от всей специфики работы с портами.
Уже здесь есть выбор — делать ли такую сущность, как класс Device с методами типа TurnGreenOn() (и иметь картину кода, повторяющую окружающий мир) или, скажем, завести просто отдельную функцию на каждую команду. Через год оказывается, что приборов может быть к вашему писюку подключено несколько (хотя клиент клялся, что такого не будет), и один делает коллекцию Device'ов, а второй — отдельно передаваемый параметр (идентификатор прибора) в каждую функцию.
Есть еще вариант с картой <cmdid | "command text"> и единственным методом SendCommand. Он, во-первых, недружественен, а во-вторых делает слишком мало полезного. Например, если понадобится прикрутить кэширование состояния лампочек, это будет делать ваш пользователь.
Допустим, вы-таки написали класс Device. За это время на базе прибора А был построен прибор Б. То есть, буквально — взяли прибор А и допаяли к нему дополнительный аппаратный модуль, например, динамик. От этого он не утратил ни лампочки, ни возможность управлять ими, но приобрел какое-то дополнительное свойство, в нашем случае — издавать звуки. Соответственно, от класса Device наследуется DeviceExt, с добавленным методом Beep() (который посылает в порт строку make bebeep). В результате выбрать тип устройства можно ровно один раз — инстанцируя фабрикой тот или иной класс. Ошибки выбора будут собраны все в одном месте. В дальнейшем ваш пользователь НЕ МОЖЕТ попросить прибор без гудка погудеть. Кроме того, глядя на этот код:
Мало того, что информация о двух приборах и их отношениях в реальном мире в API отсутствует, так ничто не мешает передать id прибора старого типа в Beep, вызвав у прибора зависание.
Наконец, что, если мы унаследовали интерфейсы, но не стали наследовать реализацию?
IDeviceExt : IDevice
{
Beep
}
В этом случае оба интерфейса должны быть реализованы по отдельности. Если вы не законченный копипакостник, делегировать выполнение вам придется к одной и той же сущности (например, агрегированной). И такое делегирование само по себе будет копипастом на три четверти.
Хуже всего то, что языки типа C++ не позволяют вам сказать что-то типа "класс B унаследовал реализацию от класса A, реализующего базовый интерфейс IA, поэтому базовая часть унаследованного от IA интерфейса IB у нас уже имплементирована":
struct IMyDevice
{
virtual void Foo() = 0;
};
struct IMyDeviceExt : public IMyDevice
{
virtual void Bar() = 0;
};
class CMyDevice : public IMyDevice
{
public:
virtual void Foo()
{
}
};
class CMyDeviceExt : public CMyDevice, public IMyDeviceExt
{
public:
virtual void Bar()
{
}
};
void mymain()
{
CMyDevice md;
md.Foo();
CMyDeviceExt mde;
mde.Foo();
mde.Bar();
}
При практической необходимости (как в COM'е) используются грязные хаки — всеобщая договоренность об __stdcall и абстрактные указатели void*. И это еще хорошо, если хаки в таком языке допустимы. Если нет — здравствуй, обезьянья работа.
Это был пример обоснованного использования наследования реализации. Пример необоснованного — унаследовать реализацию прибора от порта.
Оба примера из жизни.
SV.>>>>Должны, конечно, если мы хотим иметь код, который проще писать, читать и понимать. G>>>стати практика показывает обратное, если мы на этапе проектирования будет модели 1-в-1 перекладывать в структуры классов то получится *опа. G>>>Возникают type-test там где не надо, double dispatch, визиторы и прочие гадости. SV.>>Ваша практика показывает? G>Нет, читаю книги всяких бутчей и мейеров. Правда они там преподносят это как достижение, а на деле усложнение на ровном месте.
Тут про Design Patterns (с предисловием Буча) был замечательный постинг. Pattern это паттерн, а не образец для подражания. В общем, конкретизируйте, где и кем, например, Visitor преподносится как достижение.
Re[15]: Почему объектно-ориентированное программирование про
G>Оба они почти наверняка будут нарушать LSP. Есть реальный пример обратного — приводи.
если учесть, что круг и эллипс состоят в отношениях нарушающих принцип Лискова (в обе стороны), то это нормально.
зы
если брать полный контракт эллипса, то круг вместо него нельзя использовать (т.к. он, например, не имеет двух фокусов)
а эллипс нельзя использовать вместо круга.
Re[13]: Почему объектно-ориентированное программирование про
Здравствуйте, gandjustas, Вы писали:
G>Ты рассматриваешь проектирование классов не знаю какие задачи на них возлагаются. так нельзя делать, ничего хорошего их этого не выйдет. G>А правильные задачи класса можно получить декомпозиции общей задачи. G>Это и называется проектирование "сверху вниз", которое многие адепты ООП как раз и не любят, потому что в итоге оно не дает нам модели объектов реального мира.
Вот это пропустил. А зря. Как говорил наш преподаватель математики, ЧТД. Человек, которому попадет в руки ваш код, должен будет разбираться с особенностями вашей индивидуальной "декомпозиции общей задачи", вашего понимания общей задачи, и со всеми вашими тараканами. Человек, которому попадет в руки ООП-код с моделью, будет одновременно изучать и предметную область. Если он знает предметную область, то на понимание кода ему вообще не понадобятся усилия.
И опять у меня нет выхода, кроме как процитировать себя:
Моя цель, извините, это код, который проще писать, читать и понимать, и с гарантированным уничтожением риска противоречий (если какие-то отношения непротиворечивы в природе, значит в модели они тоже будут такими же).
Re[9]: Почему объектно-ориентированное программирование пров
U>Но объяснение Гофмана не может быть принято. Это противоречит поведению часов GPS. Различие в солнечном гравитационном потенциале для GPS синхронизируемых в точке, ближайшей к Солнцу и дальней от Солнца ( различие в расстоянии приблизительно в четыре раза превосходит земного диаметр) кажется, не оказывает никакого влияния на часы GPS.
U>Т.е. объяснение Гофмана противоречит наблюдаемым фактам.
Чего-то я не очень понимаю эту фразу. Спутники GPS движутся по круговым орбитам (ещё и геосинхронных при этом), так что для них достаточно константного смещения часов. Эффект от градиента солнечного гравитационного поля в случае с GPS пренебрежимо мал.
Далее, автор банально лжёт:
Есть два интересных взаимодействия между эффектами гравитационного потенциала и эффектами скорости в показаниях часов. Сначала, на уровне моря все часы на Земле идут с одной и той же скоростью. Это связано с тем, что вращение Земли вызывает ее раздувание на экваторе, так как гравитационный потенциал там выше. (Часы на экваторе дальше от центра Земли.) Эффект в показаниях часов от этого большого потенциала в экваторе и эффект в показаниях часов от скорости вращения точно компенсируют друг друга. Так что показания часов на экваторе равно показанию часов на полюсах.
Это не так, что элементарно можно посчитать — гравитационное красное смещение от перемещения по вертикали с лихвой компенсирует возросшую линейную скорость, при всех разумных параметрах. В классическом эксперименте с часами на самолётах — часы шли _быстрее_, а не медленнее часов на Земле.
Тут опять ерунда — спутники GPS летают по круговым орбитам, их эксцентриситет — всего несколько километров (из-за того, что барицентр системы Земля-Луна находится не в центре Земли).
Второе взаимодействие гравитационного потенциала и скорости в показаниях часов происходит из-за эксцентричности орбит GPS. В перигее, более низкий гравитационный потенциал приводит к тому, что часы GPS идут медленнее, чем номинально. Также в перигее, спутники перемещаются быстрее чем в среднем и это также заставляет часы GPS работать медленнее — точно с той же суммой. Так что кажется, что энергия – вот что заставляет часы идти с другим темпом. Возрастающая гравитационная потенциальная энергия заставляет часы работать быстрее. Возрастающая кинетическая энергия (скорость) заставляет часы работать медленнее.
Далее:
Ну и в чем же проблема часов? Проблема проявляется, вопреки ожиданиям, с часами на Земле, которые как кажется, не подвержены влиянию солнечного гравитационного потенциала. Почему так? Для часов, приязанных к Земле, проблема была описана как проблема "полдень-полночь". В полдень часы ближе к Солнцу на диаметр Земли, нежели часы в полночь. Таким образом, ожидается, что в полдень часы должны идти медленнее, чем в полночь из-за солнечного гравитационного потенциала, однако это не наблюдается.
Не ожидается, что прекрасно показал Гоффман. До этого момента всё, в принципе, более-менее правильно, в лучших традициях Геббельса.
А вот теперь момент лжи!
...
Это верно, что часы, которые облетают Солнце за год по радиусу земного полдня должны иметь тот же ход, что часы, которые облетают Солнце за год по радиусу земной полночи, то есть потенциальное гравитационное различие должно компенсироваться скоростным различием. Но объяснение Гофмана не может быть принято. Это противоречит поведению часов GPS. Различие в солнечном гравитационном потенциале для GPS синхронизируемых в точке, ближайшей к Солнцу и дальней от Солнца ( различие в расстоянии приблизительно в четыре раза превосходит земного диаметр) кажется, не оказывает никакого влияния на часы GPS.
Градиент грав. поля между уровнем моря и высотой 22000 км.:
g0=(mass of earth)/(radius of Earth)^2*G = 9.79982305 m/s^2
g1=(mass of earth)/(radius of Earth + 22000km)^2*G = 0.495033116m/s^2
Т.е. g0-g1=9.30478993m/s^2
Теперь то же самое для Солнечного гравитационного поля:
g0=(1.98892*10^30kg)/(1 astronomical unit — 22000km)^2*G = 0.00593218395 m / s2
g1=(1.98892*10^30kg)/(1 astronomical unit + 22000km)^2*G = 0.00592869541 m / s2
Т.е. g1-g0=-3.48854*10^-6 Разница между эффектами в семь порядков! Неудивительно, что эффекта не наблюдается.
Но даже если предположить, что эта разница обнаружима (а она обнаружима) — то ЭТО ТОЖЕ НЕ ПРОБЛЕМА! Так как на земные часы в момент синхронизации тоже влияет гравитационное поле Солнца, так что все расхождения (почти) полностью будут компенсированы. В строгом согласии с принципами ОТО.
S_S>>Вобщем, Гофман согласен, Хатч не согласен. U>С точки зрения науки совершенно не важно с чем согласны или нет Гофман и Хатч, важно то, что объяснение предлагаемое Гофманом противоречит фактам, а, значит, является неверным.
Каких фактов? Факт один — часы на спутниках идут быстрее. Причём в строгом соответствии с ОТО.
Здравствуйте, SV., Вы писали:
SV.>Что такое контракт?
Набор формальных правил, ограничивающих внешнее взаимодействие с объектом.
SV.> В строгом смысле мейнстримные языки Contract programming вообще не поддерживают
Программирование по контракту это совсем другое.
SV.>, а в бытовом смысле надо уточнять. Что будет контрактом в шарпе?
Публичный интерфейс класса или интерфейс. В классе два контракта — публичный и для потомков.
... << RSDN@Home 1.2.0 alpha 5 rev. 1495 on Windows 7 6.1.7600.0>>
Здравствуйте, gandjustas, Вы писали:
G>Но далеко не любая программа является моделью части реального мира.
При чем тут "реального"? Ключевое слово — модель. Например, можно брать математические модели.
G>Даже наоборот, программ где такой подход оправдан исчезающе мало.
Попробуй привести пример, который тут не раскатают по асфальту.
G>Отношение is-a отлично достигается без наследования реализации. Интерфейсы (выше ты привел именно наследование интерфейсов), typeclasses в хаскеле, ducktyping в динамических языках. Это все позволяет выстраивать отношения is-a.
Я бы не стал ducktyping приравнивать к is-a. Ибо сие отношение как раз служит для для типизированных языков как инструмент проверки контрактов в compile-time. Для ООП-скриптовых языков ducktyping работает на уровне отдельного метода, и лишь предоставляет способ реализации обмена сигналами для целей собственно работы ООП в этой динамике.
Насчет твоей фразы наследования интерфейсов — не уверен, что ты сам понял, что сказал. В ООП интерфейсом называют публичное АПИ классов, оно и наследуется автоматически. Если же ты про термин "Interface" из COM, особенность которого была повторена в Delphi/Java/C#, то его следует называть "абстрактным интерфейсом". Слово абстрактный — ключевое, т.е. мы заведомо опускаем подробности реализации, используя этот интерфейс исключительно как описание контракта для системы статической типизации компилятора. Заметь, с т.з. клиентов таких интерфейсов, им глубоко до фени, абстрактный он или нет, это подробности уже самого интерфейса.
Абстрактные интерфейсы предназначены для случая надобности сокрытия полного АПИ реализующих классов, ведь термин "абстракция" означает выделение сути/основы. То, что в некоторых языках абстрактные интерфейсы используются порой для побочных целей, например для порождения нескольких параллельных иерархий is-a — лишь следствие отсутствия в этих языках множественного наследования. То бишь, инструмент абстрагирования применяется даже там, где размер задачи абстрагирования не требует.
Рациональное зерно в наследовании абстрактных интерфейсов для построения объектной иерархии разумеется есть. И чем больше иерархия, тем больше в этом смысла. Мы избавляем такую иерархию от подробностей реализации составляющих её элементов, т.е. банально уменьшаем информационную сложность иерархии. Причем, учитывая связи м/у объектами (например, из-за использования общих или базовых реализаций), мы можем нарваться на рост числа зависимостей, близкий к квадратичному от кол-ва элементов иерархии. И вот смотрим на современные программы, где многие десятки сущностей, если не сотни... Понятное дело, что есть здравое желания снизить сложность архитектуры системы на порядок и даже чуть больше.
SV.>>Грамотная декомпозиция на значимые сущности должна быть переложена на ЯП без изменений, с сохранением всех отношений, в т.ч. наследования реализаций.
G>Выделенное необоснованно.
Оно ничему не противоречит. Даже имея описанный вариант системы, иерархия которой расписана на абстрактных интерфейсах, ничто не мешает использовать наследование реализаций для конкретных используемых типов. Вы в пылу спора всё время забываете, что вся эта абстрактность — вторична. Это лишь наше внутренее дело, как мы боремся со сложностью и какой инструмент для этого взяли. Напротив, функциональность — первична. Даже такая вещь, как агрегирование и делегирование в реализации концепции миксинов (ручной реализации чаще всего) — лишь инструмент, обыгрывающий некоторые ограничения некоторых ООП-языков/платформ.
G>Ты в принципе попал в ту же проблему, куда попадают все "философы ооп". Они поголовно считают что все достижения ООП недоступны в других парадигмах, а на деле даже наоборот.
Расшифруй, плиз, о каких достижениях речь, и куда именно попал твой оппонент? Сдается мне, тут уже наблюдается тихий спор с самим собой.
Re[11]: Почему объектно-ориентированное программирование про
Здравствуйте, gandjustas, Вы писали:
DG>>>>но значит у тебя модель другого мира. модель проекта, например. G>>> G>>>Ты всегда сводишь к абсурду. У тебя получается что объект — модель какого-то "мира".
DG>>объект — это слово(понятие) модели обычно. G>А мы вообще-то говорим про объекты и классы в ОО-языках.
Ну так в ООП объект и представляет из себя элемент модели. Класс — это уже термин из области типов, к понятию "объект" в общем случае ортогональный.
G>Композиция.
Наследование реализации в ООП — это и есть агрегирование, что есть частный случай композиции. И множественное наследование в т.ч. Подозреваю, что ты хотел упомянуть какие-нить паттерны, типа делегирования и т.д., но это уже шелуха и подробности. Ты все-равно повторно используешь именно функциональность, только предоставляешь ее не из АПИ, а через самописные переходники, эдакое ручное описание thunk, вместо компилятора. Сия техника нужна там, где нет множественного наследования или параметр генерика не может быть базой. В других языках, имея полностью абстрактные параллельные иерархии, легко использовать "автоматическую" композицию через множественное наследование, вместо получения того же эффекта вручную.
В общем, ты опять попутал причину и следствие. Миксины не самоцель, а инструмент, пригодный для обхода ограничений языка.
Re[15]: Почему объектно-ориентированное программирование про
Здравствуйте, gandjustas, Вы писали:
G>Наследование реализации наследования интерфейсов и отношения is-a в некоторых языках есть и называется mixin. Тоже концепция, уводящая в сторону от ООП.
Глупость. Миксин — это вынужденно используемый инструмент для удобства программирования в ограниченной разновидности ООП — компонентном программировании. Где же тут "в сторону"? Это на маленьком островке внутри ООП.
Re[20]: Почему объектно-ориентированное программирование про
Здравствуйте, DarkGray, Вы писали:
DG>ракета наследуется от самолета, а свиньи от военных юнитов DG>и это всех устраивает — если сделано аккуратно
Приведены баги вызванные подобным наследованием и остроумные костыли для их обхода. Какая логика привела тебя к выводу "всех устраивает, если сделано аккуратно"?
То, что софт почти с любыми архитектурными проблемами можно заставить заработать, я думаю, ни для кого из здесь присутствующих не новость, это не значит, что проблемы всех устраивают.
Re[22]: Почему объектно-ориентированное программирование про
Здравствуйте, DarkGray, Вы писали:
Z>>Приведены баги вызванные подобным наследованием и остроумные костыли для их обхода. Какая логика привела тебя к выводу "всех устраивает, если сделано аккуратно"?
DG>всех устраивает, если исходить из совокупности параметров "качество/цена"
DG>могли разработчики написать ракету с нуля, а не наследовать реализацию от самолета? могли DG>код был бы чище? скорее всего -да DG>почему не сделали? да, потому что — это выливается в большие временные затраты: необходимо заново выписывать требования, заново проектировать, заново кодировать, заново тестировать. наследование реализации позволило существенно сэкономить на всех 4-х этапах.
То есть ты хочешь сказать что ООП — хорошее средство писания говнокода?
Или просто пытаешься оправдать одну ошибку дизайна другой?
Z>>То, что софт почти с любыми архитектурными проблемами можно заставить заработать, я думаю, ни для кого из здесь присутствующих не новость, это не значит, что проблемы всех устраивают.
DG>это ты говоришь лишь про максимизацию параметра "качество" без учета "цены". DG>да, если нам нужно именно сверхкачество, то приходится отказываться от наследования реализации, и если мы берем те же самолеты, то там пишется три копии ПО без всякого наследования реализации для такого чтобы избежать наведенных проблем от наследования реализации. DG>но если берется менее критичная область, то наследование реализации вовсю используется, т.к. позволяет сильно улучшить параметр "цена".
Наследование почти всегда безболезненно можно заменить агрегацией + рефакторинг Extract Interface.
Re[17]: Почему объектно-ориентированное программирование про
V>>Был приведен пример независимых иерархий, по каждой из которых существует свое is-a. Похожая задача была про квадрат, ромб и прямоугольник, кого от кого наследовать. Никого ни от кого. Имеем несколько паралельных иерархий, и сия ситуация решается множественным наследованием для реализации конечных типов. Ну или миксинами для C# и иже с ними.
Z>Я не пойму, что ты хочешь сказать. Я возразил на выделенное, проблема начинается когда дизайн иерархии перестает удовлетворять LSP. Который как раз для этого случая и придуман, там прямым текстом написано: не хотите проблем — не делайте так.
Давай-ка подробнее. Я предположил, что вместо одой ветки наследования можно использовать несколько. Противоречие принципу Лисков будет лишь тогда, когда нам, при работе с одним из корней сей иерархии (одним интерфейсом для C#), потребуется узнать наличие еще одной базы (реализации еще одного интерфейса) или даже конкретный используемый тип. Действительно, не делайте так. Если у нас есть коллекция интерфейсов, то при обходе сей коллекции обходитесь, пожалуйста, только этим статически типизированным интерфейсом. Вот и всё.
Т.е. обрати плиз внимание, что нарушение принципа имени Барбары может наблюдаться не в момент проектрования иерархии, а в момент её использования. Да, хоть мы "нутром" понимаем, что использование зависит от вида иерархии, это далеко не всегда так. Часто это может быть от неправильного использования.
Поэтому сто раз прав г-н Степанов в том, что сначала надо разрабатывать функциональность/алгоритмы, а потом под них разработать непротиворечивую систему хранения состояния (данные). В обсуждаемом случае — чтобы использование иерархии классов, в имеющихся как данность алгоритмах, не провоцировало на нарушение LSP.
Z>Я не вижу никакой необходимости множественного наследования или миксинов в данной ситуации.
Ну хорошо, пусть без миксинов, пусть каждый метод абстрактной базы будет реализован в конечном типе с 0-ля. По-сути то это ничего не меняет.
Z>И вообще не понимаю, что такое миксины для C#.
Речь идет об эмуляции миксинов вручную через ручное делегирование. Угу, для целей реализации продвигаемой новой фишки под названием "повторное использование кода через композицию". Фишка просто замечательная для .Net/Java, за неимением на этой платформе других способов композиции объектов. Осталось лишь поддержать фишку в языках, чтобы не делать механическую работу вручную.
Z>Если требуется какой-то полимофризм их следует наследовать от фигуры.
Еще раз, в конкретно рассматриваемом примере может быть несколько веток иерархии. И да, вполне может быть один корень, пусть "фигура", и список объектов из этого корня даже можно будет подать на часть алгоритмов. Но нельзя этот же интерфейс использовать для прорисовки, например, сегмента овала/круга, т.е. в тот алгоритм надо подать другой интерфейс, чтобы внутри него не было необходимости обходить LSP. (сорри, уже просто на пальцах)
Re[18]: Почему объектно-ориентированное программирование про
Здравствуйте, vdimas, Вы писали:
V>Давай-ка подробнее. Я предположил, что вместо одой ветки наследования можно использовать несколько. Противоречие принципу Лисков будет лишь тогда, когда нам, при работе с одним из корней сей иерархии (одним интерфейсом для C#), потребуется узнать наличие еще одной базы (реализации еще одного интерфейса) или даже конкретный используемый тип. Действительно, не делайте так. Если у нас есть коллекция интерфейсов, то при обходе сей коллекции обходитесь, пожалуйста, только этим статически типизированным интерфейсом. Вот и всё.
LSP — про единичное наследование
Re[2]: Почему объектно-ориентированное программирование пров
Здравствуйте, samius, Вы писали:
S>разве в других парадигмах рефакторинг исключен? Я вообще думаю что рефакторинг это следствие отношения к предварительному проектированию и собственно самому коду.
Нужен меньше. По опыту плюсов, чем меньше создаешь классов, т.е. чем больше функциональности удается разнести в свободные ф-ии, тем меньше надобность рефакторинга. ИМХО, это объяснимо, т.к. объект в ООП — это группировка в "одно целое" относительно большого кол-ва элементов программы. И весь рефакторинг, по-сути, это перетасовка элементов таких групп. Пройдись по формальным методам рефакторинга: 90% рефакторинга — это способы перемещения методов и полей м/у объектами таким образом, чтобы не поломать случайно исходное поведение программы.
Согласись, набор свободных ф-ий подобного практически не требует. Ну, максимум их идентификаторы порой надо причесать, но сие несущественно.
S>Возможно стоит сменить название на следущее: Что считают гуру причиной провала ООП?
Никто еще не доказал, что ООП провалилось. Оно провалилось лишь как "серебряная пуля" — ИМХО, это проблемы тех, кто считает, что серебряные пули существуют.
Re[28]: Почему объектно-ориентированное программирование про
Здравствуйте, vdimas, Вы писали:
V>>>Нет, я обращал внимание на то, что нарушение LSP происходит не в месте проектирования иерархии, а в месте ее использования. Т.е. рассматривать каждую иерархию в отдельности при использовании ее через корень иерархии надо как гомоморфную.
Ну да, если метод принимает параметр по ссылке на корень, то он должен обращатся только к тем методам, которые объявлены в этом классе корня. И нефиг даункастить и дергать методы наследников. Если нужны метода наследника, то сигнатура метода должна быть изменена — чтобы метод принимал по ссылке наследника, а не базу. V>>>Явная гомоморфность иерархии — это просто способ заранее дать себе линейкой по рукам, дабы неповадно.
Ага, и вместо того, чтобы не даункастить, мы делаем специальные приседания, чтобы даункаст был бессмысленен.
— Так неприятно получать по рукам линейкой!
— Согласен... А давайте руки себе отрубим — так у нас будет гарантия, что линейкой мы по ним никогда не получим!
— Гениально!
Руки, в данном случае — это новые методы в наследниках.
A>>Нифига не понятно. V>Тем не менее, в этом вся соль. Добавил выделенное курсивом, вдруг поможет.
И тут меня осенило!
Дано: Базовый класс B и его наследник D, функции f1..fN, принимающие параметр по ссылке на B и внутри даункастящие его и дергающие методы D.
Добавляется новый наследник B — класс D2.
Требуется: Обеспечить LSP для класса D2.
Как обеспечить: Вроде бы никак, поскольку при любом раскладе функции f1..fN сломаются, если им передать объект типа D2.
Так что же, LSP нарушен уже в этих f1..fN? Нет, не так — просто здесь обман; функции f1..fN, на самом деле, принимают параметрами объекты типа D, а не B. Просто компайл-тайм проверки этого были зачем-то исскуственно придушены и перенесены в рантайм, а их сигнатуры вводят в заблуждение. И это нарушение типобезопасности, а не LSP — совсем другая тема.
Re[9]: Почему объектно-ориентированное программирование пров
Здравствуйте, vdimas, Вы писали:
V>================== V>Ты не самый интересный момент комментируешь. Суть этих постов была в замеченном факте, что давая больше доступа к обрабатываемым данным во внутреннем АПИ, надобность структурного рефакторинга, того самого, когда заметно меняется состав объектов и еще более заметно их роли, почти всегда выходит ниже.
Кстати функциональщина как раз поощряет (АТД и ПМ) такой больший доступ.
Re[9]: Почему объектно-ориентированное программирование пров
Здравствуйте, vdimas, Вы писали:
V>Ты не самый интересный момент комментируешь. Суть этих постов была в замеченном факте, что давая больше доступа к обрабатываемым данным во внутреннем АПИ, надобность структурного рефакторинга, того самого, когда заметно меняется состав объектов и еще более заметно их роли, почти всегда выходит ниже.
Как то слишком очевидно, по-капитански И ежу понятно, если сразу выдать тот самый правильный дизайн, к которому месяцами и даже годами подходят путем рафакторинга, то годы рефакторинга будут не нужны.
Про это написано практически во всх книгах по рефакторингу — Фаулер, Физерс, Кент Бек, Кериевск и тд.
Re[7]: Почему объектно-ориентированное программирование пров
Здравствуйте, vdimas, Вы писали:
V>Еще раз, объектная декомпозиция — это практически всегда разделение состояния, т.е. ухудшение инкапсуляции, т.е. всё больше подробностей реализации начинает торчать наружу
Глупость ты написал. Такое ощущение, что ты пытаешься своими терминами и не очень понятными образами выразить азбучные истины. Любой дизайн стремится к минимизации связности (coupling) и максимизации зацепления (cohesion). Соотв. любая декомпозиция в идеале должна уменьшать первое, сохраняя на приемлемом уровне второе. Любая. Хоть объектная, хоть функциональная. А вот если это правило не соблюдается, то и получаем те страшилки, о которых ты пишешь. Хоть в ООП, хоть в ФП, хоть в чистой структурщине.
Скажи честно, ты Буча давно перечитывал?
... << RSDN@Home 1.2.0 alpha 5 rev. 1495 on Windows 7 6.1.7600.0>>
Здравствуйте, AndrewVK, Вы писали:
AVK>Ну понятно, проблема во мне.
В словарном запасе и манерах — это в тебе? Впрочем, это происходит не первый десяток раз.
AVK>Тебе, правда, другие то же самое пишут, но это тоже в них проблема.
Второй "активный" участник пока не понял, о чем была речь. И пытается спроектировать читаемое на свои координаты познаний с переменным успехом.
AVK>Истинный гуру здесь, понятно, один.
Вот оно что.
V>>Ты всерьез сейчас утверждаешь, что декомпозиция всегда производится с целью минимизации связанности и максимизации зацепления?
AVK>Не с целью, а с учетом.
С неточностями решили. Попробуй теперь согласовать это с вырезанной из контекста фразой. А то толкнул неоспоримую вещь, чего уж там. Для профилактики, чтобы "гуру" себя в одиночестве не чувствовал.
V>>Коллега, стоило ли так торопиться, путая причины проведения некоей декомпозиции с критериями оценки её удачности?
AVK>Я как раз ничего ен путаю. Но то, что ты начал цеплятся к словам — показательно.
Ну так даешь повод.
Соотв. любая декомпозиция в идеале должна уменьшать первое, сохраняя на приемлемом уровне второе. Любая.
"В идеале" или "любая"? Если бы не пытался столь усилить двойным повторением, в глаза не бросалось бы.
И всегда ли надобность в декомпозиции исходит от желания/потребности улучшения метрик дизайна? Ключевой леймотив той книги я уже цитировал, как и упоминал фактически в каждом топике.
Ну и, если даже не цепляться, вторая часть фразы оставляет поле для маневра. Тем более, что это далеко не единственные критерии. А в контексте, на что был ответ — так и вовсе притягивание за уши (обсуждался случай ухудшения инкапсуляции при декомпозиции), что даже лень обсуждать. Практически всегда при "мелкогранулированной" декомпозиции часть внутренних связей перекочевывает во внешнее. Т.е. вовсе не факт, что с некоторого уровня декомпозиции вторая метрика будет продолжать улучшаться. Пока она улучшается — наша декомпозиция лишь исправляет косяки дизайна, разнося слабосвязанную ф-сть. В случае же борьбы с объективной сложностью, ищется компромисс, и Мейерс по этому неплохо прошелся. Ну да, ну разумеется, естественно, из всех вариантов стоит выбирать такой, где метрики наилучшие. Очень ценное замечание, угу. И кто здесь КО? Даже ничего, что эти оба указанных параметров неразрывно связаны, т.е. результаты декомпозиции некоего выделенного состояния/объекта достаточно оценивать по изменению одного из них. И пофиг, что этот же принцип был упомянут еще в самых первых же постах, и все последующее обсуждение шло не о том, правда это или нет, а о том, как к этому придти за меньшее число переделок. Можно смело называть глупостью и повторять потом эти же вводные.
Кстати, первоначальный рецепт все еще в силе. Он простой как три копейки (в грубом описании), но не имеет отношение к твоему замечанию. Достаточно делать любую полезную добавляемую внутреннюю функциональность видимой всем внутренним типам. Угу, смелое начало. Требует незначительных приседаний по обеспечению безопасности такого доступа. Но почему нет? Мы же в других случаях тоже на 100% знаем, что с первого раза взяли не разработаем идеальный дизайн. Дык, почему бы это знание не использовать? В каждом конкретном случае берется максимально высокоуровневый функционал (чтобы самому меньше писать), если он уже есть, или же делается для этих уникальных нужд. И ложится в "общий котел". Удовлетворив основные функциональные требования, мы получаем готовую схему связанности. Ой, так мы уже не должны "стремиться" или "пытаться" сделать дизайн с наилучшими показателями связанности, мы можем произвести точную наилучшую группировку функциональности для построения высокоуровневой архитектуры? (с целью формирования публичного АПИ, например) Коль у нас уже есть полный список всего. И мы уже воочио сталкивались с теми случаями, где нужна абстракция, и уже отличаем от тех случаев, где вовсе нет. Построение архитектуры фактически за один шаг? А почему нет? У всех тоже архитектура стабилизируется примерно к половине проекта, я лишь исключил промежуточные итерации, бо не обладаю полнотой информации. И не делаю вид, что обладаю. И что мне теперь делать с твоими "истинами"? Характерно, что рамки сего подхода тоже были очерчены с самого начала, оставив для самого верха КОП, т.е. рассматривался уровень ниже — это реализация компонент. И библиотек для них в т.ч.
Описанное XP? Вовсе нет, хотя кое-какие ее практики используются, план покрытия целевой функциональности известен заранее, как и прикинута его трудоемкость. Это всего-навсего функциональная декомпозиция. Да, банальность во всем этом была с самого начала, но не с того конца ее искали. Угу, та самая декомпозиция, неплохо работающая для сценариев, ориентированных на данные. И в рамках ООП-языков, что характерно, тоже. Буч, кстати, прошелся там по алгоритмической композиции в уничижительной форме, но это вовсе не то же, что функциональная. Последняя предлагает ср-ва абстрагирования через сигнатуры ф-ий, плюс мы это все приправляем легкостью связи с ООП, в С++ от рождения, в дотнете уже несколько лет как, и картинка выходит совсем другая. Про избавление от тонны лишних внутренних интерфейсов уже упоминал в пред. сообщении. В общем, как же он тут не прав:
Свободная подпрограмма, в терминологии C++, — это функция, не являющаяся элементом класса. Свободные подпрограммы не могут переопределяться подобно обычным методам, в них нет такой общности.
В общем, я уже не знаю, на каких пальцах объяснять очевидные вещи, чтобы не нарываться на глупые "ты изобрел отвественности" или "декомпозиция должна вестись так-то и так-то". А если не только ДЕкомпозиция, но и КОмпозиция? А если даже и это не суть, а упор на принятие важных решений ПОСЛЕ накопления информации? А если и это не было сутью, в обсуждении способов уменьшения необходимого кол-во итераций рефакторинга для достижения того же по качеству кода? Чем не полезная эвристика?
Re[14]: Почему объектно-ориентированное программирование про
Здравствуйте, Ikemefula, Вы писали:
V>>Таки нет. Декомпозиция состояния — это и есть декомпозиция в стиле классического ООП.
I>Ну тогда напримере паттернов враппер, адаптер, прокси, суррогат, декоратор поясни, где тут разделение состояния.
Адаптер — это не декомпозиция, а наоборот — композиция, т.е. усложнение. Структурные паттерны решают вопросы совместимости интерфейсов в системе статической типизации за счет дополнительных посредников.
Состоянием оперируют, например, поведенческие паттерны. Там наблюдается та самая декомпозиция внутреннего состояния по объектам. Самый яркий представитель сего семейства — паттерн state, посмотри его. Другие поведенческие паттерны через него легко выражаются.
В общем, без состояния нет поведения, это важно. Объект с методами, но без без состояния, представляет из себя просто набор ф-ий в некотором "неймспейсе". Здесь применим материал из дискретки, насчет функциональных преобразователей с памятью и без. Результат работы преобразователя без памяти предсказуем и зависит только от входных данных, в то время как результат работы преобразователя с памятью зависит от истории предыдущих вычислений, т.е. от его текущего "состояния".
Соответственно, декомпозируя состояние, мы декомпозируем поведение. Обратное не всегда верно — при надобности декомпозировать аспекты поведения, не всегда удается декомпозировать состояние. Это сразу дает понять, "кто тут главный". Наиболее популярная метрика для описанного момента — LCOM. Собсно, я её считаю самой важной, ибо по достижении наилучшего показателя по ней, остальные метрики можно тоже довести до максимума не изменяя иерархии, а только лишь причесав алгоритмы в методах. В идеале, состояние объекта должно в точности хранить пространство состояний эквивалентного автомата (преобразователя с памятью). При соблюдении этого, становится доступен весь формализм из автоматной теории. Если же подобную "идеальную" декомпозицию проделывать неохота, например, из соображений соответствия набора переменных и мысленной модели программы, то бишь из-за вносимой намеренно избыточности в пространство состояний, остается пользоваться эвристиками и приближенными оценками/метриками полученного решения. И самое главное — теперь надо бороться с этой избыточностью (обеспечивать безопасность операций), чтобы объект не оказался в неких невалидных координатах своего избыточного пространства состояний.
Re[16]: Почему объектно-ориентированное программирование про
Здравствуйте, Ikemefula, Вы писали:
I>Покажи как твой декоратор можно протестировать в изолированом виде
Ну блин, техника изоляции при тестировании всегда одна — через заглушки. А способов исполнения сих заглушек множество:
1. Использование собственных интерфейсов/абстрактных классов, суть фасадов/адаптеров третьесторонних классов, вместо использования их напрямую. Одна реализация интерфейсов будет "реальная", остальные — заглушечные в целях тестирования.
2. Использование дотнетной техники CBO. Не обязательно ручками, можно брать готовые mock-фреймворки.
3. Создание целых заглушечных сборок, содержащих одноименные используемые классы в тех же неймспейсах, что замещаемые сборки. С заглушечной же реализацией лишь минимального мн-ва используемых членов. Линковка тестовой сборки с ней. Я иногда прямо тестовые исходники в проект тестовых сборок включаю, особенно если самих тестовых сборок много и много тестовых уникальных "заглушечных" сценариев. Тоже потянет.
4. ... наверняка еще накидать способов можно. Повторюсь, детали реализации — это лишь детали. Ты применил абсолютно правильное слово — изоляция.
Вообще, тестопригодность — это фактически обязательное требование для компонент электронных устройств. Мне удивительно, что сие может подлежать обсуждению в ПО, где достичь того же эффекта можно на порядки меньшей трудоемкостью. Этот критерий должен быть вообще самым сильным и все остальные должен бороть, в случае конфликтов и "разрывов шаблонов". Т.е. "красотой иерархий" и прочей субъективной ерундой можно смело подтираться в угоду этому св-ву. Не то поиски багов будут регулярно превращаться в увлекательное приключение.
Re[10]: Почему объектно-ориентированное программирование про
S>Я немного не об этом. Вот возьмем некий алгебраический тип и функцию, которая принимает его и возвращает новый экземпляр. Можно трактовать этот процесс по Кею следующим образом: экземпляру АТД отправляем сообщение (передаем его функции) и получаем результат сообщения (новый АТД). Естественно, что традиционному ООП это поперек горла. Но в рамках Кея ФП и ООПК(ООП по Кею) можно в каком-то роде совмещать. Это мое предположение, и я без понятия как к этому отнесся бы сам Кей.
У функции нет собственного поведения, т.е. функциональности, зависящей от состояния, вот и все отличие.
S>Т.е. как бы можно взять за основу ФП декомпозицию, подменить кортежи бездушными структурами, АДТ подменить на гомоморфные иерархии, где в базе будет абстрактный интерфейс, составленный из набора функций, работающих с этим АДТ. Иммутабельность сохраняется.
Бенефит потоковой безопасности достигается так же локальностью ссылок. Тем не менее, иммутабельность на этапе обработки данных дает очень важное кач-во при последующей смене состояния. Ниже пройдусь.
S>В итоге получается как бы и ООП, но с ФП дизайном.
ФП-подход — это подход, ориентированный на функции высших порядков, как я себе представляю, чем он отличается от обычного процедурного подхода. Конечно, тоже полезная штука для абстрагирования, но скорее как инструмент для избавления от лишних зависимостей и от россыпи маленьких интерфейсов, чем как цель дизайна.
S>В том что это возможно, я нисколько не сомневаюсь, т.к. сам тяготею к такому стилю. Интересно обсудить его в плане обилия рефакторинга.
ФП подход сидит на алгоритмической декомпозиции. А та принципиально меньше тяготеет к рефакторингу, т.к. зависимостей в рамках одной ф-ии всяко меньше, чем сразу у группы оных.
Как уже тут было упомянуто, тяга к инкапсуляции подробностей реализации в больших ООП-проектах оборачивается тем, что приличная часть функционала делается многократно, но "чуть чуть" уникально для каждого объекта. И рефакторинг, помимо прочего, постоянно борется и с этим, по мере выявления схожей функциональности в соседних иерархиях. Т.е, хотя ООП и было призвано обеспечивать большее повторное применение кода, я пока вижу несколько обратное. А если бы сия функциональность была сразу доступна на уровне, скажем, модуля? Но это тоже не просто, ведь мы работаем с внутренним состоянием объектов. А что, если это состояние составлять из неких "стандартных кубиков" под нашу задачу? Мы ведь в процессе тщательного рефакторинга и объектной декомпозиции и так к этому приходим, правильно? За много итераций. Но в случае процедурного подхода, и аналогично ФП-подхода, мы вынуждены эти "стандартные кубики" разрабатывать сразу, как результат попытки реализации функциональных требований к программе. По-сути, мы вынуждены будем разработать представление/абстракции ДАННЫХ, и завязать их на алгоритмы по их трансформации. В ФП-языках эти кубики выглядят как алгебраические типы или туплы, иногда именованные — структуры/кортежи. Все кишки наружу и АПИ к ним не нарисуешь, поэтому "чистое ФП" меня не торкает. Применяя технику ООП, сии кубики можно сделать во-первых безопасными (располагаем инструментом инкапсуляции), во-вторых, нарисовать им удобный АПИ. Ну и согласен, гомоморфные наборы этих кубиков, если делать на ООП — вообще убийственная сила в плане прозрачности дизайна.
А что собственно произошло? Мы позволили процедурам и функторам принимать как аргументы и возвращать как результат объекты. Отличное дополнение к алгоритмической декомпозиции. Далее. Пытаемся реализовать ту самую функциональность, которая идет как функциональные требования. (Без всяких глобальных переменных, по крайней мере без мутабельных). В каких-то местах мы видим, что упираемся. Это происходит при надобности в какой-то точке вычислений обеспечить персистентность данных м/у вызовами. Т.е. сохранить состояние. Вот! Усек что произошло? Вместо заведомого "от балды" рисования семейства объектов-акторов, как участников "первого варианта дизайна" (который будет потом многократно перерефакторен), мы выходим на список объектов как бы автоматически, через мн-во состояний, требующих персистентности. И уже с готовыми "кубиками" наперевес, так что составить из них в нужном месте композицию получается совсем простым делом. Утрирую, понятно, но очень близко к происходящему.
S>Пробег. Информация безусловно полезная, но применительно к дизайну, она просто добавит карандашей, которые нужно сгрызть.
Вообще-то фокус был на порядок работ, чтобы минимизировать кол-во съеденных карандашей. По мне рефакторинг и есть перманентная грызня карандаша, только уже с помощью мышки и клавы.
V>>А не обязательно чистое ФП, со всеми модными фокусами. ФП сидит на функциональной декомпозиции, а это практически первое, чему учатся при обучении программированию. S>Дык и проблема в том что чистое ФП технически сложно на языках имеющих парадигму менее чем гибридную по отношению к ФП. Так или иначе получается адская мешанина.
Ты поменьше функциональщиков слушай.
Я тут многократно предлагал взглянуть на объекты как на автоматы (а они и есть автоматы), и позаимствовать оттуда кой-чего. Чем преобразователь-автомат отличается от простой цифровой функции? Наличием памяти. Cтруктура автомата (Мура) такова:
1. функция выходов, которая вычисляется от ф-ии входов и текущего состояния.
2. функция вычисления следующего состояния от входов и текущего состояния.
3. собственно память для хранения состояния.
п.п.1-2 абсолютно "чисты" с т.з. ФП, что как бэ намекает на уместность применения этого подхода для реализации объекта-автомата.
Вернемся к нашему подходу. Итого, "универсальные кубики", представляющие данные для сохранения в "памяти", уже есть. Ф-ия вычисления след. состояния, то бишь ф-ия обработки этих кубиков, тоже есть — мы с нее начали разработку. Теперь нам собрать "автомат", то бишь объект из этого — вовсе элементарно. И при этом новое состояние мы можем менять транзакционно (как работает регистр-защелка в цифровой электронике), тогда мы не будем иметь вообще никакой возможности вогнать автомат в невалидное состояние. Т.е. отделив в явном виде ф-ии вычисления след. состояния от собственно шага обновления состояния, мы можем добиться уникального в плане надежности качества — устойчивости к исключениям. Скажу по секрету, что сей устойчивостью 99% современного кода не обладают, потому как изменяют свое состояние обычно "постепенно", по мере работы. Т.е. объекты обычно ходят по промежуточным состояниям, и в случае исключения могут там и остаться. И что обычно происходит? Зачеркивается целиком всё, потому как разработка кода восстановления после ошибки больно трудоемка. В итоге, мы отказываемся еще от одной полезной практики, под названием "let it fail".
Еще момент. В многопоточных программах мы упомянутую "всевдоатомарность" пытаемся разрулись через примитивы синхронизации. Помимо того, что это не спасает от проблемы устойчивости к исключениям, мы еще блокируем эти примитивы на довольно долгий срок всех промежуточных вычислений (в общем случае). Хотя, это и так надо делать для случая писателей, но ведь это вовсе не нужно для случая читателей! Обрати внимание на изящное решение популярной проблемы читателей/писателей, получаемое вместе с транзакционностью, когда мы стадию вычисления следующего состояния отделили от операции по его обновлению.
Почему же функциональщики так жужжат о вреде смешения парадигм? Тут стоит вспомнить, что в деле разработки ПО всегда была куча вопросов, которые хотелось вывести на кончике пера, но они были для общего случая недоказуемы. Из-за той самой проблемы останова и прочих. Однако, было показано, что при наличии неких ограничений, под многое становится возможным подвести точную теорию. В итоге, "чистое ФП" — это наиболее ограниченная техника на сегодня, но благодаря ограниченности — единственная, имеющая хоть какой-то мат.аппарат. Поэтому, при нарушении наложенных ограничений, весь этот матаппарат нарушается. Но это с т.з. ФП. Что касается ООП, то он наоборот, обогащаемся целым набором замечательный св-в. Бери цифровую электронику. Это почти ООП (КОП в чистом виде) — интерфейсы и их реализации. И никто не страдает, что на одной плате есть как "чистые" цифровые ф-ии, так и россыпь автоматов. Прекрасно оно совместно работает. За счет той самой транзакционности смены состояний автоматов. Справедливости ради, в тех местах, где смена состояний растягивается на несколько шагов, в цифровой технике начинаются те же проблемы, что в ООП. И рядом сажают watch-dog таймеры, которые делают сброс охраняемой схемы, если её переклинило/зациклило в невалидном состоянии.
S>Я бы сказал что знаком с китом, а не владею.
Не скромничай. Создание делегата по нестатическому методу — это всегда замыкание, еще со времен первого дотнета. А ты наверняка делегатов насоздавал за свою практику уже немало.
S>В шарпе — да. Куда сложнее на C++ без 0x, с которым приходится иметь дело.
Дык, а boost:bind? А старые добрые std::bind1st, std::bind2nd? Та же фигня. А слоты и сигналы QT?
S>Мне довольно удобно. неудобно как раз видеть решение в ФП виде и адаптировать его к ООП.
Наверно, от образа мыслей зависит. По мне ФП хорошо, пока мы производим вычисления, и плохо, когда нам результат этого вычисления надо куда-то девать. Монада IO в Хаскеле как раз помечает те места, где "чистое ФП" умывает руки.
S>ООП ведь не запрещает анализ!
Ни одна методология не запрещает. Мое ИМХО о том, что ООП поощряет начинать сразу с квадратиков.
S>Дело в том, что код становится плохочитаемым не сам по себе, а в процессе изменений. И тут все-таки нужен рефакторинг, желательно в тот момент, когда код модифицирован, т.к. он только что прочитан и детали свежи.
Это в конкретном месте детали свежи. А если имеем несколько накопленных TODO, то можно попытаться обозреть проблему чуть более со стороны. И часто бывает так, что удовлетворяя один из них, можно удовлетворить целую пачку. В общем, перед решением любой задачи, желательно как можно больше вводных/требований. Хотя, каждый случай уникальный, понятно, и универсальных советов тут нет. Совет "рефакторить сразу" так же далек от универсальности.
S>TODO здесь поможет только в том случае, когда видно что плохо, но цель не ясна, т.к. связано с кодом, который в другом владении, либо неясна общая концепция.
Именно. Порой лучше оставить TODO с обозначением временного решения, до прояснения, с чего вообще такая ситуация возникла. При разделении труда в команде, с помощью этих TODO люди создают друг другу требования к внутреннему АПИ/функциональности, а современные IDE прекрасно составляют из них список в отдельном окошке.
S>В моей практике TODO имеют меньшие приоритеты чем issue в трэкере, потому плодятся как кролики. Стараюсь рефакторить сразу.
Ну естественно, функциональные требования в приоритете над требованиями дизайна. Но они обычно для удовлетворения требуют не столько рефакторинга, сколько доработки функциональности, что как бэ слегка иное.
Re: Почему объектно-ориентированное программирование провали
Здравствуйте, vdimas, Вы писали:
V>Мне демонстрировать ручную заглушку для этого случая или и так всё понятно? Хотя, и для первого случая заглушка может быть полезна для того, например, чтобы проверить, что этот вызов-таки был произведен в нужном месте. Чтобы не вручную, можно юзать какой-нить mock framework:
Не валяй дурака. Тебе надо было протестировать твой код, а не ThirdParty. Посему я скипнул порожний и неотносящийся к делу код. Похоже ты вообще не понимаешь, что пишешь
Показываю проблему тестирования в ТВОЕМ коде:
// тут наследуем, т.к. PreDo()/PostDo() требуют особого доступа к базе по условию,class PreAndPostDecorator : ThirdPartyClass
ThirdPartyClass - ЭТО ЖОСТКАЯ ЗАВИСИМОСТЬ КОТОРАЯ ПРЕПЯТСТВУЕТ ТЕСТИРОВАНИЮ
{
public void PreDo() {}
public void PostDo() {}
}
// структурная композицияclass PreAndPostDoerDecorator : IDoer
{
private PreAndPostDecorator _decorator = new PreAndPostDecorator();
ВОТ ЭТО ЖОСТКАЯ ЗАВИСИМОСТЬ КОТОРАЯ ПРЕПЯТСТВУЕТ ТЕСТИРОВАНИЮ
PreAndPostDoerDecorator(IDoer doer){ _doer = doer;}
void Do() {
_decorator.PreDo();
_doer.Do();
_decorator.PostDo();
}
}
interface IDoer
{
void Do();
}
Твой код НЕ ТЕСТИРУЕМЫЙ В ПРИНЦИПЕ, ТК НЕЛЬЗЯ ОТДЕЛИТЬ PreAndPostDoerDecorator от ThirdPartyClass, т.е
итого, что надо сделать, что бы твой декоторатор был тестируемым ?
// тут наследуем, т.к. PreDo()/PostDo() требуют особого доступа к базе по условию,class PreAndPostDecorator : ThirdPartyClass
{
publicvirtualvoid PreDo() {} // СМОТРИМ ВНИМАТЕЛЬНО - virtualpublicvirtualvoid PostDo() {} // СМОТРИМ ВНИМАТЕЛЬНО - virtual
}
class PreAndPostDoerDecorator : IDoer
{
private PreAndPostDecorator _decorator;
public PreAndPostDoerDecorator(PreAndPostDecorator d)
{
decorator = d;
}
public PreAndPostDoerDecorator(PreAndPostDecorator d)
{
decorator = = new PreAndPostDecorator();
}
PreAndPostDoerDecorator(IDoer doer){ _doer = doer;}
public void Do() {
_decorator.PreDo();
_doer.Do();
_decorator.PostDo();
}
}
interface IDoer
{
void Do();
}
и сам тест
[TestMethod]
public void TestDoerDecorator
{
var thirdPartyMock = new Mock<PreAndPostDecorator>();
Очевидно, решение не самое лучшее, т.к. PreAndPostDecorator вообще не нужен. Все что надо сделать — добавить возможность инжектить ThirdParty прямо в декоторатор ровно тем же способом, который был показан чуть выше.
Re[21]: Почему объектно-ориентированное программирование про
Здравствуйте, Ikemefula, Вы писали:
I>Здравствуйте, samius, Вы писали:
I>>>Кто такое сказал ? Какие проблемы возникают ? Какие есть более толковые решения ? Или же вопрос чисто идеологический ?
S>>Почитай у Кириевски, ты любишь на него ссылаться.
I>Ты про визитор ?
I>Современные ООП языки не умеют PM, сделано это не ради идеологии, а из за сложности реализации синтаксиса.
Если ты про C++, VB и C#, то куда им ПМ, если в них нет даже тюплов и АТД
Про сложность реализации синтаксиса — это ты тоже здорово махнул
I>Так шта...
Re[22]: Почему объектно-ориентированное программирование про
Здравствуйте, Ikemefula, Вы писали:
I>Показываю проблему тестирования в ТВОЕМ коде:
I>
I>// тут наследуем, т.к. PreDo()/PostDo() требуют особого доступа к базе по условию,
I>class PreAndPostDecorator : ThirdPartyClass
I>ThirdPartyClass - ЭТО ЖОСТКАЯ ЗАВИСИМОСТЬ КОТОРАЯ ПРЕПЯТСТВУЕТ ТЕСТИРОВАНИЮ
ИМХО, не надо быть мега-спецом, чтобы понять описанные способы:
1. Использование собственных интерфейсов/абстрактных классов, суть фасадов/адаптеров третьесторонних классов, вместо использования их напрямую. Одна реализация интерфейсов будет "реальная", остальные — заглушечные в целях тестирования.
2. Использование дотнетной техники CBO. Не обязательно ручками, можно брать готовые mock-фреймворки.
3. Создание целых заглушечных сборок, содержащих одноименные используемые классы в тех же неймспейсах, что замещаемые сборки. С заглушечной же реализацией лишь минимального мн-ва используемых членов. Линковка тестовой сборки с ней. Я иногда прямо тестовые исходники в проект тестовых сборок включаю, особенно если самих тестовых сборок много и много тестовых уникальных "заглушечных" сценариев. Тоже потянет.
Какой из 3-х способов вызывает трудности?
Ты отчасти правильно пишешь:
Тебе надо было протестировать твой код, а не ThirdParty.
Но лишь отчасти. Третьесторонний код тоже иногда приходится тестировать, когда возникают сомнения в его надежности (хотя в таких случаях полезней от сомнительного третьестороннего кода отказаться). Его можно тестировать по "артефактам", коль он порождает сайд-эффекты при своей работе. Вот их и тестируют. Даже если это запись в файл/базу или вывод сообщения протокола в сокет. Значит в тесте через независимое соединение лезешь в базу и проверяешь данные, читаешь файл, слушаешь сокет. Если без сайд-эффекта, то вопрос тестирования еще проще и сравним с тестированием одной ф-ии.
Код наследника от "черного ящика" точно так же тестируется. Этот код надо лишь отделить от базы.
Показываю техники для всех 3-х вариантов.
1.
class ThirdParty {
protected abstact int TemplateMethod();
protected void EntryPoint() {}
}
interface IThirdPartyCallback {
int TemplateMethod();
}
interface IThirdPartyAPI {
void EntryPoint();
}
class ThirdPartyAdapter : ThirdParty, IThirdPartyAPI {
IThirdPartyCallback _callback;
public ThirdPartyAccess(IThirdPartyCallback callback) { _callback = callback; }
new public void EntryPoint() { base.EntryPoint(); }
protected override int TemplateMethod() { return _callback.TemplateMethod(); }
}
public delegate IThirdPartyAPI ThirdPartyFactory(IThirdPartyCallback callback);
class InternalParty : IThirdPartyCallback {
IThirdPartyAPI _api;
public InternalParty(ThirdPartyFactory factory) { _api = factory(this); }
public void UsefulMethod() { _api.EntryPoint(); }
private int IThirdPartyCallback.TemplateMethod() { return 42; }
}
Итого, InternalParty тестируется отдельно от ThirdParty, через заглушку, реализующую IThirdPartyAPI. В случае, когда наследование не требуется, вся развязка с целью тестопригодности делается одним интерфейсом или абстрактным классом.
Подкорректируй под систему типов из способа 1. Или оставь как есть, если наследование от ThirdParty не нужно.
3. Самое что ни на есть решение "в лоб". Создаешь сборку, где в нужных неймспейсах пишешь тестового двойника ThirdParty под некоторые сценарий, с минимально необходимым интерфейсом. Линкуешь тестируемый код с этой сборкой, либо просто создаешь тестовую сборку из нужного набора файлов-исходников, куда включаешь исходный код двойника в т.ч.
Задача двойника — проверять в тестовом сценарии правильность протокола вызова его же методов внешним классом, и выдавать для этих сценариев ожидаемые ответные реакции. Т.е., рисовать в некое устройство не надо, надо лишь проверить, что тестируемый класс правильно вызывает наши методы рисования. Применяя этот способ, можно не заботиться насчет всей этой развязки на интерфейсах.
Способ, с одной стороны, самый трудоемкий, с другой — самый гибкий и самый приближенный к происходящему. Например, если у нас высоконагруженное решение, то все эти лишние развязки через интерфейсы могут заметно повлиять на производительность, поэтому "ручные" заглушки для пары мест в проекте могут оказаться кстати. Из наблюдений, сей подход практически изжил себя из-за обилия mock-фрейморков. Или народ хитрит, и делает объекты через MarshalByRefObject, чтобы юзать технику стабов из ремоутинга.
I>ВОТ ЭТО ЖОСТКАЯ ЗАВИСИМОСТЬ КОТОРАЯ ПРЕПЯТСТВУЕТ ТЕСТИРОВАНИЮ
Конечно, препятствует. Фигли:
Я скипнул порожний текст.
Не скипай, и не будет препятствовать. Все тестируют аж бегом, а у тебя, ясен пень, особый случай.
Ты его обрисовал уже, там ничего особого нет.
I>итого, что надо сделать, что бы твой декоторатор был тестируемым ?
Пройтись по интернету насчет более подробной инфы по указанным способам. Потом поставить у себя технический эксперимент. Возможно — задать пару вопросов в тематических форумах. В итоге, подобрать для вашей инфраструктуры наиболее удобный способ из описанных, или их комбинацию.
Re[22]: Почему объектно-ориентированное программирование про
Здравствуйте, Ikemefula, Вы писали:
I>Очевидно, решение не самое лучшее, т.к. PreAndPostDecorator вообще не нужен.
Ты на втором же посте после примера сказал, что нужен, упомянув использование методов базового класса. Отсюда все извороты.
I>Все что надо сделать — добавить возможность инжектить ThirdParty прямо в декоторатор ровно тем же способом, который был показан чуть выше.
Ты уже заблудился. В приведенном тобой примере ты тестируешь PreAndPostDoerDecorator, т.е. вот этот код:
А уже высказывал свои сомнения относительно необходимости писать для него тест.
Ты напиши изолированный тест для PreAndPostDecorator, который, например, нетривиально пользует базовый ThirdPartyClass. Вот что представляет интерес для тестирования.
Re[25]: Почему объектно-ориентированное программирование про
Здравствуйте, vdimas, Вы писали:
V>Ты пока проверил сам факт вызова методов целевого класса. Вместо целевого класса была заглушка. Мои поздравления, это было впечатляюще! Тестирования целевого класса не будет? Коль методы находятся в наследнике, они не пусты, что-то делают. Где тестовое покрытие этих методов? А базовый класс заведомо надежен?
Может тебе запостить сюда тесты для всего фреймворка ?
V>>>Ты напиши изолированный тест для PreAndPostDecorator, который, например, нетривиально пользует базовый ThirdPartyClass. Вот что представляет интерес для тестирования.
I>>Точно такой же подход.
V>Дык, покажи.
см выше
Re[57]: Почему объектно-ориентированное программирование про
Здравствуйте, Ikemefula, Вы писали:
I>Здравствуйте, samius, Вы писали:
I>>>Поскольку свою точку зрения ты отказываешься пояснить, смысла продолжать нету S>>Я пытался, но ты все время подразумеваешь что-то свое и пытаешься опровергнуть.
I>Дай ка ссылку, где ты пояснил напримерах свое высказывание ?
Пытался пояснить и пытался пояснить на примерах — это разные вещи, не мухлюй
S>>Вот ответь, контракт IEnumerator подразумевает иммутабельность?
I>Нет, в эти игры мы играть не будем. Сперва дай внятную, проверяемую трактовку своего высказывания, а потом продолжим.
Какого именно высказывания? Мне все больше кажется, что ты начал спорить с тем, чего не понял. Ну да я тут не причем.
I>Не способен приводить примеры — просто не отвечай, не переживай, не ты первый
Я уже приводил примеры. Iterator, Observer, State. Что я получил в ответ?
Цитирую
yield return
...
CurrentState().Method()
Потом я начал выяснять, не считаешь ли ты IEnumerator иммутабельным. А ты отказываешься играть в эти игры.
Вот так наша беседа вкратце выглядит для меня. В чем я действительно лажанулся — так это начал с тобой спорить притом что уже имел печальный опыт.
Я действительно намерен прекратить этот спор, потому как конструктива он не несет, и единственная очевидная цель в нем для меня убедить тебя что я не верблюд. Но с твоей терминологией и формальной логикой это бессмысленно.
Re[14]: Почему объектно-ориентированное программирование про
Здравствуйте, DarkGray, Вы писали:
DG>в wpf — есть и то, и другое, DG>в svg — тоже есть
И где там ООП? Неужели прямоугольник в WPF является наследником квадрата? Или наоборот?
DG>допустим мы описываем тип int с насыщением DG>тогда такой тип удобнее описать как DG>
DG>class BoundedInt<Range>
DG>{
DG> public BoundedInt(int value)
DG> {
DG> if (value < Range.MinValue)
DG> value = Range.MinValue;
DG> else if (value > Range.MaxValue)
DG> value = Range.MaxValue;
DG> this.value = value;
DG> }
DG> public int value;
DG> static BoundedInt<Range> operator + (BoundedInt<Range> v1, BoundedInt<Range> v2)
DG> {
DG> return new BoundedInt<Range>(v1.value + v2.value);
DG> }
DG>}
DG>
Нет, ну так не интересно. Это же не ООП — где тут сообщение, которое мы посылаем объекту? В ООП оператор + является методом, который применяется к левому аргументу. Так что это левый аргумент "решает", что именно вернуть, и это его поведение.
А статик метод поведение никакого объекта не описывает.
DG>>>что в этом такого странного? и в чем противоречие с ООП? S>>Противоречие не с ООП. Противоречие — с идиотским предположением о том, что ООП предлагает лепить классы с сущностей модели. Если у вас встанет задача смоделировать управление стройкой, то в вашем коде не будет никаких TКран, ТБульдозер, ТКаменщик или ТЦементМарки400.
DG>не будет, если будет абстрактное моделирование стройки — например, на уровне проектных граней, например, распределения ресурсов или там начисление зарплаты DG>но если будет моделирование именно стройки, например, игра-стройка, то все эти объекты появятся.
S>>Ничего из того, во что можно ткнуть пальцем на стройке, не проникнет в реальную модель вашей программы. Зато будет дохрена всяких штук типа TEditingSession, TChange, TMainWindow и прочего, что моделирует устройство исключительно самой программы. Никто в здравом уме не будет наследовать TПрораба от ТБригадира. Будет (в лучшем случае!) класс TEmployee. А то и его не будет — прекрасно обойдёмся тупо DataSet/DataRow, потому что никакого полиморфизма поведения у работников на стройке не предусмотрено.
DG>понятно, если речь идет чисто о задаче начисления зарплаты на стройке, то да — никаких прорабов и бригадиров не будет. DG>но если речь идет о моделировании взаимодействия между прорабом и бригадиром, то прорабы и бригадиры появятся.
DG>разные классы появляются, когда необходимо описать разное поведение. DG>если мы при моделировании отойдем слишком далеко, что нам уже будет пофигу — это стройка, магазин или дет.сад — то да, никаких объектов прораб, кирпич и арматура не будет. DG>если мы при моделировании подойдем слишком близко, и будет моделировать мир на уровне атомов — то да, тоже никаких объектов прораб, кирпич или арматура не будет. DG>да, все эти объекты появятся лишь только если мы будем моделировать именно саму стройку, а не что-то еще.
DG>имхо, ты на основе задач — а давайте мы напишем еще одну программу для начисления зарплаты на стройке, делаешь вывод о том, что для описания модели стройки — не нужны объекты прораб, бригадир или кирпич. DG>а это логически неверный вывод.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[32]: Почему объектно-ориентированное программирование про
Здравствуйте, Cyberax, Вы писали:
C>Эээ... Собственно, конкретное состояние в какой-то момент времени. Какие проблемы-то?
Проблемы лично у меня с тем, что identity получается утеряна. В классическом ООП можно абстрагироваться от состояния объекта, и отличать его от всех других.
К примеру, можно иметь некий dictionary, в котором лежат строки, индексированные thread.
В любой момент можно пойти в этот dictionary, имея ссылку на текущее состояние потока, и получить нужную строку.
В immutable реализации это невозможно: строку складывали со "старым" потоком, ищем с "новым".
Придётся вносить какой-нибудь threadID, который будет сохраняться при смене состояния потока.
А это и есть "ручная идентичность" в противовес "встроенной".
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[38]: Почему объектно-ориентированное программирование про
Здравствуйте, samius, Вы писали:
S>Я понимаю. Но в корне не согласен с тем что иммутабельный объект противоречит ООП своим существованием.
Ну пока что я не могу получить изоморфизм между поведением модели, построенной из "настоящих" объектов, и из иммутабельных объектов.
S>Мне непонятно в каком месте происходит "потеря" идентичности объекта. Все эти примеры манипулируют ссылками на объекты, хотя должны демонстрировать "потерю" идентичности объекта.
Идентичность тесно связана со ссылками. S>По определению идентичность — это такое свойство объекта, которое отличает его от остальных. После присваиваний ссылок объект остается вместе с тем свойством, которое его от остальных отличает.
Это понятно. Но у нас нет средства взаимодействовать с объектом без использования ссылок.
Поэтому все особенности поведения идентичности выявляются через манипуляции со ссылками.
Идентичность означает возможность однозначно и корректно ответить на вопрос "ссылаются ли эти две ссылки на один и тот же объект".
S>Нет, я пытался продемонстрировать что нормальный объект (мутабельный) точно так же "теряет" идентичность, как и иммутабельный (с ваших слов). На самом деле верно то что у другого объекта другая идентичность.
У вас не получилось. Объект идентичность не потерял. S>Так и иммутабельные объекты — они могут иметь структурную эквивалентность, а могут и нет. Способ по которому производится поиск в словаре завязан именно на эквивалентность объектов.
Конечно. Просто для value-типов ссылочная эквивалентность не имеет смысла. А для настоящих объектов — имеет, поскольку для них ссылка и есть их identity. S>И этот пример на эквивалентность. Его запросто заставить работать по-другому, если создать словарь с компарером, работающем на ReferenceEquals.
Можно. Но это не имеет физического смысла.
S>По-моему проще согласиться с тем что идентичность — неотъемлемая характеристика объекта, невзирая на возможность изменять его состояние (фактическое или наблюдаемое).
С этим никто не спорит. Вопрос только в том, имеет ли идентичность смысл для иммутабельных объектов.
S>Вообще говоря — любой объект можно считать иммутабельным в некоторой фазе работы программы. иммутабельные от мутабельных отличаются лишь тем, что для них эта фаза длится всё время жизни. А это не исключено и для мутабельных объектов, т.е. мутабельный объект может все время существования сохранять свое наблюдаемое состояние. Было бы странно если бы такое отличие как длина фазы иммутабельности влияло бы на идентичность объекта и как следствие на "истинную объектность".
Это какая-то гуманитарщина. Поймите, иммутабельность — это не случайно обнаруженное поведение программы. Это набор некоторых гарантий. Нельзя быть "немножко беременной", или "частично мужчиной". Гарантированная иммутабельность позволяет нам делать некоторые полезные преобразования программы, т.к. обеспечивает сохранение полезных инвариантов.
Казуальная иммутабельность — всего лишь досадная помеха: она ограничивает возможности наших действий, но не даёт выигрыша.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[2]: Почему объектно-ориентированное программирование пров
Здравствуйте, alex904, Вы писали:
A>Степанов много чего критикует, но никогда не разочаровывался в ООП вцелом.
А где про это? (Про то, что не разочаровывался.)
A>Та цитата была вырвана из разговора про Generic Programming. Под ООП в данном случае он имел классическую схему наследования и отметил, что она неэффективна для алгоритмических задач, где входные данные могут быть любым.
Откуда ты знаешь, что он там имел? Буквально было в частности следующее:
Здравствуйте, mister-AK, Вы писали:
D>>По-моему, это все же сарказм. Одно упоминание эфиродинамики и ненужности ТО чего стоит. D>>Или у автора совсем все плохо. MA>очередной высер в сторону Анри Пуанкаре или просто поклонни культового Альберта? а ты то готов высказать различие в действии эфиродинамики (световой эфир) и тёмной материи на модель вращения звезд в рукавах спиральных галлактик к примеру?
Я то не готов. Но у меня хватает мозгов понять, что для опровержения общепринятой фундаментальной теории надо несколько больше, чем походя ее пнуть в низкопробной статейке или намекнуть на фанатизм и культ автора.
Re: Почему объектно-ориентированное программирование провали
ИС>Авторы: ИС> Игорь САВЧУК
ИС>Аннотация: ИС>Среди множества идей, которые звучат красиво скорее в теории, чем на практике, объектно-ориентированное программирование занимает особое место. Попробуем разобраться и ответить на главный вопрос, почему всё же объектно-ориентированное программирование провалилось?
Это куда оно провалилось?
Программа — мысли спрессованные в код.
Re[2]: Почему объектно-ориентированное программирование пров
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>Этот прием совсем не нов и аппелирует не к сознанию, а к подсознанию. Его цель — заставить читающего подсознательно согласиться с высказываемой точкой зрения. Для многих высказаться вопреки общепринятой точке зрения очень нелегко, поэтому когда ему что-то подается как общепринятая точка зрения, он подсознательно вынужден с ней согласиться.
А ещё этот приём акцентирует внимание на первой части предложения, снижая внимание со второй.
Мсье Пуаро хочет знать, какого цвета была пара сапог, которые у Ральфа были в гостинице, – коричневого или черного? От этого многое зависит.
...
Откровенно признаюсь, что вопрос о цвете был поставлен лишь для того, чтобы скрыть цель моих расспросов.
Вы знаете, какие результаты дали наведенные ею справки. Выяснилось, что у Ральфа Пейтена действительно были с собой сапоги.
Вселенная бесконечна как вширь, так и вглубь.
Re[4]: Почему объектно-ориентированное программирование пров
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>Корректная полемика предполагает как минимум в начале формулировку разных точек зрения, после чего можно перейти к своим аргументам в пользу одной из них. Когда же с самого начала спорное утверждение подается как бесспорное и не объясняется почему (а в заголовке этого сделать нельзя) — это именно демагогия.
Да? А оригинальный заголовок (Objects Have Failed) это тоже демагогия или уже можно?
Re[4]: Почему объектно-ориентированное программирование пров
Здравствуйте, igna, Вы писали:
I>Здравствуйте, samius, Вы писали:
S>>Возможно стоит сменить название на следущее: Что считают гуру причиной провала ООП?
I>Не берусь говорить за гуру, на мой взгляд основная причина провала это наследование реализации.
Не хотел бы брать на себя выявление причин провала. Лишь показал что меня не устраивает в статье весьма пафосная вывеска без раскрытия темы.
I>Простейшая задача имеет порой заумную реализацию в ООП. Например требуется реализовать сравнение на равенство определенное следующим образом: два объекта равны, если все их составные части попарно равны. На шаблонах C++ реализация записывается буквально в соответствии с определением и в одну строку, в ООП, на том же C++, или на Java, или на С# начинаются пританцовывания на ровном месте с проверкой типа и т.п.
Согласен, что-то в этом есть. Тем более что в ООП не считается зазорным сравнивать объекты разных типов с различными количеством и типами составных частей. Хотя проблема тут скорее не в ООП, а в желании сравнивать объекты и их составные части, принадлежащих разным подъиерархиям.
Re[4]: Почему объектно-ориентированное программирование пров
Здравствуйте, samius, Вы писали:
S>Согласен, что-то в этом есть. Тем более что в ООП не считается зазорным сравнивать объекты разных типов с различными количеством и типами составных частей. Хотя проблема тут скорее не в ООП, а в желании сравнивать объекты и их составные части, принадлежащих разным подъиерархиям.
В данном случае проблема действительно не в ООП, а в конкретной его реализации в большинстве языков программирования, допускающих диспетчеризацию только по одному параметру. Тем не менее большинство программистов как бы не чувствуют закорюченности используемых ими ООП языков программирования, что печально, поскольку тормозит прогресс.
Re[2]: Почему объектно-ориентированное программирование пров
Здравствуйте, igna, Вы писали:
I>Здравствуйте, Pavel Dvorkin, Вы писали:
PD>>Корректная полемика предполагает как минимум в начале формулировку разных точек зрения, после чего можно перейти к своим аргументам в пользу одной из них. Когда же с самого начала спорное утверждение подается как бесспорное и не объясняется почему (а в заголовке этого сделать нельзя) — это именно демагогия.
I>Да? А оригинальный заголовок (Objects Have Failed) это тоже демагогия или уже можно?
Можно ссылку на этот оригинальный заголовок ? Я искать не буду.
With best regards
Pavel Dvorkin
Re[3]: Почему объектно-ориентированное программирование пров
Здравствуйте, dikun, Вы писали:
VE>>"Ну и где мы теперь, с этой вашей красивой теорией относительности [...]"
VE>>Гэбриел не в курсе про существование GPS что ли?
D>А где в GPS используется теория относительности?
Здравствуйте, Undying, Вы писали:
U>Здравствуйте, VoidEx, Вы писали:
VE>>Гэбриел не в курсе про существование GPS что ли?
U>Разработчик GPS с тобой не согласен:
U>http://bourabai.kz/hatch/clocks_rus.htm
Почему ни одна ссылка на странице невалидна? Можно поподробнее про это?
Re: Почему объектно-ориентированное программирование провали
Здравствуйте, igna, Вы писали:
I>Здравствуйте, Pavel Dvorkin, Вы писали:
PD>>Неудача объектно-ориентированного программирования.
PD>>В таком виде название звучит нейтрально.
I>И не по-русски.
I>Тогда уж должно быть "Провал объектно-ориентированного программирования".
Я не согласен, что это звучит не по-русски.
Что же касается твоей версии, то мне она пришла в голову, но я ее откинул. Слово "неудача" в русском языке нейтральное, а вот "провал" имеет ярко выраженный эмоциональный оттенок, настраивает на соответствующее отношение.
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>Неудача миссии НАТО в Афганистане приведет к распаду страны
PD>Нейтрально.
PD>Провал миссии Буллита
PD>Я еще не знаю, о чем там речь идет, но уже ясно — провалилась эта миссия.
И в Афганистане провалилось. Но дело даже не в этом, а в том, что слово "миссия" не является аналогом слова "объектно-ориентированное программирование", первое есть процесс, второе — нет. Поищи вот со словом "идеология", "провал идеологии" Google находит несколько сотен раз, а "неудача идеологии" — всего три раза, причем употреблены они там так же коряво.
Re[11]: Почему объектно-ориентированное программирование про
Здравствуйте, igna, Вы писали:
I>И в Афганистане провалилось. Но дело даже не в этом, а в том, что слово "миссия" не является аналогом слова "объектно-ориентированное программирование", первое есть процесс, второе — нет. Поищи вот со словом "идеология", "провал идеологии" Google находит несколько сотен раз, а "неудача идеологии" — всего три раза, причем употреблены они там так же коряво.
Я не буду спорить и настаивать на слове "неудача". Но найди иное слово, без эмоциональной окраски. Провал — слишком эмоционально. Если у меня что-то не получилось, это неудача, печально, а вот если провал — тут уже гораздо хуже. Давай оставаться по возможности в области рацио, а не эмоций. Целью же является убедить в правоте своей точки зрения, а не подсознательно навязать, так ?
With best regards
Pavel Dvorkin
Re[4]: Почему объектно-ориентированное программирование пров
Здравствуйте, shrecher, Вы писали:
S>Здравствуйте, мыщъх, Вы писали:
М>>Здравствуйте, shrecher, Вы писали:
М>>вопрос о провале ООП действительно встает на манагеровских митингах.
S>Итересно, почему вопрос встает на манагеровских митингах, не должны ли программисты или архитекты об этом заботится? Или в Макафи манагеры лучше рабираются на чем код писать? Хе-хе.
разбираются. и даже сам код пишут. в прошлом сами неплохие программисты и ведущие разработчики. а правильный выбор инструментов очень важен.
americans fought a war for a freedom. another one to end slavery. so, what do some of them choose to do with their freedom? become slaves.
Re[3]: Почему объектно-ориентированное программирование пров
Здравствуйте, Michael7, Вы писали:
M>Здравствуйте, Pavel Dvorkin, Вы писали:
PD>>Этот прием совсем не нов и аппелирует не к сознанию, а к подсознанию. Его цель — заставить читающего подсознательно согласиться с высказываемой точкой зрения. Для многих высказаться вопреки общепринятой точке зрения очень нелегко, поэтому когда ему что-то подается как общепринятая точка зрения, он подсознательно вынужден с ней согласиться.
M>Это в том случае когда сам тезис (провалилось) спорен или вовсе не верен. А если — нет, например "Почему X провалился на выборах?" До выборов, такой вопрос будет некорректен, но после — вполне, если X и в самом деле их не выиграл.
Совершенно верно. Хорошая, кстати, демонстрация. "Почему X провалится на выборах ?" — типичный прием того, о чем я говорил. А в твоем варианте — все корректно, провалился он.
With best regards
Pavel Dvorkin
Re[3]: Почему объектно-ориентированное программирование пров
Здравствуйте, VladD2, Вы писали:
VD>Здравствуйте, Pavel Dvorkin, Вы писали:
PD>>Читать не буду, потому что неинтересно.
VD>Где-то я это уже слышал... "Сам я Пастернака не читал, но как и весь Советский народ осуждаю..."
Название я прочитал. А о содержании не высказывался.
With best regards
Pavel Dvorkin
Re[2]: Почему объектно-ориентированное программирование пров
Здравствуйте, samius, Вы писали:
S>Да, возможно было навязано. Некрасиво, согласен. Но это не причина провала.
Ну, смотря что подразумевать под "провалом".
Исходя из того, что пишет Гэбриэл
В свете всего вышесказанного, можно с уверенностью заявить, что объектная парадигма обманула наши ожидания.
можно заключить, что "провалилась" означает "не оправдала оказанного доверия".
S>Возможно стоит сменить название на следущее: Что считают гуру причиной провала ООП?
Или так: Почему ООП утратило доверие?
Re[3]: Почему объектно-ориентированное программирование пров
Здравствуйте, Трурль, Вы писали:
Т>Здравствуйте, samius, Вы писали:
S>>Да, возможно было навязано. Некрасиво, согласен. Но это не причина провала. Т>Ну, смотря что подразумевать под "провалом". Т>Исходя из того, что пишет Гэбриэл Т>
В свете всего вышесказанного, можно с уверенностью заявить, что объектная парадигма обманула наши ожидания.
Т>можно заключить, что "провалилась" означает "не оправдала оказанного доверия".
Не оправдала доверия потому как была навязана? Тоже не годится. Надо зайти с другой стороны:
Т.е. Гэбриэл ожидал что использование объектной парадигмы приведет к чему-то важному для него, но этого не случилось. Причин этому может быть несколько: Гэбриэл что-то делал не так, либо действительно парадгима не в состоянии обеспечить это. Вот это последнее, наверное и может быть причиной утраты доверия. Но не тот факт что ООП была навязана или свалилась с неба в качестве откровения.
Откуда фраза, кстати? Что там было вышесказанного?
S>>Возможно стоит сменить название на следущее: Что считают гуру причиной провала ООП? Т>Или так: Почему ООП утратило доверие?
неа, на вопрос "почему" нужно отвечать. А по поводу гуру — можно просто накидать цитат и оставить все на суд читателя, что собственно и сделано в статье.
А то получается как в недавней передаче про отшельников (не помню по какому каналу и как называлась), где перед каждой рекламой трагическим голосом обещали рассказать "почему Перельман отказался от миллиона". В конце оказалось что интервью он им таки не дал, в итоге от всей передачи один только осадок.
Re[12]: Почему объектно-ориентированное программирование про
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>Я не буду спорить и настаивать на слове "неудача". Но найди иное слово, без эмоциональной окраски. Провал — слишком эмоционально. Если у меня что-то не получилось, это неудача, печально, а вот если провал — тут уже гораздо хуже. Давай оставаться по возможности в области рацио, а не эмоций. Целью же является убедить в правоте своей точки зрения, а не подсознательно навязать, так ?
Так реальное ООП и есть "гораздо хуже" чем просто печально. Устрашающее ведь количество человеко-лет и все на говно. Коммунизму и то можно поболее в плюс записать тем более если вспомнить чему на смену он пришел. А в программировании все было вполне неплохо, распространился Pascal, структурное программирование, языком восьмидесятых должны были стать Ada и Modula-2, в первом были даже какие-никакие генерики, вполне вероятно, что функциональное программирование начало бы входить в mainstream на 20 лет раньше, если бы не вдруг откуда не возьмись это ООП, да еще и в виде ужаса под названием C++.
Ну еще должен заметить, что под ООП имею в виду ООП с наследованием реализации, как его с появлением и внедрением C++ продавали широким массам вроде меня.
Re[13]: Почему объектно-ориентированное программирование про
Здравствуйте, igna, Вы писали:
I>Здравствуйте, Pavel Dvorkin, Вы писали:
PD>>Я не буду спорить и настаивать на слове "неудача". Но найди иное слово, без эмоциональной окраски. Провал — слишком эмоционально. Если у меня что-то не получилось, это неудача, печально, а вот если провал — тут уже гораздо хуже. Давай оставаться по возможности в области рацио, а не эмоций. Целью же является убедить в правоте своей точки зрения, а не подсознательно навязать, так ?
I>Так реальное ООП и есть "гораздо хуже" чем просто печально. Устрашающее ведь количество человеко-лет и все на говно. Коммунизму и то можно поболее в плюс записать тем более если вспомнить чему на смену он пришел. А в программировании все было вполне неплохо, распространился Pascal, структурное программирование, языком восьмидесятых должны были стать Ada и Modula-2, в первом были даже какие-никакие генерики, вполне вероятно, что функциональное программирование начало бы входить в mainstream на 20 лет раньше, если бы не вдруг откуда не возьмись это ООП, да еще и в виде ужаса под названием C++.
Ты не туда метишь. Я не обсуждал успех или неудачу ООП вообще. Я просто просил выбрать слово, которое нейтрально, без эмоций. "Провал" — слишком эмоционально, даже если там действительно провал. (В скобках — назвать провалом то, что реально используется, и широко используется, как-то все же странно, даже если считать это направление ошибочным). Я предложил "неудача", тебе не понравилось — предложи другое.
I>Ну еще должен заметить, что под ООП имею в виду ООП с наследованием реализации, как его с появлением и внедрением C++ продавали широким массам вроде меня.
Начнем очередной флейм о С++ ? Лучше не надо.
With best regards
Pavel Dvorkin
Re[4]: Почему объектно-ориентированное программирование пров
Здравствуйте, VladD2, Вы писали:
VD>Это не верная формулировка при наличии подтипов (что возможно и без наследования).
Подтипы без наследования в широком смысле (включая имплементирование интерфейсов) обсуждать не готов. Кроме того мое "наследование реализации" надо понимать в еще более широком смысле. Постараюсь объяснить, что имею в виду.
То, что проблему можно воспроизвести без наследования от класса, лишь имплементируя интерфейс, понятно; но в таком случае для воспроизведения проблемы понадобится метод с параметром типа этого интерфейса, метод этот становится внешней частью реализации интерфейса, и все типы имплементирующие этот интерфейс будут "наследовать" реализацию этого метода.
Такое обобщенное понимание интерфейса есть у Саттера (Exceptional C++, Item 32: Name Lookup and the Interface Principle).
Я использовал слово "имплементирование", когда речь идет об имплементировании интерфейсов в смысле implements в Java, и слово "реализация" когда речь идет об общем случае реализации. Для различения наследования в смысле extends в Java, и "наследования реализации" в обобщенном смысле во втором случае заключал это слово в кавычки.
VD>Если это так просто, то просьба продемонстрировать эту реализацию прямо здесь.
Здравствуйте, Трурль, Вы писали:
Т>Здравствуйте, samius, Вы писали:
S>>Откуда фраза, кстати? Что там было вышесказанного? Т>Да вот, из списка литературы.
Даже в закладках оказалась
S>>Т.е. Гэбриэл ожидал что использование объектной парадигмы приведет к чему-то важному для него, но этого не случилось. Причин этому может быть несколько: Гэбриэл что-то делал не так, либо действительно парадгима не в состоянии обеспечить это. Вот это последнее, наверное и может быть причиной утраты доверия. Но не тот факт что ООП была навязана или свалилась с неба в качестве откровения.
Т>Провал кукурузы в 60-х был обусловлен не какими-то имманентными свойствами кукурузы, а как раз тем, что она свалилась с неба.
Провалилась не кукуруза, а идея ее повсеместного засилия. Хотя не сказать что совсем провалилась, в моих широтах (средний урал) ей нынче кормят скот, а до 60х ей тут и не пахло
Re[3]: Почему объектно-ориентированное программирование пров
>>Пустой аргумент, ни в пользу ООП ни против. Какая разница что с чем связали?
Разница в том, что многие под достоинствами ООП понимают другие вещи. Например, я считаю достоинством ООП — удобное создание Абстрактных Типов Данных (АТД). Но нельзя не согласиться с Грэмом, что это фишка есть и вне ООП. А раз так, то относить ее к достоинствам ООП уже некорректно.
Скажем так — если собравшиеся мужики перед дискуссией не выписали на бумажке и не согласовали какие стороны они поддерживают — то это, мягко говоря, не в пользу диспута. То, что кто-то даже не удасужился выписать на листочке "ооп — это то-то и то-то" не может быть ни его достоинством, ни недостатком. А что до "многие считают" — многие вообще считают что программа на ООП — это кучка экземпляров глобальных классов, которые дергают друг и друга методы. И что с того?
Re[4]: Почему объектно-ориентированное программирование пров
Здравствуйте, Undying, Вы писали: VE>>Гэбриел не в курсе про существование GPS что ли?
U>Разработчик GPS с тобой не согласен: U>http://bourabai.kz/hatch/clocks_rus.htm
Нет это не аргумент. Если бы ученый хорошо знающий СТО+ОТО был бы несогласен тогда другое дело.
Да и из статьи следует что никаких проблем и отклонений в расчетах нет.
Есть только проблемы у него самого с объяснением этого всего на уровне болтологии/рассуждений без формул и без расчетов, на основе словестных обьяснений надерганных из какой-то литературы.
Есть где нибудь информация что описанные проблемы, еще для кого-то являются проблемами, или с расчетами значительно не сходится?
Часы GPS показывают, как и ожидается, что перемещающиеся часы идут медленней и, что часы идут медленней при более низком гравитационном потенциале.
Что ему еще надо?
Но объяснение Гофмана не может быть принято. Это противоречит поведению часов GPS.
Его комментарии к этой фразе похожи на болтологию. Тем более что он ничего вычислять и не пытался.
U>Разработчик GPS с тобой не согласен: U>http://bourabai.kz/hatch/clocks_rus.htm
Вобщем, Гофман согласен, Хатч не согласен.
Re[4]: Почему объектно-ориентированное программирование пров
Здравствуйте, Silver_S, Вы писали:
S_S> Нет это не аргумент. Если бы ученый хорошо знающий СТО+ОТО был бы несогласен тогда другое дело.
Вообще-то наука строится на фактах, а не на мнении авторитетов.
S_S>Да и из статьи следует что никаких проблем и отклонений в расчетах нет. S_S>Есть только проблемы у него самого с объяснением этого всего на уровне болтологии/рассуждений без формул и без расчетов, на основе словестных обьяснений надерганных из какой-то литературы. S_S> Есть где нибудь информация что описанные проблемы, еще для кого-то являются проблемами, или с расчетами значительно не сходится?
Читай внимательнее:
Но объяснение Гофмана не может быть принято. Это противоречит поведению часов GPS. Различие в солнечном гравитационном потенциале для GPS синхронизируемых в точке, ближайшей к Солнцу и дальней от Солнца ( различие в расстоянии приблизительно в четыре раза превосходит земного диаметр) кажется, не оказывает никакого влияния на часы GPS.
Т.е. объяснение Гофмана противоречит наблюдаемым фактам.
S_S>Вобщем, Гофман согласен, Хатч не согласен.
С точки зрения науки совершенно не важно с чем согласны или нет Гофман и Хатч, важно то, что объяснение предлагаемое Гофманом противоречит фактам, а, значит, является неверным.
Re[5]: Почему объектно-ориентированное программирование пров
Здравствуйте, Undying, Вы писали:
U>С точки зрения науки совершенно не важно с чем согласны или нет Гофман и Хатч, важно то, что объяснение предлагаемое Гофманом противоречит фактам, а, значит, является неверным.
Его рассуждения может чему то и противоречат. Но найдутся такие знатоки, которые якобы докажут, что теория относительности не верна потому что якобы есть проблема с парадоксом близнецов. На уровне рассуждений так все логично опишут что и не придерешься. Но проблемы то у них в рассуждениях.
Очень похоже это тот же случай с Хатчем.
Re[5]: Почему объектно-ориентированное программирование пров
Здравствуйте, Undying, Вы писали:
U>Читай внимательнее: U>
U>Но объяснение Гофмана не может быть принято. Это противоречит поведению часов GPS. Различие в солнечном гравитационном потенциале для GPS синхронизируемых в точке, ближайшей к Солнцу и дальней от Солнца ( различие в расстоянии приблизительно в четыре раза превосходит земного диаметр) кажется, не оказывает никакого влияния на часы GPS.
На земле нет разницы в ходе часов от такого фактора как разная близость к солнцу и разная скорость вращения вокруг солнца часов в разных точках, как-то компенсируются факторы.
Для разных точек спутниковой орбиты такой разницы тоже нет. Это пока еще ничему не противоречит.
Его обьяснения про то что радиус спутниковой орбиты в 4 раза больше земли неубедительны. Если он что по-делу хотел сказать, или что-то откопал толковое, привел хотя бы цифры — насколько у него расчеты не сходятся, миллионные доли процента или десятки процентов, но он этого и сам похоже не знает.
Re[5]: Почему объектно-ориентированное программирование пров
И кстати, самое главное, о каком порядке величин идет речь.
Это верно, что часы, которые облетают Солнце за год по радиусу земного полдня должны иметь тот же ход, что часы, которые облетают Солнце за год по радиусу земной полночи, то есть потенциальное гравитационное различие должно компенсироваться скоростным различием.
Какой получается порядок величины скоростного различия?
Скорость земли по орбите 100 000 км/ч. Радиус земли меньше радиуса ее орбиты в 12500 раз.
Разница скоростей между ночной и дневной орбитами 100000/12500 км/ч ~~ 8 км/ч
Это скорость пешехода. А скорости спутников в тысячи раз больше, если прибавить скорость пешехода то мало что изменится.
Если до такой точности эффекты проститывать, то гораздо сложнее, т.к. можно что-то потерять, привнести погрешность. Тем более что что там нелинейности. И тем более что там не только скорости замерять, а и отклонения от округлой формы Земли учитывать.
Я таких расчетов не делал и не видел, он похоже тоже.
P.S.
И вобще, если бы кто-то действительно нашел экспериментальные нестыковки в ТО. То ученые все бы бросили, забросили и многострадальный колайдер, ринулись бы ставить эксперименты перепроверять, такой бы шум подняли...
А так, есть еще не только Хатч, но и Хатчинсон
Вот первое из гугла, но сам не читал (только какой-то сюжет по ТВ видел): http://x-faq.ru/index.php?topic=67.0
Он уже научился делать антигравитацию, при помощи нескольких осциллографов и приборов 60-годов. Даже по телевидению показывали. Но все равно тишина по этому поводу, наверное не из-за того что антигравитация в народном хозяйстве пока не нужна.
А ао поводу Хатча, тишина, наверное не из-за того что что никому нет дела ТО ошибочна или нет.
Re[5]: Почему объектно-ориентированное программирование пров
Здравствуйте, igna, Вы писали:
I>В данном случае проблема действительно не в ООП, а в конкретной его реализации в большинстве языков программирования, допускающих диспетчеризацию только по одному параметру. Тем не менее большинство программистов как бы не чувствуют закорюченности используемых ими ООП языков программирования, что печально, поскольку тормозит прогресс.
Т. е. исходное утверждение сводится к "ООП провалилось, потому что в нём нет мультиметодов"? Не боитесь опухнуть это доказывать? Можете начать с того, что ООП исключает наличие мультиметодов. =))
Re[4]: Почему объектно-ориентированное программирование пров
Здравствуйте, SV., Вы писали:
SV.>Грамотная декомпозиция на значимые сущности...
Настоящим открытием для меня было, как мало людей умеют это делать. Взять хоть написание документа, посвященного интерфейсу разрабатываемого продукта П. Читаешь — все в кучу, мысли с пятого на десятое, оглавление похоже черт знает на что. Когда такие люди садятся программировать в ООП-стиле, можете себе представить.
Re[6]: Почему объектно-ориентированное программирование пров
Здравствуйте, SV., Вы писали:
SV.>Здравствуйте, gandjustas, Вы писали:
SV.>>>Сама "сомнительность" наследования реализации — следствие тех самых overhype и втыкания во все дыры. Сомнительным может быть конкретное применение, но не прием. Почему? Потому, что наследование реализации — объективное явление (вне нашего сознания и интерпретаций). И если оно наблюдается в моделируемом куске жизни, повторение его в модели (а любой софт это модель) делает ее полезнее. G>>Но далеко не любая программа является моделью части реального мира. Даже наоборот, программ где такой подход оправдан исчезающе мало.
SV.>Коль скоро это так, вас, конечно же, не затруднит привести пример программы, которая не является моделью?
Вот сейчас занимаюсь веб-приложением для автоматизации проектного управления. У меня там нет ни одного объекта, который является моделью объекта реального мира.
SV.>>>Например, и "воробьи", и "вороны" (обобщенно — "птицы") имеют в своем составе "крылья" и летает, "махая" ими. "Воробьи" являются "птицами", и летают как любая другая "птица" — "махая" (по-птичьи) "крыльями" (птичьими). НЕ ПОТОМУ, что внутри у "воробья" сидит абстрактная "птица" или какой-нибудь вполне конкретный "летатель", и летает за него (при этом, имеет форму черного ящика, то есть летает неизвестно как). При написании софта, надо повторять это объективное отношение (подкласс <вид "воробей"> наследует такое поведение, как полет, у суперкласса <класс "птиц">), потому, что такой софт проще писать, читать и понимать, а также потому, что дурацких противоречий ("Ва-а-ась, как оно теперь у нас будет плавать, с такими-то крыльями?!") гарантированно не возникнет. G>>Отношение is-a отлично достигается без наследования реализации. Интерфейсы (выше ты привел именно наследование интерфейсов), typeclasses в хаскеле, ducktyping в динамических языках. Это все позволяет выстраивать отношения is-a.
SV.>Откуда взялась такая странная цель — отношение is-a?
Так ты об этом написал выше. Переведя на английский часть выделенное выше получим "sparrow is a bird".
SV.>Что касается утиной типизации, то это способ перейти от явных контрактов к неявным, сэкономив на объявлении контракта, и к делу (способу выполнения контракта) не относится.
А вот и нет, далеко не всегда ты сможешь утинотипизированный код заменить на явнотипизированный. Далеко не все языки позволят такое написать.
G>>Ты в принципе попал в ту же проблему, куда попадают все "философы ооп". Они поголовно считают что все достижения ООП недоступны в других парадигмах, а на деле даже наоборот.
SV.>А это смотря что считать достижениями. Если is-a, то это не достижение, а тип отношения. Если код, который проще писать, читать и понимать, и с гарантированным уничтожением риска противоречий, то парадигма ООП может работать как на него, так и против. Примеры и того, и другого я привел.
А кто тебе сказал что наследование реализации "проще писать, читать и понимать"?
Re[7]: Почему объектно-ориентированное программирование пров
G>Вот сейчас занимаюсь веб-приложением для автоматизации проектного управления. У меня там нет ни одного объекта, который является моделью объекта реального мира.
но значит у тебя модель другого мира. модель проекта, например.
SV.>>Что касается утиной типизации, то это способ перейти от явных контрактов к неявным, сэкономив на объявлении контракта, и к делу (способу выполнения контракта) не относится. G>А вот и нет, далеко не всегда ты сможешь утинотипизированный код заменить на явнотипизированный. Далеко не все языки позволят такое написать.
так и пиши тогда целую фразу правильно: далеко не во всех языках ты сможешь утинотипизированный код заменить на явнотипизированный.
но ведь это же проблема языков. верно ведь?
G>А кто тебе сказал что наследование реализации "проще писать, читать и понимать"?
наследовать реализацию обычно проще, чем писать ее заново.
Re[7]: Почему объектно-ориентированное программирование пров
Здравствуйте, gandjustas, Вы писали:
SV.>>Коль скоро это так, вас, конечно же, не затруднит привести пример программы, которая не является моделью? G>Вот сейчас занимаюсь веб-приложением для автоматизации проектного управления. У меня там нет ни одного объекта, который является моделью объекта реального мира.
Техзадание на ваше приложение имеется? Оно — модель реальности, а ваш код — перевод этой модели с русского или английского языка на ЯП, а, следовательно, тоже модель. В то, что при переводе ключевые сущности оказались заменены другими, я не очень верю, но если поверить, то гордиться тут нечем. А если считаете, что есть чем, расскажите больше.
SV.>>>>Например, и "воробьи", и "вороны" (обобщенно — "птицы") имеют в своем составе "крылья" и летает, "махая" ими. "Воробьи" являются "птицами", и летают как любая другая "птица" — "махая" (по-птичьи) "крыльями" (птичьими). НЕ ПОТОМУ, что внутри у "воробья" сидит абстрактная "птица" или какой-нибудь вполне конкретный "летатель", и летает за него (при этом, имеет форму черного ящика, то есть летает неизвестно как). При написании софта, надо повторять это объективное отношение (подкласс <вид "воробей"> наследует такое поведение, как полет, у суперкласса <класс "птиц">), потому, что такой софт проще писать, читать и понимать, а также потому, что дурацких противоречий ("Ва-а-ась, как оно теперь у нас будет плавать, с такими-то крыльями?!") гарантированно не возникнет. G>>>Отношение is-a отлично достигается без наследования реализации. Интерфейсы (выше ты привел именно наследование интерфейсов), typeclasses в хаскеле, ducktyping в динамических языках. Это все позволяет выстраивать отношения is-a.
SV.>>Откуда взялась такая странная цель — отношение is-a? G>Так ты об этом написал выше. Переведя на английский часть выделенное выше получим "sparrow is a bird".
А если не часть перевести, а все целиком? Может, на английском понятнее будет?
Being a "bird", a "sparrow" flies like a "bird" NEITHER BECAUSE it delegates flying to an aggregated "bird" or a "flyer" (which are black box shaped at that, since we don't know how they fly), NOR because it somehow imitates flying in a special sparrow manner, but because it uses the same "wings" in the same way as every "bird" does. SO HOW DOES IT FLY?
К черту шутки и мой скверный английский. Каким образом обеспечивается is-a, вот о чем речь.
SV.>>Что касается утиной типизации, то это способ перейти от явных контрактов к неявным, сэкономив на объявлении контракта, и к делу (способу выполнения контракта) не относится. G>А вот и нет, далеко не всегда ты сможешь утинотипизированный код заменить на явнотипизированный. Далеко не все языки позволят такое написать.
Этого я не понял.
G>>>Ты в принципе попал в ту же проблему, куда попадают все "философы ооп". Они поголовно считают что все достижения ООП недоступны в других парадигмах, а на деле даже наоборот.
SV.>>А это смотря что считать достижениями. Если is-a, то это не достижение, а тип отношения. Если код, который проще писать, читать и понимать, и с гарантированным уничтожением риска противоречий, то парадигма ООП может работать как на него, так и против. Примеры и того, и другого я привел. G>А кто тебе сказал что наследование реализации "проще писать, читать и понимать"?
Я не буду уподобляться оверхайперам от ООП и принимать на себя бремя такого спорного утверждения, которое вы мне приписали. Вот мое утверждение: когда в моделируемой системе мы выделяем значимые сущности, одна из которых ведет себя как другая за счет того, что имеет те же приспособления, используемые таким же образом, то обе значимые сущности на этапе программирования должны стать классами, причем первый унаследовать реализацию от второго. Должны, конечно, если мы хотим иметь код, который проще писать, читать и понимать.
Re[8]: Почему объектно-ориентированное программирование пров
Здравствуйте, DarkGray, Вы писали:
G>>Вот сейчас занимаюсь веб-приложением для автоматизации проектного управления. У меня там нет ни одного объекта, который является моделью объекта реального мира.
DG>но значит у тебя модель другого мира. модель проекта, например.
Ты всегда сводишь к абсурду. У тебя получается что объект — модель какого-то "мира".
SV.>>>Что касается утиной типизации, то это способ перейти от явных контрактов к неявным, сэкономив на объявлении контракта, и к делу (способу выполнения контракта) не относится. G>>А вот и нет, далеко не всегда ты сможешь утинотипизированный код заменить на явнотипизированный. Далеко не все языки позволят такое написать.
DG>так и пиши тогда целую фразу правильно: далеко не во всех языках ты сможешь утинотипизированный код заменить на явнотипизированный.
Далеко не во всех вообще возможна утиная типизация. но если взять типовой язык где она возможна (js) и сравнить с типовым языком со статической типизацией (java) то многое не получится в них выразить.
DG>но ведь это же проблема языков. верно ведь?
Не языков, а парадигмы. Об этом и разговор.
G>>А кто тебе сказал что наследование реализации "проще писать, читать и понимать"? DG>наследовать реализацию обычно проще, чем писать ее заново.
Есть другие способы повторного использования кода.
Re: Почему объектно-ориентированное программирование провали
Здравствуйте, Игорь САВЧУК, Вы писали:
ИС>Аннотация: ИС>Среди множества идей, которые звучат красиво скорее в теории, чем на практике, объектно-ориентированное программирование занимает особое место. Попробуем разобраться и ответить на главный вопрос, почему всё же объектно-ориентированное программирование провалилось?
Никто никуда не проваливался. И парадигма позволяет стандартным образом подходить к новой задаче. Это уже плюс так как стандартизирует сам процесс понимания и общения.
Re[8]: Почему объектно-ориентированное программирование пров
Здравствуйте, SV., Вы писали:
SV.>Здравствуйте, gandjustas, Вы писали:
SV.>>>Коль скоро это так, вас, конечно же, не затруднит привести пример программы, которая не является моделью? G>>Вот сейчас занимаюсь веб-приложением для автоматизации проектного управления. У меня там нет ни одного объекта, который является моделью объекта реального мира.
SV.>Техзадание на ваше приложение имеется? Оно — модель реальности, а ваш код — перевод этой модели с русского или английского языка на ЯП, а, следовательно, тоже модель.
См выделенное.
SV.>В то, что при переводе ключевые сущности оказались заменены другими, я не очень верю, но если поверить, то гордиться тут нечем. А если считаете, что есть чем, расскажите больше.
Спокойно. Проект на sharepoint, основные объекты с которым приходится работать это "сайт", "список" и "элемент списка". Причем ни один из них никак не фигурирует ни в каких ТЗ.
SV.>>>>>Например, и "воробьи", и "вороны" (обобщенно — "птицы") имеют в своем составе "крылья" и летает, "махая" ими. "Воробьи" являются "птицами", и летают как любая другая "птица" — "махая" (по-птичьи) "крыльями" (птичьими). НЕ ПОТОМУ, что внутри у "воробья" сидит абстрактная "птица" или какой-нибудь вполне конкретный "летатель", и летает за него (при этом, имеет форму черного ящика, то есть летает неизвестно как). При написании софта, надо повторять это объективное отношение (подкласс <вид "воробей"> наследует такое поведение, как полет, у суперкласса <класс "птиц">), потому, что такой софт проще писать, читать и понимать, а также потому, что дурацких противоречий ("Ва-а-ась, как оно теперь у нас будет плавать, с такими-то крыльями?!") гарантированно не возникнет. G>>>>Отношение is-a отлично достигается без наследования реализации. Интерфейсы (выше ты привел именно наследование интерфейсов), typeclasses в хаскеле, ducktyping в динамических языках. Это все позволяет выстраивать отношения is-a.
SV.>Каким образом обеспечивается is-a, вот о чем речь.
Именно, я тебе выше написал что много других способов. Причем наследование реализации — далеко не самый лучший.
Вообще говоря наследование реализации в ООП обычно совмещается с наследованием интерфейса (кроме private наследования в С++), причем is-a достигается именно наследованием интерфейса, а наследование реализации позволяет повторно использовать код базового класса.
G>>А кто тебе сказал что наследование реализации "проще писать, читать и понимать"?
SV.>Я не буду уподобляться оверхайперам от ООП и принимать на себя бремя такого спорного утверждения, которое вы мне приписали. Вот мое утверждение: когда в моделируемой системе мы выделяем значимые сущности, одна из которых ведет себя как другая за счет того, что имеет те же приспособления, используемые таким же образом, то обе значимые сущности на этапе программирования должны стать классами, причем первый унаследовать реализацию от второго.
Кому должны?
SV.>Должны, конечно, если мы хотим иметь код, который проще писать, читать и понимать.
стати практика показывает обратное, если мы на этапе проектирования будет модели 1-в-1 перекладывать в структуры классов то получится *опа.
Возникают type-test там где не надо, double dispatch, визиторы и прочие гадости.
Re[10]: Почему объектно-ориентированное программирование про
DG>>>но значит у тебя модель другого мира. модель проекта, например. G>> G>>Ты всегда сводишь к абсурду. У тебя получается что объект — модель какого-то "мира".
DG>объект — это слово(понятие) модели обычно.
А мы вообще-то говорим про объекты и классы в ОО-языках.
DG>>наследовать реализацию обычно проще, чем писать ее заново. G>>Есть другие способы повторного использования кода. DG>например?
Композиция.
Re[11]: Почему объектно-ориентированное программирование про
Здравствуйте, DarkGray, Вы писали:
DG>>>>наследовать реализацию обычно проще, чем писать ее заново. G>>>>Есть другие способы повторного использования кода. DG>>>например? G>>Композиция.
DG>и чем наследование реализации отличается от композиции кроме названия?
Наследование реализации создает отношение is-a (кроме приватного наследования в C++), тогда как композиция не создает.
Re[14]: Почему объектно-ориентированное программирование про
Здравствуйте, DarkGray, Вы писали:
DG>проблема начинается, когда люди начинают считать, что наследуя реализацию — они при этом автоматически получают наследование внешнего контракта, а также что получили отношение is-a.
В общем да. Но вообще есть LSP который запрещает использовать наследование без отношения is-a.
Re[12]: Почему объектно-ориентированное программирование про
Здравствуйте, SV., Вы писали:
SV.>Здравствуйте, gandjustas, Вы писали:
SV.>>>>>Техзадание на ваше приложение имеется? Оно — модель реальности, а ваш код — перевод этой модели с русского или английского языка на ЯП, а, следовательно, тоже модель. G>>>>См выделенное. SV.>>>>>В то, что при переводе ключевые сущности оказались заменены другими, я не очень верю, но если поверить, то гордиться тут нечем. А если считаете, что есть чем, расскажите больше. G>>>>Спокойно. Проект на sharepoint, основные объекты с которым приходится работать это "сайт", "список" и "элемент списка". Причем ни один из них никак не фигурирует ни в каких ТЗ.
SV.>>>Это как с утиной типизацией — контракт задается неявно, но это не значит, что его нет. Чтобы в этом убедиться, попробуйте пасхалкой встроить тетрис. Это к вопросу о ТЗ. G>>Вообще не понял причем тут пасхалки.
SV.>Пасхалки тут вот причем. Вы говорите, что сайты, списки и айтемы не фигурируют в ТЗ. Я говорю: хорошо, тетрис в вашем ТЗ наверняка тоже не фигурирует. Но если вы займетесь тетрисом, а не списками и сайтами, то почувствуете разницу. А если разница есть, может ваше ТЗ просто недостаточно детализировано и они там подразумеваются? Или, как я написал выше, "контракт задается неявно, но это не значит, что его нет".
А причем тут список в ТЗ? Ты же говорил про объекты реального мира. Список, который указан в ТЗ, ничему в реальном пире не соотвествует.
Если ты начинаешь выдумывать объекты см, то можешь и любые отношения между ними построить, но это уже будет не моделирование.
SV.>На этом я предлагаю тему моделирования закруглить.
Да уже и так съехали на непонятно что.
SV.>>>Это утверждение бессмысленно вне контекста. В контексте одних объектов — не самый лучший, других — самый лучший, третьих — худший. Должен ли я приводить соответствующие примеры? G>>Попробуй.
SV.>У вас есть прибор А, который управляются через двунаправленный dataport потоком команд. Допустим, с набором из 3 лампочек — красной, синей и зеленой. Послали в порт turn green on — зеленая лампочка зажглась. Послали turn green off — она же погасла. А вам надо получить API, который абстрагирует вашего пользователя от всей специфики работы с портами.
SV.>Уже здесь есть выбор — делать ли такую сущность, как класс Device с методами типа TurnGreenOn() (и иметь картину кода, повторяющую окружающий мир) или, скажем, завести просто отдельную функцию на каждую команду. Через год оказывается, что приборов может быть к вашему писюку подключено несколько (хотя клиент клялся, что такого не будет), и один делает коллекцию Device'ов, а второй — отдельно передаваемый параметр (идентификатор прибора) в каждую функцию.
SV.>Есть еще вариант с картой <cmdid | "command text"> и единственным методом SendCommand. Он, во-первых, недружественен, а во-вторых делает слишком мало полезного. Например, если понадобится прикрутить кэширование состояния лампочек, это будет делать ваш пользователь.
Ты рассматриваешь проектирование классов не знаю какие задачи на них возлагаются. так нельзя делать, ничего хорошего их этого не выйдет.
А правильные задачи класса можно получить декомпозиции общей задачи.
Это и называется проектирование "сверху вниз", которое многие адепты ООП как раз и не любят, потому что в итоге оно не дает нам модели объектов реального мира.
SV.>Допустим, вы-таки написали класс Device. За это время на базе прибора А был построен прибор Б. То есть, буквально — взяли прибор А и допаяли к нему дополнительный аппаратный модуль, например, динамик. От этого он не утратил ни лампочки, ни возможность управлять ими, но приобрел какое-то дополнительное свойство, в нашем случае — издавать звуки. Соответственно, от класса Device наследуется DeviceExt, с добавленным методом Beep() (который посылает в порт строку make bebeep). В результате выбрать тип устройства можно ровно один раз — инстанцируя фабрикой тот или иной класс. Ошибки выбора будут собраны все в одном месте. В дальнейшем ваш пользователь НЕ МОЖЕТ попросить прибор без гудка погудеть. Кроме того, глядя на этот код:
SV.>
SV.>ваш пользователь понимает, что API поддерживает два типа приборов. Эта информация зашита в сам API и не требует отдельной документации.
Прекрасный пример.
Теперь представим что у нас появился другой прибор, который умеет гудеть и не умеет зажигать лампочки. При этом у нас фактически разные UI отвечают за лампочки и за гудки. То есть один фактически получать на вход ILightDevice, а другой ISoundDevice, но сами интерфейсы при этом не связаны между собой.
Это очень яркая демонстрация вреда наследования, как инструмента проектирования.
И все потому что ты изначально привязался к устройству как к модели реального мира, а я рассматриваю это как набор выполняемых функций.
Остальное комментить не буду, ибо совсем незачем.
Re[14]: Почему объектно-ориентированное программирование про
Здравствуйте, DarkGray, Вы писали:
G>>Наследование реализации создает отношение is-a (кроме приватного наследования в C++), тогда как композиция не создает.
DG>это есть часто повторяемое заблуждение.
DG>если брать пару: круг и эллипс, то можно для круга наследовать реализацию от эллипса и "открутить лишнее", а можно DG>для эллипса наследовать реализацию от круга и "прикрутить дополнение". DG>и оба подхода будет верными в том, или ином контексте.
Оба они почти наверняка будут нарушать LSP. Есть реальный пример обратного — приводи.
DG>проблема начинается, когда люди начинают считать, что наследуя реализацию — они при этом автоматически получают наследование внешнего контракта, а также что получили отношение is-a.
Это по факту так и есть.
Если у тебя A унаследован от B, то в любом месте где требуется B ты можешь подставить A.
Наследование реализации наследования интерфейсов и отношения is-a в некоторых языках есть и называется mixin. Тоже концепция, уводящая в сторону от ООП.
Re[15]: Почему объектно-ориентированное программирование про
Z>В общем да. Но вообще есть LSP который запрещает использовать наследование без отношения is-a.
принцип Лисковой говорит о взаимодействие с внешним миром и соответственно о наследование внешнего контракта(интерфейса), а не о наследовании реализации — которая отвечает за внутреннее устройство объекта
Re[16]: Почему объектно-ориентированное программирование про
Здравствуйте, DarkGray, Вы писали:
G>>Оба они почти наверняка будут нарушать LSP. Есть реальный пример обратного — приводи.
DG>если учесть, что круг и эллипс состоят в отношениях нарушающих принцип Лискова (в обе стороны), то это нормально.
DG>зы DG>если брать полный контракт эллипса, то круг вместо него нельзя использовать (т.к. он, например, не имеет двух фокусов) DG>а эллипс нельзя использовать вместо круга.
Ну так я и говорю: приведи тот самый контекст где наследование с эллипса от круга или наоборот будет корректным.
Re[17]: Почему объектно-ориентированное программирование про
G>Ну так я и говорю: приведи тот самый контекст где наследование с эллипса от круга или наоборот будет корректным.
если у нас такой контракт круга и такая реализация эллипса
interface ICircle
{
PointF Center {get;}
double Radius {get;}
double Square {get;}
}
class Ellipse
{
public Ellipse(PointF center, double radius1, double radius2){..}
public readonly PointF Center;
public readonly double Radius1;
public readonly double Radius2;
public double Square {get{..}}
}
то наследование реализации эллипса для круга будет удачным решением
class Circle:Ellipse,ICircle
{
public Circle(PointF center, double radius):base(center, radius, radius){}
public double Radius {get {return Radius1;}}
public double ICircle.Center {get {return this.Center;}}
}
Re[18]: Почему объектно-ориентированное программирование про
Здравствуйте, DarkGray, Вы писали:
G>>Ну так я и говорю: приведи тот самый контекст где наследование с эллипса от круга или наоборот будет корректным.
DG>если у нас такой контракт круга и такая реализация эллипса DG>
DG>interface ICircle
DG>{
DG> PointF Center {get;}
DG> double Radius {get;}
DG> double Square {get;}
DG>}
DG>class Ellipse
DG>{
DG> public Ellipse(PointF center, double radius1, double radius2){..}
DG> public readonly PointF Center;
DG> public readonly double Radius1;
DG> public readonly double Radius2;
DG> public double Square {get{..}}
DG>}
DG>
DG>то наследование реализации эллипса для круга будет удачным решением DG>
DG>class Circle:Ellipse,ICircle
DG>{
DG> public Circle(PointF center, double radius):base(center, radius, radius){}
DG> public double Radius {get {return Radius1;}}
DG> public double ICircle.Center {get {return this.Center;}}
DG>}
DG>
Ты приведи как это будет использоваться в программе.
А то я не вижу причин чтобы такой код мог реально где-то встретиться.
Re[19]: Почему объектно-ориентированное программирование про
G>Ты приведи как это будет использоваться в программе. G>А то я не вижу причин чтобы такой код мог реально где-то встретиться.
как-то так
Ну, сделали и мы в Блицкриге эту самую ракету. Как и немцы, сделали ее уже ближе к концу проекта и соорудили на базе объекта "самолет". Но программисты несколько схалтурили и не пооткручивали у бывшего самолета подозрительную для баллистической ракеты функциональность. Оказалость, что если во время полета к цели начинал идти дождь или снег, то во-первых ракета говорила человеческим голосом "Fliege zuruck"(нем. лечу назад), а во-вторых разворачивалась и летела обратно на базу. Фигли там, погода то нелетная.
..
Со свиньями был связан, кстати, еще один баг, из-за которого игра падала. В какой-то момент программисты что-то такое там подкрутили и свиньи перестали быть нейтральными, а обрели возможность принадлежать какому-то игроку. Управлять ими было нельзя, но формально они могли быть "наши" или "ненаши". Так вот свиньи роняли игру. Потому что видя неприятеля, патриотичная хавронья хотела дать врагу отпор и лезла за оружием, которого у нее естественно не было. Если мне не изменяет память, программисты исправили баг, просто выдав свинье пистолет Люгер без патронов. Визуально это никак не видно, но формально, теперь, видя врага, она лезет за оружием, видит что патронов нет и на этом успокаивается.
Здравствуйте, gandjustas, Вы писали:
G>А причем тут список в ТЗ? Ты же говорил про объекты реального мира. Список, который указан в ТЗ, ничему в реальном пире не соотвествует.
Ну что, опять самоцитироваться? Я уже написал, какому объекту реального мира сответствует список.
SV.>>Допустим, вы-таки написали класс Device. За это время на базе прибора А был построен прибор Б. То есть, буквально — взяли прибор А и допаяли к нему дополнительный аппаратный модуль, например, динамик. От этого он не утратил ни лампочки, ни возможность управлять ими, но приобрел какое-то дополнительное свойство, в нашем случае — издавать звуки. Соответственно, от класса Device наследуется DeviceExt, с добавленным методом Beep() (который посылает в порт строку make bebeep). В результате выбрать тип устройства можно ровно один раз — инстанцируя фабрикой тот или иной класс. Ошибки выбора будут собраны все в одном месте. В дальнейшем ваш пользователь НЕ МОЖЕТ попросить прибор без гудка погудеть. Кроме того, глядя на этот код:
SV.>>
SV.>>ваш пользователь понимает, что API поддерживает два типа приборов. Эта информация зашита в сам API и не требует отдельной документации.
G>Прекрасный пример.
G>Теперь представим что у нас появился другой прибор, который умеет гудеть и не умеет зажигать лампочки. При этом у нас фактически разные UI отвечают за лампочки и за гудки. То есть один фактически получать на вход ILightDevice, а другой ISoundDevice, но сами интерфейсы при этом не связаны между собой.
Если у нас появился другой прибор, значит поменялся окружающий мир. И наша ООП-модель ему больше не соответствует. Разумеется, не надо пытаться натягивать ее до конца, а надо взять и отрефакторить ОМ в очередной версии. Рефакторинг, конечно, сведется к тому, что ILightDevice и ISoundDevice будут разнесены и не связаны между собой. Но даже при этом сохранится смысл наследования реализаций (а о нем мы спорим, как о самом спорном приеме ООП, не так ли?), поскольку оба прибор по-прежнему имеют датапорт и умеют принимать в него строки (то есть, имеют объект класса Port и метод Send(string) к нему).
Самое приятное, что увидев новый API, пользователь сразу поймет, что теперь одни приборы могут светить, а другие гудеть, а некоторые (может быть) и то, и другое. Без документации.
G>Это очень яркая демонстрация вреда наследования, как инструмента проектирования. G>И все потому что ты изначально привязался к устройству как к модели реального мира, а я рассматриваю это как набор выполняемых функций.
Я не "привязывался" в том смысле, что код написан один раз и навека. Привязка в моем понимании значит, что при изменении прототипов ООП модель, как привязанная, должна меняться вслед за ними.
G>Остальное комментить не буду, ибо совсем незачем.
Re[14]: Почему объектно-ориентированное программирование про
Здравствуйте, SV., Вы писали:
SV.>Здравствуйте, gandjustas, Вы писали:
G>>А причем тут список в ТЗ? Ты же говорил про объекты реального мира. Список, который указан в ТЗ, ничему в реальном пире не соотвествует.
SV.>Ну что, опять самоцитироваться? Я уже написал, какому объекту реального мира сответствует список.
Нет, ты придумал этот объект. Список не является результатом моделирования.
SV.>>>Допустим, вы-таки написали класс Device. За это время на базе прибора А был построен прибор Б. То есть, буквально — взяли прибор А и допаяли к нему дополнительный аппаратный модуль, например, динамик. От этого он не утратил ни лампочки, ни возможность управлять ими, но приобрел какое-то дополнительное свойство, в нашем случае — издавать звуки. Соответственно, от класса Device наследуется DeviceExt, с добавленным методом Beep() (который посылает в порт строку make bebeep). В результате выбрать тип устройства можно ровно один раз — инстанцируя фабрикой тот или иной класс. Ошибки выбора будут собраны все в одном месте. В дальнейшем ваш пользователь НЕ МОЖЕТ попросить прибор без гудка погудеть. Кроме того, глядя на этот код:
SV.>>>
SV.>>>ваш пользователь понимает, что API поддерживает два типа приборов. Эта информация зашита в сам API и не требует отдельной документации.
G>>Прекрасный пример.
G>>Теперь представим что у нас появился другой прибор, который умеет гудеть и не умеет зажигать лампочки. При этом у нас фактически разные UI отвечают за лампочки и за гудки. То есть один фактически получать на вход ILightDevice, а другой ISoundDevice, но сами интерфейсы при этом не связаны между собой.
SV.>Если у нас появился другой прибор, значит поменялся окружающий мир. И наша ООП-модель ему больше не соответствует. Разумеется, не надо пытаться натягивать ее до конца, а надо взять и отрефакторить ОМ в очередной версии. Рефакторинг, конечно, сведется к тому, что ILightDevice и ISoundDevice будут разнесены и не связаны между собой.
А зачем что-то делать, а потом рефакторить, если можно заранее избежать проблем? Ведь способ с двумя интерфейсами решает все проблемы, про которые ты тут рассказываешь, а наследование эти проблемы создает.
Кстати выделенное — бред. Мир не меняется, меняется набор наших знаний о нем.
SV.>Но даже при этом сохранится смысл наследования реализаций (а о нем мы спорим, как о самом спорном приеме ООП, не так ли?), поскольку оба прибор по-прежнему имеют датапорт и умеют принимать в него строки (то есть, имеют объект класса Port и метод Send(string) к нему).
А зачем тогда класс прибора нужен вообще? Создаются объекты, которые получают на вход Port (вернее IPort) и отправляют команды.
Ну и все. Связь с "реальным миром" (который фактически набор знаний) мы потеряли, от этого программа стала более устойчивой к изменениям этого "реального мира".
Имеет смысл наследование реализации без наследования интерфейса. В большинстве ОО-языков наследование реализации без наследования интерфейса невозможны, а вот mixins и typeclasses позволяют полностью разделить реализацию и интерфейсы.
SV.>Самое приятное, что увидев новый API, пользователь сразу поймет, что теперь одни приборы могут светить, а другие гудеть, а некоторые (может быть) и то, и другое. Без документации.
ILightDevice, ISoundDevice изначально решают проблему без наследований, необходимости рефакторингов итп.
G>>Это очень яркая демонстрация вреда наследования, как инструмента проектирования. G>>И все потому что ты изначально привязался к устройству как к модели реального мира, а я рассматриваю это как набор выполняемых функций.
SV.>Я не "привязывался" в том смысле, что код написан один раз и навека. Привязка в моем понимании значит, что при изменении прототипов ООП модель, как привязанная, должна меняться вслед за ними.
Так ты понял вообще что твоя привязка создала работу, которую можно было и не делать при другом способе проектирования?
Вот в этом и заключается вся жопа ООП, вернее ООАД.
Re[14]: Почему объектно-ориентированное программирование про
Здравствуйте, SV., Вы писали:
SV.>Здравствуйте, gandjustas, Вы писали:
G>>Ты рассматриваешь проектирование классов не знаю какие задачи на них возлагаются. так нельзя делать, ничего хорошего их этого не выйдет. G>>А правильные задачи класса можно получить декомпозиции общей задачи. G>>Это и называется проектирование "сверху вниз", которое многие адепты ООП как раз и не любят, потому что в итоге оно не дает нам модели объектов реального мира.
SV.>Вот это пропустил. А зря. Как говорил наш преподаватель математики, ЧТД. Человек, которому попадет в руки ваш код, должен будет разбираться с особенностями вашей индивидуальной "декомпозиции общей задачи", вашего понимания общей задачи, и со всеми вашими тараканами. Человек, которому попадет в руки ООП-код с моделью, будет одновременно изучать и предметную область. Если он знает предметную область, то на понимание кода ему вообще не понадобятся усилия.
Модель предметной области — тоже результат некоторой индивидуальной умственной деятельности и обладает теми же свойствами.
Нету однозначного рецепта получения правильной модели предметной области в вакууме. Даже эванса почитай — он пишет про множество адаптаций и рефакторингов относительно изначальной картины.
Кроме того domain-driven design получается слишком сложным. То есть не-domain-driven код проще писать, читать и понимать (это и адепты ddd признают и не рекомендуют ddd для простых проектов), чем dd код.
Re[4]: Почему объектно-ориентированное программирование пров
Здравствуйте, SV., Вы писали:
SV.>Сама "сомнительность" наследования реализации — следствие тех самых overhype и втыкания во все дыры. Сомнительным может быть конкретное применение, но не прием. Почему? Потому, что наследование реализации — объективное явление (вне нашего сознания и интерпретаций). И если оно наблюдается в моделируемом куске жизни, повторение его в модели (а любой софт это модель) делает ее полезнее.
Проблема не в наследовании реализации как таковом, а в том, что оно неразрывно и неотделимо связано с наследованием контракта.
... << RSDN@Home 1.2.0 alpha 5 rev. 1495 on Windows 7 6.1.7600.0>>
Здравствуйте, gandjustas, Вы писали:
G>Далеко не во всех вообще возможна утиная типизация. но если взять типовой язык где она возможна (js) и сравнить с типовым языком со статической типизацией (java) то многое не получится в них выразить.
С чего ты взял, что утиная типизация противоречит статической? Утиная типизация это просто вшитый в язык для простейших случаев паттерн адаптер.
Собственно, в хорошо знакомом тебе шарпе утиная типизация кое где присутствует. Например, при создании делегата для конкретного метода.
... << RSDN@Home 1.2.0 alpha 5 rev. 1495 on Windows 7 6.1.7600.0>>
Здравствуйте, DarkGray, Вы писали:
AVK>>Проблема не в наследовании реализации как таковом, а в том, что оно неразрывно и неотделимо связано с наследованием контракта.
DG>почему это утверждение верное?
Не понял вопроса
... << RSDN@Home 1.2.0 alpha 5 rev. 1495 on Windows 7 6.1.7600.0>>
AVK>>>Проблема не в наследовании реализации как таковом, а в том, что оно неразрывно и неотделимо связано с наследованием контракта.
DG>>почему это утверждение верное?
AVK>Не понял вопроса
на основе какой логической цепочки следует, что наследование реализации неотделимо связано с наследованием контракта?
Re[8]: Почему объектно-ориентированное программирование пров
Здравствуйте, DarkGray, Вы писали:
AVK>>Не понял вопроса
DG>на основе какой логической цепочки следует, что наследование реализации неотделимо связано с наследованием контракта?
Это следует не на основе логической цепочки, а на основе того, что мы наблюдаем в большинстве мейнстримовых ООП языков.
... << RSDN@Home 1.2.0 alpha 5 rev. 1495 on Windows 7 6.1.7600.0>>
Здравствуйте, Undying, Вы писали:
VE>>Гэбриел не в курсе про существование GPS что ли? U>Разработчик GPS с тобой не согласен: U>http://bourabai.kz/hatch/clocks_rus.htm
Ну так и Лисперы вот говорят, что это они всё придумали и могут переписать все программы мира за 10 минут.
Sapienti sat!
Re[4]: Почему объектно-ориентированное программирование пров
Здравствуйте, VoidEx, Вы писали:
U>>Разработчик GPS с тобой не согласен: U>>http://bourabai.kz/hatch/clocks_rus.htm VE>Почему ни одна ссылка на странице невалидна? Можно поподробнее про это?
Обычный фрик, не обращай внимания.
Sapienti sat!
Re[10]: Почему объектно-ориентированное программирование про
Здравствуйте, AndrewVK, Вы писали:
AVK>Здравствуйте, gandjustas, Вы писали:
G>>Далеко не во всех вообще возможна утиная типизация. но если взять типовой язык где она возможна (js) и сравнить с типовым языком со статической типизацией (java) то многое не получится в них выразить.
AVK>С чего ты взял, что утиная типизация противоречит статической? Утиная типизация это просто вшитый в язык для простейших случаев паттерн адаптер.
А с чего ты это взял? Выделенное смотри.
AVK>Собственно, в хорошо знакомом тебе шарпе утиная типизация кое где присутствует. Например, при создании делегата для конкретного метода.
Она там в первую очередь присутствует в query comprehensions, в foreach и async, а еще в C# есть dynamic и библиотека Clay
Re[10]: Почему объектно-ориентированное программирование про
Здравствуйте, DarkGray, Вы писали:
DG>без логической цепочки — это лишь проблемы этих мейнстрим-языков, а не проблема принципа "наследование реализации"
Верно. Именно это я и пытался сказать — проблема не в принципе.
... << RSDN@Home 1.2.0 alpha 5 rev. 1495 on Windows 7 6.1.7600.0>>
Здравствуйте, AndrewVK, Вы писали:
SV.>>Сама "сомнительность" наследования реализации — следствие тех самых overhype и втыкания во все дыры. Сомнительным может быть конкретное применение, но не прием. Почему? Потому, что наследование реализации — объективное явление (вне нашего сознания и интерпретаций). И если оно наблюдается в моделируемом куске жизни, повторение его в модели (а любой софт это модель) делает ее полезнее.
AVK>Проблема не в наследовании реализации как таковом, а в том, что оно неразрывно и неотделимо связано с наследованием контракта.
Что такое контракт? В строгом смысле мейнстримные языки Contract programming вообще не поддерживают, а в бытовом смысле надо уточнять. Что будет контрактом в шарпе?
Re[15]: Почему объектно-ориентированное программирование про
Здравствуйте, gandjustas, Вы писали:
G>Модель предметной области — тоже результат некоторой индивидуальной умственной деятельности и обладает теми же свойствами.
Обладает, но в меньшей мере. Знаете, как говорят — дураки спорят о крайностях, а умные — о мере?
G>Нету однозначного рецепта получения правильной модели предметной области в вакууме. Даже эванса почитай — он пишет про множество адаптаций и рефакторингов относительно изначальной картины.
Нету. Но давайте не будем уподобляться дуракам из цитаты выше.
G>Кроме того domain-driven design получается слишком сложным. То есть не-domain-driven код проще писать, читать и понимать (это и адепты ddd признают и не рекомендуют ddd для простых проектов), чем dd код.
Re[16]: Почему объектно-ориентированное программирование про
Здравствуйте, SV., Вы писали:
SV.>Здравствуйте, gandjustas, Вы писали:
SV.>>>Ну что, опять самоцитироваться? Я уже написал, какому объекту реального мира сответствует список. G>>Нет, ты придумал этот объект. Список не является результатом моделирования.
SV.>Как по-вашему работали отделы статистики до изобретения компьютеров?
Это тут причем? Ты опять выдумываешь модель для того кода, который изначально не был моделью чего-то.
SV.>>>Если у нас появился другой прибор, значит поменялся окружающий мир. И наша ООП-модель ему больше не соответствует. Разумеется, не надо пытаться натягивать ее до конца, а надо взять и отрефакторить ОМ в очередной версии. Рефакторинг, конечно, сведется к тому, что ILightDevice и ISoundDevice будут разнесены и не связаны между собой.
G>>А зачем что-то делать, а потом рефакторить, если можно заранее избежать проблем? Ведь способ с двумя интерфейсами решает все проблемы, про которые ты тут рассказываешь, а наследование эти проблемы создает.
SV.>Затем, что мой пример — из жизни, а ваш — из области фантастики.
У меня в каждом проекте таких примеров немеряно.
SV.>Зная, однако, что некоторые клиенты/менеджеры рождены, чтоб сказку сделать былью, я не стал отнекиваться, а написал, что должен делать хороший ООПер в такой ОЧЕНЬ маловероятной ситуации.
Да, действительно есть тенденция говорить что неудобные ситуации маловероятны. А по факту наоборот.
Расширение спектра различных устройств случается гораздо чаще, чем апгрейд какого-то одного устройства.
SV.>>>Но даже при этом сохранится смысл наследования реализаций (а о нем мы спорим, как о самом спорном приеме ООП, не так ли?), поскольку оба прибор по-прежнему имеют датапорт и умеют принимать в него строки (то есть, имеют объект класса Port и метод Send(string) к нему).
G>>А зачем тогда класс прибора нужен вообще? Создаются объекты, которые получают на вход Port (вернее IPort) и отправляют команды.
SV.>Затем, чтобы ваш пользователь мог включать и выключать лампочки и бикать спикером, не создавая объекта Port и не отдавая его на вход. Этим занимается фабрика, как я и написал. Возлюбите своего пользователя, дабы он не возлюбил вас через саппорт.
А причем тут пользователь? Он вообще в кнопочки на экране тыкает. Ему нет разницы какого класса объекты создаются.
Re[16]: Почему объектно-ориентированное программирование про
Здравствуйте, SV., Вы писали:
SV.>Здравствуйте, gandjustas, Вы писали:
G>>Модель предметной области — тоже результат некоторой индивидуальной умственной деятельности и обладает теми же свойствами.
SV.>Обладает, но в меньшей мере.
Докажи. Вряд ли у тебя получится, потому что эта мера и зависит от конкретного человека.
SV.>Знаете, как говорят — дураки спорят о крайностях, а умные — о мере?
Знаю, но это к теме разговора не имеет отношения.
Re[15]: Почему объектно-ориентированное программирование про
Здравствуйте, Ziaw, Вы писали:
DG>>проблема начинается, когда люди начинают считать, что наследуя реализацию — они при этом автоматически получают наследование внешнего контракта, а также что получили отношение is-a.
Z>В общем да. Но вообще есть LSP который запрещает использовать наследование без отношения is-a.
Был приведен пример независимых иерархий, по каждой из которых существует свое is-a. Похожая задача была про квадрат, ромб и прямоугольник, кого от кого наследовать. Никого ни от кого. Имеем несколько паралельных иерархий, и сия ситуация решается множественным наследованием для реализации конечных типов. Ну или миксинами для C# и иже с ними.
Re[16]: Почему объектно-ориентированное программирование про
Здравствуйте, vdimas, Вы писали:
DG>>>проблема начинается, когда люди начинают считать, что наследуя реализацию — они при этом автоматически получают наследование внешнего контракта, а также что получили отношение is-a.
Z>>В общем да. Но вообще есть LSP который запрещает использовать наследование без отношения is-a.
V>Был приведен пример независимых иерархий, по каждой из которых существует свое is-a. Похожая задача была про квадрат, ромб и прямоугольник, кого от кого наследовать. Никого ни от кого. Имеем несколько паралельных иерархий, и сия ситуация решается множественным наследованием для реализации конечных типов. Ну или миксинами для C# и иже с ними.
Я не пойму, что ты хочешь сказать. Я возразил на выделенное, проблема начинается когда дизайн иерархии перестает удовлетворять LSP. Который как раз для этого случая и придуман, там прямым текстом написано: не хотите проблем — не делайте так.
Я не вижу никакой необходимости множественного наследования или миксинов в данной ситуации. И вообще не понимаю, что такое миксины для C#. Если требуется какой-то полимофризм их следует наследовать от фигуры.
Re[6]: Почему объектно-ориентированное программирование пров
Здравствуйте, vdimas, Вы писали:
V>Здравствуйте, gandjustas, Вы писали:
G>>Но далеко не любая программа является моделью части реального мира.
V>При чем тут "реального"? Ключевое слово — модель. Например, можно брать математические модели.
Математическая модель — набор формул. Этот набор формул никак не связан с классами и объектами.
Связь модели с классами только в голове разработчика.
G>>Даже наоборот, программ где такой подход оправдан исчезающе мало. V>Попробуй привести пример, который тут не раскатают по асфальту.
Пример чего?
G>>Отношение is-a отлично достигается без наследования реализации. Интерфейсы (выше ты привел именно наследование интерфейсов), typeclasses в хаскеле, ducktyping в динамических языках. Это все позволяет выстраивать отношения is-a.
V>Я бы не стал ducktyping приравнивать к is-a. Ибо сие отношение как раз служит для для типизированных языков как инструмент проверки контрактов в compile-time. Для ООП-скриптовых языков ducktyping работает на уровне отдельного метода, и лишь предоставляет способ реализации обмена сигналами для целей собственно работы ООП в этой динамике.
Какая-то слишком заумная фраза, смысл её мне остался непонятен.
V>Насчет твоей фразы наследования интерфейсов — не уверен, что ты сам понял, что сказал. В ООП интерфейсом называют публичное АПИ классов, оно и наследуется автоматически. Если же ты про термин "Interface" из COM, особенность которого была повторена в Delphi/Java/C#, то его следует называть "абстрактным интерфейсом".
Кем принято? Ссылку на первоисточник.
Тут все понимают интефейс, как явно указанный набор методов\свойств, которые реализует объект.
V>Заметь, с т.з. клиентов таких интерфейсов, им глубоко до фени, абстрактный он или нет, это подробности уже самого интерфейса.
Замечу что это неверно, особенно когда дело касается наследования.
V>Абстрактные интерфейсы предназначены для случая надобности сокрытия полного АПИ реализующих классов, ведь термин "абстракция" означает выделение сути/основы. То, что в некоторых языках абстрактные интерфейсы используются порой для побочных целей, например для порождения нескольких параллельных иерархий is-a — лишь следствие отсутствия в этих языках множественного наследования. То бишь, инструмент абстрагирования применяется даже там, где размер задачи абстрагирования не требует.
Ну это твои домыслы, которые не соответствуют практике.
V>Рациональное зерно в наследовании абстрактных интерфейсов для построения объектной иерархии разумеется есть. И чем больше иерархия, тем больше в этом смысла. Мы избавляем такую иерархию от подробностей реализации составляющих её элементов, т.е. банально уменьшаем информационную сложность иерархии. Причем, учитывая связи м/у объектами (например, из-за использования общих или базовых реализаций), мы можем нарваться на рост числа зависимостей, близкий к квадратичному от кол-ва элементов иерархии. И вот смотрим на современные программы, где многие десятки сущностей, если не сотни... Понятное дело, что есть здравое желания снизить сложность архитектуры системы на порядок и даже чуть больше.
Смотрю я .NET FW ине могу найти интерфейсов, более 3 уровней наследования.
Видимо создатели библиотек в 200000 классов (кажись такое число) не разделяют твоего мнения.
SV.>>>Грамотная декомпозиция на значимые сущности должна быть переложена на ЯП без изменений, с сохранением всех отношений, в т.ч. наследования реализаций.
G>>Выделенное необоснованно.
V>Оно ничему не противоречит. Даже имея описанный вариант системы, иерархия которой расписана на абстрактных интерфейсах, ничто не мешает использовать наследование реализаций для конкретных используемых типов.
Если прочитаешь внимательно, то тут многие говорят что наследование реализации без наследования интерфейсов вполне можно безопасно (то есть не не создавая проблем) использовать.
Основная проблема в том что в большинстве языков наследование реализации автоматически наследует интерфейс.
V>Вы в пылу спора всё время забываете, что вся эта абстрактность — вторична.
Абстрактность ты придумал. Я использую интерфейс для отделения вещей друг от друга.
G>>Ты в принципе попал в ту же проблему, куда попадают все "философы ооп". Они поголовно считают что все достижения ООП недоступны в других парадигмах, а на деле даже наоборот. V>Расшифруй, плиз, о каких достижениях речь, и куда именно попал твой оппонент? Сдается мне, тут уже наблюдается тихий спор с самим собой.
Чаще всего укушенные ООП любят говорить что только ООП позволяет полиморфизм и отношение is-a.
Re[16]: Почему объектно-ориентированное программирование про
Здравствуйте, vdimas, Вы писали:
V>Здравствуйте, gandjustas, Вы писали:
G>>Наследование реализации наследования интерфейсов и отношения is-a в некоторых языках есть и называется mixin. Тоже концепция, уводящая в сторону от ООП.
V>Глупость. Миксин — это вынужденно используемый инструмент для удобства программирования в ограниченной разновидности ООП — компонентном программировании. Где же тут "в сторону"? Это на маленьком островке внутри ООП.
ООП: инкапсуляция, полиморфизм, наследование реализации с интерфейсом. mixin_ы в эту формулу не вписываются, они расширяют ООП.
Re[12]: Почему объектно-ориентированное программирование про
Здравствуйте, vdimas, Вы писали:
V>Здравствуйте, gandjustas, Вы писали:
DG>>>>>но значит у тебя модель другого мира. модель проекта, например. G>>>> G>>>>Ты всегда сводишь к абсурду. У тебя получается что объект — модель какого-то "мира".
DG>>>объект — это слово(понятие) модели обычно. G>>А мы вообще-то говорим про объекты и классы в ОО-языках.
V>Ну так в ООП объект и представляет из себя элемент модели. Класс — это уже термин из области типов, к понятию "объект" в общем случае ортогональный.
Ага, только в типизированных языках каждый объект имеет некоторый класс. Так что не ортогональный.
G>>Композиция.
V>Наследование реализации в ООП — это и есть агрегирование, что есть частный случай композиции.
Это ты что-тоне то выдумал. Наследование и агрегирование — разные вещи.
V>В общем, ты опять попутал причину и следствие. Миксины не самоцель, а инструмент, пригодный для обхода ограничений языка.
Для обхода ограничений ООП. Ну об этом я и говорю.
Re[21]: Почему объектно-ориентированное программирование про
Z>Приведены баги вызванные подобным наследованием и остроумные костыли для их обхода. Какая логика привела тебя к выводу "всех устраивает, если сделано аккуратно"?
всех устраивает, если исходить из совокупности параметров "качество/цена"
могли разработчики написать ракету с нуля, а не наследовать реализацию от самолета? могли
код был бы чище? скорее всего -да
почему не сделали? да, потому что — это выливается в большие временные затраты: необходимо заново выписывать требования, заново проектировать, заново кодировать, заново тестировать. наследование реализации позволило существенно сэкономить на всех 4-х этапах.
Z>То, что софт почти с любыми архитектурными проблемами можно заставить заработать, я думаю, ни для кого из здесь присутствующих не новость, это не значит, что проблемы всех устраивают.
это ты говоришь лишь про максимизацию параметра "качество" без учета "цены".
да, если нам нужно именно сверхкачество, то приходится отказываться от наследования реализации, и если мы берем те же самолеты, то там пишется три копии ПО без всякого наследования реализации для такого чтобы избежать наведенных проблем от наследования реализации.
но если берется менее критичная область, то наследование реализации вовсю используется, т.к. позволяет сильно улучшить параметр "цена".
Re[7]: Почему объектно-ориентированное программирование пров
Здравствуйте, gandjustas, Вы писали:
SV.>>Коль скоро это так, вас, конечно же, не затруднит привести пример программы, которая не является моделью? G>Вот сейчас занимаюсь веб-приложением для автоматизации проектного управления. У меня там нет ни одного объекта, который является моделью объекта реального мира.
Не совсем ясно, что ты понимаешь под объектами реального мира. "собака", "кошка" ?
А куда деть явления, отношения ? Ну, например, "проект"
Re[8]: Почему объектно-ориентированное программирование пров
Здравствуйте, Ikemefula, Вы писали:
I>Здравствуйте, gandjustas, Вы писали:
SV.>>>Коль скоро это так, вас, конечно же, не затруднит привести пример программы, которая не является моделью? G>>Вот сейчас занимаюсь веб-приложением для автоматизации проектного управления. У меня там нет ни одного объекта, который является моделью объекта реального мира.
I>Не совсем ясно, что ты понимаешь под объектами реального мира. "собака", "кошка" ?
I>А куда деть явления, отношения ? Ну, например, "проект"
Да пожалуйста. В постановке задачи у меня есть "проект" и в интерфейсе много где есть "проект", а вот класса "проект" нету.
Re[17]: Почему объектно-ориентированное программирование про
Здравствуйте, gandjustas, Вы писали:
V>>Глупость. Миксин — это вынужденно используемый инструмент для удобства программирования в ограниченной разновидности ООП — компонентном программировании. Где же тут "в сторону"? Это на маленьком островке внутри ООП.
G>ООП: инкапсуляция, полиморфизм, наследование реализации с интерфейсом. mixin_ы в эту формулу не вписываются, они расширяют ООП.
Смешались в кучу люди, кони.
У меня после прочтения тебя в этой ветке сложилось впечатление, что ты на всё смотришь под своеобразным углом зрения, путая причину и следствие, цель и инструмент. Давай уже начинай раскладывать по полкам.
В классике, наследование реализации — не есть непременный атрибут ООП. Наследование — это лишь один из способов повторного использования кода в статически-типизируемых ОО-языках. Миксины можно рассматривать как альтернативу того же самого. Оба этих способа повышают эффективности разработки, предоставляя инструмент полуавтоматического повторного использования кода (когда подробностями повторного использования кода при сохранении типобезопасности занимается компилятор, а не мы ручкам, например в С++ компилятор генерирует thunk/переходник для вызова базового метода в случае множественного наследования).
Т.е. эти инструменты ни расширяют, ни еще как-то модифицируют ОО-парадигму, а являются лишь удобными и признанными практиками в её рамках, поддержанными на уровне языков.
Re[19]: Почему объектно-ориентированное программирование про
Здравствуйте, artelk, Вы писали:
A>Здравствуйте, vdimas, Вы писали:
V>>Давай-ка подробнее. Я предположил, что вместо одой ветки наследования можно использовать несколько. Противоречие принципу Лисков будет лишь тогда, когда нам, при работе с одним из корней сей иерархии (одним интерфейсом для C#), потребуется узнать наличие еще одной базы (реализации еще одного интерфейса) или даже конкретный используемый тип. Действительно, не делайте так. Если у нас есть коллекция интерфейсов, то при обходе сей коллекции обходитесь, пожалуйста, только этим статически типизированным интерфейсом. Вот и всё.
A>LSP — про единичное наследование
С чего ты взял?
Re[18]: Почему объектно-ориентированное программирование про
Здравствуйте, vdimas, Вы писали:
V>Здравствуйте, gandjustas, Вы писали:
V>>>Глупость. Миксин — это вынужденно используемый инструмент для удобства программирования в ограниченной разновидности ООП — компонентном программировании. Где же тут "в сторону"? Это на маленьком островке внутри ООП.
G>>ООП: инкапсуляция, полиморфизм, наследование реализации с интерфейсом. mixin_ы в эту формулу не вписываются, они расширяют ООП.
V>Смешались в кучу люди, кони.
V>У меня после прочтения тебя в этой ветке сложилось впечатление, что ты на всё смотришь под своеобразным углом зрения, путая причину и следствие, цель и инструмент. Давай уже начинай раскладывать по полкам.
V>В классике, наследование реализации — не есть непременный атрибут ООП.
А что тогда непременный атрибут ООП?
Я пользуюсь общепринятым определением ООП: инкапсуляция, наследование реализации (повторное использование), полиморфизм. Причем каждый из этих компонент есть и в других парадигмах (и даже лучше делается).
V>Наследование — это лишь один из способов повторного использования кода в статически-типизируемых ОО-языках. Миксины можно рассматривать как альтернативу того же самого.
Ну и насколько "альтернатива наследования" относится к ООП?
V>Т.е. эти инструменты ни расширяют, ни еще как-то модифицируют ОО-парадигму, а являются лишь удобными и признанными практиками в её рамках, поддержанными на уровне языков.
Ок, ссылку на авторитетный источник приведи.
Кстати почему в mainstream языках (которые имеют бирку ООП) нету mixin-ов?
Наверное потому что это очень признанные практики в ООП.
Твои слова не соответствуют реальности в основном.
Re[14]: Почему объектно-ориентированное программирование про
Здравствуйте, vdimas, Вы писали:
V>Здравствуйте, gandjustas, Вы писали:
V>>>Ну так в ООП объект и представляет из себя элемент модели. Класс — это уже термин из области типов, к понятию "объект" в общем случае ортогональный. G>>Ага, только в типизированных языках каждый объект имеет некоторый класс. Так что не ортогональный.
V>Каша.
Где именно?
V>Какая именно типизация имеется ввиду, статическая или динамическая?
Естественно статическая.
V>И при чем тут эта частность с типизацией, если полно не ОО-языков с обоими видами типизации и без типизации вообще, точно так же как полно ОО-языков опять же с обоим видами типизации и без типизации вообще. Классы могут быть поддержаны системой типов, а могут быть и нет. Класс — это "шаблон" объекта и одновременно type identity для целей типизации. Но если типизации нет, то и классы зачастую не нужны. И тогда мы наблюдаем "шаблоны" объектов в чистом виде, как в JavaScript. Фактически там нет классов, там есть "образцы" объектов.
Это кстати доказывает неортогональность "классов" (как бы они не выражались) и объектов.
Так что каша покачто у тебя.
G>>Наследование и агрегирование — разные вещи.
V>Двойка тебе, коллега. Иди учи уроки.
Датыче?
А ты как-нить можешь подтвердить свое мнение?
Даже гугл с тобой не согласен.
V>>>В общем, ты опять попутал причину и следствие. Миксины не самоцель, а инструмент, пригодный для обхода ограничений языка. G>>Для обхода ограничений ООП. Ну об этом я и говорю. V>Ничего-то ты не понимаешь.
Слив зощитан.
Re[20]: Почему объектно-ориентированное программирование про
Здравствуйте, gandjustas, Вы писали:
G>Здравствуйте, artelk, Вы писали:
A>>Здравствуйте, vdimas, Вы писали:
V>>>Давай-ка подробнее. Я предположил, что вместо одой ветки наследования можно использовать несколько. Противоречие принципу Лисков будет лишь тогда, когда нам, при работе с одним из корней сей иерархии (одним интерфейсом для C#), потребуется узнать наличие еще одной базы (реализации еще одного интерфейса) или даже конкретный используемый тип. Действительно, не делайте так. Если у нас есть коллекция интерфейсов, то при обходе сей коллекции обходитесь, пожалуйста, только этим статически типизированным интерфейсом. Вот и всё.
A>>LSP — про единичное наследование
G>С чего ты взял?
Принцип LSP описывает отношение между классом-наследником и одним базовым классом. Принцип сводится к тому, что класс-наследник должен не только наследовать реализацию, а также поддерживать явный и неявный интерфейс базового класса, чтобы все функции, принимающие по ссылке объекты базового класса, могли с тем же успехом принимать объекты класса-наследника.
P.S. Я не утверждаю, что принцип LSP имеет смысл только когда у класса только один базовый класс. Может выразился неудачно... При множественном наследовании нужно смотреть каждый конкретный базовый класс отдельно и выяснять удеовлетворяет ли наследование от него принципу LSP. Просто товарищ, на сколько я понял, утверждал что LSP — это про множественное наследование и про явное приведение типов от ссылки на одну базу к другой.
Re[7]: Почему объектно-ориентированное программирование пров
Здравствуйте, gandjustas, Вы писали:
V>>При чем тут "реального"? Ключевое слово — модель. Например, можно брать математические модели. G>Математическая модель — набор формул. Этот набор формул никак не связан с классами и объектами.
Ага, особенно если брать вектора/матрица и переопределять операции по ним в языке. Это уровень 0, где уже требуется создавать свои типы. А если брать системы ПИД из теории автоматического управления, то там набор формул управляет вполне ощутимо разнесенными "группами переменных", описывающих характеристики и состояния отдельных узлов ПИД.
G>Связь модели с классами только в голове разработчика.
Она там рождается, разумеется, и в плоском тексте мы лишь стараемся максимально приближенно к предметной области выразить, то, что родилось в голове. С переменным успехом, разумеется.
V>>Попробуй привести пример, который тут не раскатают по асфальту. G>Пример чего?
Пример программы — не модели.
G>>>Отношение is-a отлично достигается без наследования реализации. Интерфейсы (выше ты привел именно наследование интерфейсов), typeclasses в хаскеле, ducktyping в динамических языках. Это все позволяет выстраивать отношения is-a.
V>>Для ООП-скриптовых языков ducktyping работает на уровне отдельного метода, и лишь предоставляет способ реализации обмена сигналами для целей собственно работы ООП в этой динамике.
G>Какая-то слишком заумная фраза, смысл её мне остался непонятен.
G>Тут все понимают интефейс, как явно указанный набор методов\свойств, которые реализует объект.
Кроме тебя — никто. Да, используют просто сокращенное "интерфейс" когда идет обсуждение в рамках конкретного языка, но когда речь об ООП в целом — все прекрасно понимают о чем речь.
V>>Заметь, с т.з. клиентов таких интерфейсов, им глубоко до фени, абстрактный он или нет, это подробности уже самого интерфейса. G>Замечу что это неверно, особенно когда дело касается наследования.
Еще раз, клиентам объектов до фени. Или ты о том, что в некоторых платформах вызовы абстрактных методов и методов интерфейсов компилируются в разные инструкции? Ну дык, для того ЯВУ и нужны, чтобы мы от этих вещей абстрагировались.
V>>Абстрактные интерфейсы предназначены для случая надобности сокрытия полного АПИ реализующих классов, ведь термин "абстракция" означает выделение сути/основы. То, что в некоторых языках абстрактные интерфейсы используются порой для побочных целей, например для порождения нескольких параллельных иерархий is-a — лишь следствие отсутствия в этих языках множественного наследования. То бишь, инструмент абстрагирования применяется даже там, где размер задачи абстрагирования не требует. G>Ну это твои домыслы, которые не соответствуют практике.
К твоему сожалению не так. Это лишь узкий кругозор у кое кого, что даже нельзя посмотреть, что происходит в других языках.
V>>Рациональное зерно в наследовании абстрактных интерфейсов для построения объектной иерархии разумеется есть. И чем больше иерархия, тем больше в этом смысла. Мы избавляем такую иерархию от подробностей реализации составляющих её элементов, т.е. банально уменьшаем информационную сложность иерархии. Причем, учитывая связи м/у объектами (например, из-за использования общих или базовых реализаций), мы можем нарваться на рост числа зависимостей, близкий к квадратичному от кол-ва элементов иерархии. И вот смотрим на современные программы, где многие десятки сущностей, если не сотни... Понятное дело, что есть здравое желания снизить сложность архитектуры системы на порядок и даже чуть больше. G>Смотрю я .NET FW ине могу найти интерфейсов, более 3 уровней наследования. G>Видимо создатели библиотек в 200000 классов (кажись такое число) не разделяют твоего мнения.
Видимо, кто-то не в состоянии сообразить, что интерфейсов должно быть на порядки меньше, чем реализующих классов. Посему аппелировать к кол-ву классов как-то странно. И еще видимо, кто-то не понимает эквивалентность абстрактных классов и интерфейсов с т.з. архитектуры программы на дотнет, если не требуется множество интерфейсов в базе. Посмотри на дотнет теперь еще раз. И заодно оцени, какая доля публичных классов дотнета не идет корнем прямо или косвенно от интерфейсов или абстрактных классов. Эта доля ничтожно мала.
Ну и иерархии интерфейсов тоже есть, справедливости ради, хоть это было и необязательно для уровня библиотеки, которая должна вносить как можно меньше архитектурной сложности в конечное решение.
V>>Оно ничему не противоречит. Даже имея описанный вариант системы, иерархия которой расписана на абстрактных интерфейсах, ничто не мешает использовать наследование реализаций для конкретных используемых типов. G>Если прочитаешь внимательно, то тут многие говорят что наследование реализации без наследования интерфейсов вполне можно безопасно (то есть не не создавая проблем) использовать.
Естественно, и полно конкретных ситуаций, где это именно так.
G>Основная проблема в том что в большинстве языков наследование реализации автоматически наследует интерфейс.
Это проблема только в тех конкретных ситуациях, где это проблема. Понимаешь, вот так походя всё обобщая, ты превращаешь полезнейшие практики и наработки в средневековые предрассудки, которыми пытаешься пугать коллег.
V>>Вы в пылу спора всё время забываете, что вся эта абстрактность — вторична. G>Абстрактность ты придумал. Я использую интерфейс для отделения вещей друг от друга.
V>>Расшифруй, плиз, о каких достижениях речь, и куда именно попал твой оппонент? Сдается мне, тут уже наблюдается тихий спор с самим собой.
G>Чаще всего укушенные ООП любят говорить что только ООП позволяет полиморфизм и отношение is-a.
Таки я прав и это был неоконченный спор с самим собой. Возможно, что интересный и нам, только введи нас в курс дела.
Re[7]: Почему объектно-ориентированное программирование пров
Здравствуйте, AndrewVK, Вы писали:
SV.>>, а в бытовом смысле надо уточнять. Что будет контрактом в шарпе? AVK>Публичный интерфейс класса или интерфейс. В классе два контракта — публичный и для потомков.
Стало быть, вы имеете в виду protected-секцию класса, она же "контракт для потомков". ("Публичного контракта" может не быть, а значит, он не связан неразрывно с наследованием реализаций). Тогда я согласен с вашим утверждением, что в мейнстримовых ЯП такая связь неизбежна.
Давайте перейдем ко второму утверждению — что это проблема. Это может быть проблемой в частных случаях (каких, кстати?), но не в общем, коль скоро потомки активно заставляют предка отрабатывать контракт, а сами они запечатаны (и действие контракта прервано).
Re[15]: Почему объектно-ориентированное программирование про
V>>Какая именно типизация имеется ввиду, статическая или динамическая? G>Естественно статическая.
Неестественно, учитывая историю появления ООП.
V>>И при чем тут эта частность с типизацией, если полно не ОО-языков с обоими видами типизации и без типизации вообще, точно так же как полно ОО-языков опять же с обоим видами типизации и без типизации вообще. Классы могут быть поддержаны системой типов, а могут быть и нет. Класс — это "шаблон" объекта и одновременно type identity для целей типизации. Но если типизации нет, то и классы зачастую не нужны. И тогда мы наблюдаем "шаблоны" объектов в чистом виде, как в JavaScript. Фактически там нет классов, там есть "образцы" объектов. G>Это кстати доказывает неортогональность "классов" (как бы они не выражались) и объектов.
Ну ты так и не понял дуальность роли классов: служить прототипом и type identity. Когда "класс" нужен только как прототип, его называют шаблоном/образцом/прототипом. И реализуется это удобнее всего не в виде выделенной сущности-типа, а в виде экземпляра объекта — прототипа, создание других объектов по которому — суть клонирование прототипа. Ощути, насколько поменялась картинка, как только мы убираем типы в явном виде.
G>Так что каша покачто у тебя.
Перечитай пояснение, должно помочь.
G>А ты как-нить можешь подтвердить свое мнение? G>Даже гугл с тобой не согласен.
Гуглом тоже уметь надо пользоваться. Взгляни на работу компиляторов, что они делают, когда один тип наследует другого. И тогда станет понятно, что искать. Твое замечание в соседнем посте насчет автоматического наследования публичных интерфейсов в ООП при наследовании реализаций и отличия в этом от собственно агрегирования — верное. Но на этом и все, бо я и так сказал о "частном случае". Частность в этом моменте и заключается, что не просто агрегируется база, но автоматически ее публичный интерфейс становится и нашим публичным интерфейсом. Хотя, и это не всегда так. Например, в С++ есть protected/private наследование, что позволяет агрегировать базу, переопределять её виртуальные методы, тем не менее не наследуя её публичного интерфейса и не имея возможности извне привести ссылку на объект к его приватной базе.
V>>>>В общем, ты опять попутал причину и следствие. Миксины не самоцель, а инструмент, пригодный для обхода ограничений языка. G>>>Для обхода ограничений ООП. Ну об этом я и говорю. V>>Ничего-то ты не понимаешь. G> G>Слив зощитан.
Кем засчитан? Ограничения не в ООП как таковом, а в конкретных реализациях. И ты этого по-прежнему в упор не понимаешь.
Re[17]: Почему объектно-ориентированное программирование про
Здравствуйте, gandjustas, Вы писали:
G>>>Модель предметной области — тоже результат некоторой индивидуальной умственной деятельности и обладает теми же свойствами.
SV.>>Обладает, но в меньшей мере. G>Докажи. Вряд ли у тебя получится, потому что эта мера и зависит от конкретного человека.
Охренеть. Интересно, а какое доказательство вы вообще приняли бы?
gandjustas, доказать можно теорему, исходя из аксиом. См. тут: http://ru.wikipedia.org/wiki/%D0%94%D0%B5%D0%B4%D1%83%D0%BA%D1%82%D0%B8%D0%B2%D0%BD%D0%B0%D1%8F_%D1%81%D0%B8%D1%81%D1%82%D0%B5%D0%BC%D0%B0 Разработка софта — не дедуктивная система, и доказать нельзя ничего. Максимум, что мы ВМЕСТЕ можем сделать, это провести опрос и посмотреть, какой группе разработчиков удобнее с чьим кодом работать. Но для этого надо, чтобы для начала вы привели свой, отличный от моего, подход к проектирования API, в виде псевдокода, как у меня. Затем мы оформим голосование и получим... результаты голосования, а не доказательство. По-хорошему, следовало бы набрать две большие группы, чтобы в каждой были представлены все типы разработчиков, дать каждой достаточно сложный API и заставить писать, оценивая время и качество. Но такой эксперимент жизнь уже поставила. Сколько Windows-разработчиков пишет на голом WinAPI, а сколько — на MFC/Delphi/C++ Builder/WinForms etc. etc.?
SV.>>Знаете, как говорят — дураки спорят о крайностях, а умные — о мере? G>Знаю, но это к теме разговора не имеет отношения.
Re[19]: Почему объектно-ориентированное программирование про
A>Принцип LSP описывает отношение между классом-наследником и одним базовым классом.
Правильно, речь о гомоморфности каждой отдельно рассматриваемой иерархии. Вопрос в силе: с чего ты взял, что конечный объект должен участвовать лишь в одной иерархии?
Re[8]: Почему объектно-ориентированное программирование пров
Здравствуйте, vdimas, Вы писали:
V>Здравствуйте, gandjustas, Вы писали:
V>>>При чем тут "реального"? Ключевое слово — модель. Например, можно брать математические модели. G>>Математическая модель — набор формул. Этот набор формул никак не связан с классами и объектами.
V>Ага, особенно если брать вектора/матрица и переопределять операции по ним в языке. Это уровень 0, где уже требуется создавать свои типы.
Любые свои типы это классы ООП?
Я вот знаю много разных типов: кортежи, списки, варианты, записи.
К ООП имеют весьма отдаленное отношение, которое заключается только в том что эти типы худо-бедно можно выразить через классы. Но зачастую без поддержки языка работать с ними сложно.
V>А если брать системы ПИД из теории автоматического управления, то там набор формул управляет вполне ощутимо разнесенными "группами переменных", описывающих характеристики и состояния отдельных узлов ПИД.
Даже боюсь спрашивать что есть ПИД.
G>>Связь модели с классами только в голове разработчика.
V>Она там рождается, разумеется, и в плоском тексте мы лишь стараемся максимально приближенно к предметной области выразить, то, что родилось в голове. С переменным успехом, разумеется.
В результатах только один "абстрактный интерфейс", причем по ссылке не объяснено в чем отличие абстрактного от неабстрактного.
Поэтому давай пользоваться более устоявшейся терминологией.
G>>Тут все понимают интефейс, как явно указанный набор методов\свойств, которые реализует объект.
V>Кроме тебя — никто. Да, используют просто сокращенное "интерфейс" когда идет обсуждение в рамках конкретного языка, но когда речь об ООП в целом — все прекрасно понимают о чем речь.
Угу, все понимают и никто ниче не говорит. Твое сознание тебя подводит.
V>>>Заметь, с т.з. клиентов таких интерфейсов, им глубоко до фени, абстрактный он или нет, это подробности уже самого интерфейса. G>>Замечу что это неверно, особенно когда дело касается наследования.
V>Еще раз, клиентам объектов до фени. Или ты о том, что в некоторых платформах вызовы абстрактных методов и методов интерфейсов компилируются в разные инструкции? Ну дык, для того ЯВУ и нужны, чтобы мы от этих вещей абстрагировались.
Видимо я неправильно понял чем отличаются твои абстрактные интерфейсы от неабстрактных.
Может объяснишь?
V>>>Абстрактные интерфейсы предназначены для случая надобности сокрытия полного АПИ реализующих классов, ведь термин "абстракция" означает выделение сути/основы. То, что в некоторых языках абстрактные интерфейсы используются порой для побочных целей, например для порождения нескольких параллельных иерархий is-a — лишь следствие отсутствия в этих языках множественного наследования. То бишь, инструмент абстрагирования применяется даже там, где размер задачи абстрагирования не требует. G>>Ну это твои домыслы, которые не соответствуют практике. V>К твоему сожалению не так. Это лишь узкий кругозор у кое кого, что даже нельзя посмотреть, что происходит в других языках.
Ты хоть приводи подтверждения своим высказываниям.
А то твое понимание ООП, интерфейсов, наследования и других инструментов не соотвествует практике и даже той статье в википедии, на которую ты прислал ссылку.
Хотя может ты просто настолько заумно пытаешься все объяснить.
V>>>Рациональное зерно в наследовании абстрактных интерфейсов для построения объектной иерархии разумеется есть. И чем больше иерархия, тем больше в этом смысла. Мы избавляем такую иерархию от подробностей реализации составляющих её элементов, т.е. банально уменьшаем информационную сложность иерархии. Причем, учитывая связи м/у объектами (например, из-за использования общих или базовых реализаций), мы можем нарваться на рост числа зависимостей, близкий к квадратичному от кол-ва элементов иерархии. И вот смотрим на современные программы, где многие десятки сущностей, если не сотни... Понятное дело, что есть здравое желания снизить сложность архитектуры системы на порядок и даже чуть больше. G>>Смотрю я .NET FW ине могу найти интерфейсов, более 3 уровней наследования. G>>Видимо создатели библиотек в 200000 классов (кажись такое число) не разделяют твоего мнения.
V>Видимо, кто-то не в состоянии сообразить, что интерфейсов должно быть на порядки меньше, чем реализующих классов.
Так ты говорил не про количество, а про большую иерархию" или я тебя неправильно понял.
V>Посему аппелировать к кол-ву классов как-то странно.
Просто метрика объема библиотеки.
V>И еще видимо, кто-то не понимает эквивалентность абстрактных классов и интерфейсов с т.з. архитектуры программы на дотнет, если не требуется множество интерфейсов в базе. Посмотри на дотнет теперь еще раз. И заодно оцени, какая доля публичных классов дотнета не идет корнем прямо или косвенно от интерфейсов или абстрактных классов. Эта доля ничтожно мала.
Это ты что теперь доказать пытаешься?
Не уводи в сторону разговор. Ты сказал:
V>>>Рациональное зерно в наследовании абстрактных интерфейсов для построения объектной иерархии разумеется есть. И чем больше иерархия, тем больше в этом смысла.
Я же тебе говорю что в .NET нету больших иерархий абстрактных интерфейсов.
Хотя я понял, что я не понял твоего определения абстрактного интерфейса.
V>Ну и иерархии интерфейсов тоже есть, справедливости ради, хоть это было и необязательно для уровня библиотеки, которая должна вносить как можно меньше архитектурной сложности в конечное решение.
Есть, но довольно маленькие. Это противоречит тому что выделено выше.
G>>Основная проблема в том что в большинстве языков наследование реализации автоматически наследует интерфейс.
V>Это проблема только в тех конкретных ситуациях, где это проблема. Понимаешь, вот так походя всё обобщая, ты превращаешь полезнейшие практики и наработки в средневековые предрассудки, которыми пытаешься пугать коллег.
То что сегодня не проблема завтра может стать проблемой. Наследование — очень сильная связь между классами, её тяжело разрывать.
Я это показывал на примере с наследованием устройствам.
Здравствуйте, vdimas, Вы писали:
V>Здравствуйте, artelk, Вы писали:
A>>Принцип LSP описывает отношение между классом-наследником и одним базовым классом.
V>Правильно, речь о гомоморфности каждой отдельно рассматриваемой иерархии.
Ээ.. А причем тут гомоморфность?
V>Вопрос в силе: с чего ты взял, что конечный объект должен участвовать лишь в одной иерархии?
Это ко мне вопрос? Где я такое утверждал или имел ввиду?
Re[16]: Почему объектно-ориентированное программирование про
Здравствуйте, vdimas, Вы писали:
V>Здравствуйте, gandjustas, Вы писали:
V>>>Какая именно типизация имеется ввиду, статическая или динамическая? G>>Естественно статическая.
V>Неестественно, учитывая историю появления ООП.
Первый ООП язык — Simula. Вполне себе статически типизированный.
Первый массовый ООП язык — С++, тоже вполне статически типизированный.
V>>>И при чем тут эта частность с типизацией, если полно не ОО-языков с обоими видами типизации и без типизации вообще, точно так же как полно ОО-языков опять же с обоим видами типизации и без типизации вообще. Классы могут быть поддержаны системой типов, а могут быть и нет. Класс — это "шаблон" объекта и одновременно type identity для целей типизации. Но если типизации нет, то и классы зачастую не нужны. И тогда мы наблюдаем "шаблоны" объектов в чистом виде, как в JavaScript. Фактически там нет классов, там есть "образцы" объектов. G>>Это кстати доказывает неортогональность "классов" (как бы они не выражались) и объектов.
V>Ну ты так и не понял дуальность роли классов: служить прототипом и type identity. Когда "класс" нужен только как прототип, его называют шаблоном/образцом/прототипом. И реализуется это удобнее всего не в виде выделенной сущности-типа, а в виде экземпляра объекта — прототипа, создание других объектов по которому — суть клонирование прототипа. Ощути, насколько поменялась картинка, как только мы убираем типы в явном виде.
Да какая разница? ты сказал об ортогональности (то есть независимости) понятий, а теперь сам приводишь аргументы что они зависимы.
G>>А ты как-нить можешь подтвердить свое мнение? G>>Даже гугл с тобой не согласен.
V>Гуглом тоже уметь надо пользоваться.
Значит не можешь.
V>Взгляни на работу компиляторов, что они делают, когда один тип наследует другого. И тогда станет понятно, что искать.
Ну и что же такого делает компилятор C# что чтобы можно было утверждать что наследование и агрегирование — одно и тоже.
V>Твое замечание в соседнем посте насчет автоматического наследования публичных интерфейсов в ООП при наследовании реализаций и отличия в этом от собственно агрегирования — верное. Но на этом и все, бо я и так сказал о "частном случае". Частность в этом моменте и заключается, что не просто агрегируется база, но автоматически ее публичный интерфейс становится и нашим публичным интерфейсом.
Ну да, мелочи, всего-то контракт наследуется.
V>Хотя, и это не всегда так. Например, в С++ есть protected/private наследование, что позволяет агрегировать базу, переопределять её виртуальные методы, тем не менее не наследуя её публичного интерфейса и не имея возможности извне привести ссылку на объект к его приватной базе.
Непубличное наследование и есть разновидность mixin.
V>>>>>В общем, ты опять попутал причину и следствие. Миксины не самоцель, а инструмент, пригодный для обхода ограничений языка. G>>>>Для обхода ограничений ООП. Ну об этом я и говорю. V>>>Ничего-то ты не понимаешь. G>> G>>Слив зощитан.
V>Кем засчитан? Ограничения не в ООП как таковом, а в конкретных реализациях. И ты этого по-прежнему в упор не понимаешь.
Тогда давай по новой: что ты считаешь ООП? Приведи точное и непротиворечивое определение.
Я как-то по наивности пользуюсь общепринятым, которое ты можешь прочитать в ссылке, которую сам приводил.
Re[19]: Почему объектно-ориентированное программирование про
Здравствуйте, gandjustas, Вы писали:
V>>В классике, наследование реализации — не есть непременный атрибут ООП.
G>А что тогда непременный атрибут ООП? G>Я пользуюсь общепринятым определением ООП: инкапсуляция, наследование реализации (повторное использование), полиморфизм.
Это не определение ООП, это "три кита", на которых стоит современный ООП. Т.е. это практики, которые используются для достижения целей ООП. А вот из википедии, что есть ООП:
По мнению Алана Кея, создателя языка Smalltalk, которого считают одним из «отцов-основателей» ООП, объектно-ориентированный подход заключается в следующем наборе основных принципов (цитируется по вышеупомянутой книге Т. Бадда).
Всё является объектом. Вычисления осуществляются путём взаимодействия (обмена данными) между объектами, при котором один объект требует, чтобы другой объект выполнил некоторое действие. Объекты взаимодействуют, посылая и получая сообщения. Сообщение — это запрос на выполнение действия, дополненный набором аргументов, которые могут понадобиться при выполнении действия. Каждый объект имеет независимую память, которая состоит из других объектов.
G>Причем каждый из этих компонент есть и в других парадигмах (и даже лучше делается).
Правильно, многие практики shared м/у парадигмами.
V>>Наследование — это лишь один из способов повторного использования кода в статически-типизируемых ОО-языках. Миксины можно рассматривать как альтернативу того же самого.
G>Ну и насколько "альтернатива наследования" относится к ООП?
Думаю, теперь и ты и сам в состоянии решить.
V>>Т.е. эти инструменты ни расширяют, ни еще как-то модифицируют ОО-парадигму, а являются лишь удобными и признанными практиками в её рамках, поддержанными на уровне языков. G>Ок, ссылку на авторитетный источник приведи. G>Кстати почему в mainstream языках (которые имеют бирку ООП) нету mixin-ов? G>Наверное потому что это очень признанные практики в ООП.
Есть, просто это не так называется. Например в С++ виртуальное наследование — это и есть наследование в стиле ООП, когда обеспечивается транзитивность до одной корневой базы в случае сложных иерархий, а обычное множественное наследование в С++ — суть миксин, ибо каждая операция наследования целиком агрегирует базу. Сколько раз от базы отнаследуешься, столько раз будет выполнено агрегирование, т.е. столько экземпляров данных базы будет располагаться в памяти объекта. "Миксин" от одной базы предоставлен и в C#, скажите и на этом спасибо. Потому как в VB и этого не было, можно было наследовать интерфейсы, но нельзя было наследовать реализацию, надо было ручками делегирование описывать. В общем, одиночное наследование с агрегированием базы избавляет от того описанного эффекта с клонами этих баз для случая множественного наследования. Эти эффекты реально не всеми разработчиками понимаются и являются источниками ошибок. Поэтому оперирование миксинами в явном виде как бы более "честное", т.к. прямо указывается на количество экземпляров и способ композиции данных/функциональности.
G>Твои слова не соответствуют реальности в основном.
Это может быть верно с т.з. твоей реальности.
Re[18]: Почему объектно-ориентированное программирование про
Здравствуйте, SV., Вы писали:
SV.>Здравствуйте, gandjustas, Вы писали:
G>>>>Модель предметной области — тоже результат некоторой индивидуальной умственной деятельности и обладает теми же свойствами.
SV.>>>Обладает, но в меньшей мере. G>>Докажи. Вряд ли у тебя получится, потому что эта мера и зависит от конкретного человека.
SV.>Охренеть. Интересно, а какое доказательство вы вообще приняли бы?
SV.>gandjustas, доказать можно теорему, исходя из аксиом. См. тут: http://ru.wikipedia.org/wiki/%D0%94%D0%B5%D0%B4%D1%83%D0%BA%D1%82%D0%B8%D0%B2%D0%BD%D0%B0%D1%8F_%D1%81%D0%B8%D1%81%D1%82%D0%B5%D0%BC%D0%B0 Разработка софта — не дедуктивная система, и доказать нельзя ничего.
То есть будем считать что степень влияния конкретного дизайнера на конкретный дизайн одинакова, независимо от подхода к дизайну.
И твой аргумент про что "модель предметной области понятнее" отбросим как неорганизованный.
SV.>Максимум, что мы ВМЕСТЕ можем сделать, это провести опрос и посмотреть, какой группе разработчиков удобнее с чьим кодом работать. Но для этого надо, чтобы для начала вы привели свой, отличный от моего, подход к проектирования API, в виде псевдокода, как у меня. Затем мы оформим голосование и получим... результаты голосования, а не доказательство. По-хорошему, следовало бы набрать две большие группы, чтобы в каждой были представлены все типы разработчиков, дать каждой достаточно сложный API и заставить писать, оценивая время и качество.
У меня нет времени таким заниматься.
SV.>Но такой эксперимент жизнь уже поставила. Сколько Windows-разработчиков пишет на голом WinAPI, а сколько — на MFC/Delphi/C++ Builder/WinForms etc. etc.?
А это тут причем? Ты же говорил о моделях, соответствующих реальному миру. Я вот постоянно использую объектные модели, но они крайне редко соответствуют каким-то моделям реального мира (если эти модели специально не выдумывать постфактум).
Re[9]: Почему объектно-ориентированное программирование пров
Здравствуйте, gandjustas, Вы писали:
I>>Не совсем ясно, что ты понимаешь под объектами реального мира. "собака", "кошка" ?
I>>А куда деть явления, отношения ? Ну, например, "проект"
G>Да пожалуйста. В постановке задачи у меня есть "проект" и в интерфейсе много где есть "проект", а вот класса "проект" нету.
И что с того ?
Вот смотри, есть китобойное судно. Сколько китятины изловит кок, гальюнщик, боцман, матрос добычи, владелец судна, владелец флотилии ?
Китятина есть, а кто ж наловил её —
Вот так и с твоим "проектом". Если класса нет, то эти ничего не означает.
Re[8]: Почему объектно-ориентированное программирование пров
Здравствуйте, SV., Вы писали:
SV.>Давайте перейдем ко второму утверждению — что это проблема. Это может быть проблемой в частных случаях (каких, кстати?), но не в общем, коль скоро потомки активно заставляют предка отрабатывать контракт, а сами они запечатаны (и действие контракта прервано).
Это не есть теоретические измышления, это сугубо практические наблюдения — в 99% случаев наследование используется криво. Т.е. механизм приносит больше вреда, чем реальной пользы.
... << RSDN@Home 1.2.0 alpha 5 rev. 1495 on Windows 7 6.1.7600.0>>
Здравствуйте, vdimas, Вы писали:
V>Здравствуйте, gandjustas, Вы писали:
V>>>В классике, наследование реализации — не есть непременный атрибут ООП.
G>>А что тогда непременный атрибут ООП? G>>Я пользуюсь общепринятым определением ООП: инкапсуляция, наследование реализации (повторное использование), полиморфизм.
V>Это не определение ООП, это "три кита", на которых стоит современный ООП. Т.е. это практики, которые используются для достижения целей ООП. А вот из википедии, что есть ООП: V>
V>По мнению Алана Кея, создателя языка Smalltalk, которого считают одним из «отцов-основателей» ООП, объектно-ориентированный подход заключается в следующем наборе основных принципов (цитируется по вышеупомянутой книге Т. Бадда).
V>Всё является объектом. Вычисления осуществляются путём взаимодействия (обмена данными) между объектами, при котором один объект требует, чтобы другой объект выполнил некоторое действие. Объекты взаимодействуют, посылая и получая сообщения. Сообщение — это запрос на выполнение действия, дополненный набором аргументов, которые могут понадобиться при выполнении действия. Каждый объект имеет независимую память, которая состоит из других объектов.
Ок, как сюда относится mixin? Судя по всему вообще никак. Да и наследование тоже.
С точки зрения кея самый правильный ООП — это Эрланг. Но Кей идеалист в данном вопрос, а smalltalk очень мощный язык, гораздо мощнее, чем многие другие языки, которые носят бирку ООП.
V>>>Т.е. эти инструменты ни расширяют, ни еще как-то модифицируют ОО-парадигму, а являются лишь удобными и признанными практиками в её рамках, поддержанными на уровне языков. G>>Ок, ссылку на авторитетный источник приведи. G>>Кстати почему в mainstream языках (которые имеют бирку ООП) нету mixin-ов? G>>Наверное потому что это очень признанные практики в ООП.
V>Есть, просто это не так называется.
Ну и как оно называется? Сразу со ссылкой.
V>Например в С++ виртуальное наследование — это и есть наследование в стиле ООП, когда обеспечивается транзитивность до одной корневой базы в случае сложных иерархий, а обычное множественное наследование в С++ — суть миксин, ибо каждая операция наследования целиком агрегирует базу. Сколько раз от базы отнаследуешься, столько раз будет выполнено агрегирование, т.е. столько экземпляров данных базы будет располагаться в памяти объекта. "Миксин" от одной базы предоставлен и в C#, скажите и на этом спасибо. Потому как в VB и этого не было, можно было наследовать интерфейсы, но нельзя было наследовать реализацию, надо было ручками делегирование описывать. В общем, одиночное наследование с агрегированием базы избавляет от того описанного эффекта с клонами этих баз для случая множественного наследования. Эти эффекты реально не всеми разработчиками понимаются и являются источниками ошибок. Поэтому оперирование миксинами в явном виде как бы более "честное", т.к. прямо указывается на количество экземпляров и способ композиции данных/функциональности.
У тебя каша в терминах. Приведи в порядок их тогда продолжим.
Re[10]: Почему объектно-ориентированное программирование про
Здравствуйте, Ikemefula, Вы писали:
I>Здравствуйте, gandjustas, Вы писали:
I>>>Не совсем ясно, что ты понимаешь под объектами реального мира. "собака", "кошка" ?
I>>>А куда деть явления, отношения ? Ну, например, "проект"
G>>Да пожалуйста. В постановке задачи у меня есть "проект" и в интерфейсе много где есть "проект", а вот класса "проект" нету.
I>И что с того ?
I>Вот смотри, есть китобойное судно. Сколько китятины изловит кок, гальюнщик, боцман, матрос добычи, владелец судна, владелец флотилии ?
I>Китятина есть, а кто ж наловил её —
I>Вот так и с твоим "проектом". Если класса нет, то эти ничего не означает.
А о чем разговор вообще?
Изначально высказывалась мысль что есть некоторые отношения между объектами реального мира и необходимо их в таком виде перенести на иерархии классов в программе. Я же сказал что такой подход к проектированию оправдан в крайне малом проценте приложений.
Меня попросили привести пример программы, в которой нету модели реального мира в виде иерархии классов.
Я привел.
Re[11]: Почему объектно-ориентированное программирование про
Здравствуйте, gandjustas, Вы писали:
G>Изначально высказывалась мысль что есть некоторые отношения между объектами реального мира и необходимо их в таком виде перенести на иерархии классов в программе. Я же сказал что такой подход к проектированию оправдан в крайне малом проценте приложений. G>Меня попросили привести пример программы, в которой нету модели реального мира в виде иерархии классов. G>Я привел.
Хорошо, давай сначала. Сколько китятины добывает кок на китобое ?
Re[21]: Почему объектно-ориентированное программирование про
Здравствуйте, gandjustas, Вы писали:
G>У тебя каша в терминах. Приведи в порядок их тогда продолжим.
Каша в терминах существует сама по себе. Одним и тем же термином в разных языках называются разные вещи. Поэтому попытайся сосредоточиться на сути происходящего, бо в терминологическом споре мы далеко не уйдем. Мы уже уперлись, лишь только задавшись вопросом, что есть ООП.
Re[17]: Почему объектно-ориентированное программирование про
G>Непубличное наследование и есть разновидность mixin.
Собсно, для демонстрации этого пример и приводил.
V>>Кем засчитан? Ограничения не в ООП как таковом, а в конкретных реализациях. И ты этого по-прежнему в упор не понимаешь. G>Тогда давай по новой: что ты считаешь ООП? Приведи точное и непротиворечивое определение. G>Я как-то по наивности пользуюсь общепринятым, которое ты можешь прочитать в ссылке, которую сам приводил.
Далее в википедии идет про классы, но мы же знаем про языки, в которых декларируется поддержка ООП, но классы не являются тем же, чем они являются в приведенных тобой симуле и С++, а являются прототипами для клонирования экземпляров. Поэтому понятие "классов" я склонен относить к подробностям системы типов конкретного языка, а не ООП как такового. Класс в мейнстриме это не только шаблон реализации типа, но и описание контракта типа. А последнее встречается даже в классах типов в Хаскель, хоть там ООП и не пахнет, т.е. из термина остается голый контракт, наподобие интерфейсов Java/.Net.
С терминологией вообще беда, если по справедливости, т.к. практически всегда требуется уточнение в рамках какого языка термин используется.
Re[17]: Почему объектно-ориентированное программирование про
Здравствуйте, gandjustas, Вы писали:
V>>Взгляни на работу компиляторов, что они делают, когда один тип наследует другого. И тогда станет понятно, что искать. G>Ну и что же такого делает компилятор C# что чтобы можно было утверждать что наследование и агрегирование — одно и тоже.
Сорри, пропустил интересный вопрос.
Для C# это делает не компилятор, а среда исполнения. Она располагает данные базового типа в памяти наследника. Для случая С++ это делает непосредственно компилятор. В случае множественного наследования компилятор располагает данные всех баз в памяти наследника в порядке, указанном при перечислении баз типа в его объявлении. При вызове методов наследника управление не передается непосредственно методам базы, оно передается через делегирующий код, в котором происходит смещение адреса this на область памяти, в которой хранятся агрегированные данные конкретной базы (и указатель на её vtable в т.ч.), и уже потом вызывается целевой код. Учитывая склонности С++ к оптимизации, зачастую этот thunk не живет в виде выделенного бинарного кода, а сразу происходит смещение адреса this на агрегированные данные базы для корректного вызова базового метода прямо в том месте, где происходит вызов. Но это лишь детали, а суть такова, что есть делегирующая функциональность, которую компилятор генерит автоматически.
Re[22]: Почему объектно-ориентированное программирование про
Здравствуйте, vdimas, Вы писали:
V>Здравствуйте, gandjustas, Вы писали:
G>>У тебя каша в терминах. Приведи в порядок их тогда продолжим.
V>Каша в терминах существует сама по себе. Одним и тем же термином в разных языках называются разные вещи. Поэтому попытайся сосредоточиться на сути происходящего, бо в терминологическом споре мы далеко не уйдем. Мы уже уперлись, лишь только задавшись вопросом, что есть ООП.
Чтобы сосредоточиться на сути надо понимать о какой сути мы говорим. Разговор был о проектировании, а ты как-то внезапно съехал на внутренности компилятора, подменяя суть терминов.
Re[9]: Почему объектно-ориентированное программирование пров
Здравствуйте, gandjustas, Вы писали:
G>Любые свои типы это классы ООП? G>Я вот знаю много разных типов: кортежи, списки, варианты, записи.
Там вопрос был "оно модель?", а не "оно ООП?"
G>Даже боюсь спрашивать что есть ПИД.
Неужели в гугле нашел?
V>>Она там рождается, разумеется, и в плоском тексте мы лишь стараемся максимально приближенно к предметной области выразить, то, что родилось в голове. С переменным успехом, разумеется.
G>А зачем вы стараетесь так делать? Какой положительный эффект для кода от этого образуется, желательно метриками.
А чтобы не оперировать понятиями, взятыми от балды.
V>>Пример программы — не модели. G>Я уже приводил, читай тему.
Сорри, не могу себе такое позволить, если не трудно кинь ссылку.
V>> Взаимодействие объектов происходит посредством сообщений.
G>И?
А остальное — подробности реализации.
G>>>Тут все понимают интефейс, как явно указанный набор методов\свойств, которые реализует объект.
V>>Еще раз, клиентам объектов до фени. Или ты о том, что в некоторых платформах вызовы абстрактных методов и методов интерфейсов компилируются в разные инструкции? Ну дык, для того ЯВУ и нужны, чтобы мы от этих вещей абстрагировались.
G>Видимо я неправильно понял чем отличаются твои абстрактные интерфейсы от неабстрактных. G>Может объяснишь?
Вопрос терминологии конкретного языка.
class C {
public void M1() {}
public void M2() {}
}
Публичный интерфейс класса С составляют методы М1, М2. Коль эти методы содержат реализацию, интерфейс не абстрактный. Знаешь, наверно полезней погуглить по фразе "полностью абстрактный интерфейс". Просто, если такое, значит бывает и "неполностью абстрактный".
G>
V>>>>Рациональное зерно в наследовании абстрактных интерфейсов для построения объектной иерархии разумеется есть. И чем больше иерархия, тем больше в этом смысла.
G>Я же тебе говорю что в .NET нету больших иерархий абстрактных интерфейсов.
Там нет больших иерархий, наверно. Или же там, где в Java выводится иерархия на чистых джавовских интерфейсах, в дотнете применены абстрактные классы. Подозреваю, что из соображений производительности. Тем не менее, хороший пример однофигственности. Как и тут.
Можно заметить, что интерфейс, с точки зрения реализации — это просто чистый абстрактный класс, то есть класс, в котором не определено ничего, кроме абстрактных методов. Если язык программирования поддерживает множественное наследование и абстрактные методы (как, например, C++), то необходимости во введении в синтаксис языка, отдельного понятия «интерфейс» не возникает. Данные сущности описываются с помощью абстрактных классов и наследуются классами для реализации абстрактных методов.
G>Хотя я понял, что я не понял твоего определения абстрактного интерфейса.
V>>Это проблема только в тех конкретных ситуациях, где это проблема. Понимаешь, вот так походя всё обобщая, ты превращаешь полезнейшие практики и наработки в средневековые предрассудки, которыми пытаешься пугать коллег.
G>То что сегодня не проблема завтра может стать проблемой. Наследование — очень сильная связь между классами, её тяжело разрывать.
Ну так, если связь эта не столь сильна, что ее придется разрывать, нафига там наследование? Заканчивай сам с собой спорить.
V>>>>Вы в пылу спора всё время забываете, что вся эта абстрактность — вторична. G>>>Абстрактность ты придумал. Я использую интерфейс для отделения вещей друг от друга.
V>>И сие не есть абстрагирование? http://ru.wikipedia.org/wiki/%D0%90%D0%B1%D1%81%D1%82%D1%80%D0%B0%D0%BA%D1%86%D0%B8%D1%8F
G>Третья ссылка ни о чем. Приведи что ли конкретный фрагмент, в котором будет написано что "разделение" является "абстракцией".
Твое выделил. А вот по ссылке "ни о чем":
Абстрагирование — это мысленное выделение, вычленение некоторых элементов конкретного множества и отвлечение их от прочих элементов данного множества. Это один из основных процессов умственной деятельности человека,
Добавлю от себя, что процесс абстрагирования — это процесс связанный с допущениями/упрощениями, угу, для выделения сути. Поэтому понятие" абстрактного класса" для меня прочно ассоциируется с "упрощенным классом", в интерфейсе которого описана лишь суть порождаемой им иерархии.
Re[23]: Почему объектно-ориентированное программирование про
Здравствуйте, artelk, Вы писали:
A>Ээ.. А причем тут гомоморфность?
Иерархии, следующие LSP автоматически выходят гомоморфными.
V>>Вопрос в силе: с чего ты взял, что конечный объект должен участвовать лишь в одной иерархии? A>Это ко мне вопрос? Где я такое утверждал или имел ввиду?
Парой постов выше.
Re[13]: Почему объектно-ориентированное программирование про
Здравствуйте, gandjustas, Вы писали:
V>>Ну так в ООП объект и представляет из себя элемент модели. Класс — это уже термин из области типов, к понятию "объект" в общем случае ортогональный. G>Ага, только в типизированных языках каждый объект имеет некоторый класс. Так что не ортогональный.
При структурной типизации как-раз ортогональный.
Например в OCaml классы по сути синтаксический сахар, можно легко обойтись без них.
Re[3]: Почему объектно-ориентированное программирование пров
Здравствуйте, vdimas, Вы писали:
V>Здравствуйте, samius, Вы писали:
S>>разве в других парадигмах рефакторинг исключен? Я вообще думаю что рефакторинг это следствие отношения к предварительному проектированию и собственно самому коду.
V>Нужен меньше. По опыту плюсов, чем меньше создаешь классов, т.е. чем больше функциональности удается разнести в свободные ф-ии, тем меньше надобность рефакторинга.
Согласен что меньше
V>ИМХО, это объяснимо, т.к. объект в ООП — это группировка в "одно целое" относительно большого кол-ва элементов программы.
Согласен лишь с тем что при группировке относительно большого кол-ва элементов необходимость рефакторинга возрастает. Но кто заставляет группировать много элементов?
V>И весь рефакторинг, по-сути, это перетасовка элементов таких групп. Пройдись по формальным методам рефакторинга: 90% рефакторинга — это способы перемещения методов и полей м/у объектами таким образом, чтобы не поломать случайно исходное поведение программы.
Все же здесь проблеммы не в самом ООП, а в отсутствии четких критериев группировки полей и методов.
V>Согласись, набор свободных ф-ий подобного практически не требует. Ну, максимум их идентификаторы порой надо причесать, но сие несущественно.
Согласен. Но все же ООП не запрещает свободные функции. В рамках ООП их можно рассматривать их как объект с одним методом. Т.е. если мы возьмем ФП программу и свободные функции преобразуем в объекты, необходимости к рефакторингу не прибавится.
Проблема ООП в отношении рефакторинга лишь в том, что существует тенденция лепить все в существующие уже классы дабы "не плодить сущности".
Все ИМХО, без претензий на абсолютную истину.
S>>Возможно стоит сменить название на следущее: Что считают гуру причиной провала ООП?
V>Никто еще не доказал, что ООП провалилось. Оно провалилось лишь как "серебряная пуля" — ИМХО, это проблемы тех, кто считает, что серебряные пули существуют.
+1, не совсем корректно выразился.
Re[9]: Почему объектно-ориентированное программирование пров
Здравствуйте, AndrewVK, Вы писали:
AVK>Здравствуйте, SV., Вы писали:
SV.>>Давайте перейдем ко второму утверждению — что это проблема. Это может быть проблемой в частных случаях (каких, кстати?), но не в общем, коль скоро потомки активно заставляют предка отрабатывать контракт, а сами они запечатаны (и действие контракта прервано).
AVK>Это не есть теоретические измышления, это сугубо практические наблюдения — в 99% случаев наследование используется криво. Т.е. механизм приносит больше вреда, чем реальной пользы.
С количеством (99%) не согласен, соглашусь лишь с "достаточно часто". Достаточно, для того, чтобы кривое использование наследования надо было признать как явление. И это возвращает нас к моему самому первому утверждению про нездоровые следствия overhype (http://rsdn.ru/forum/philosophy/4155690.1.aspx
С итоговым утверждением "механизм приносит больше вреда, чем реальной пользы" не согласен тоже, но не потому, что механизм приносит больше пользы, чем вреда, а потому, что это утверждение не имеет смысла. Надо не мерить суммарный вред и пользу, а применять строго по делу. Чтобы не разводить пустословие, предлагаю вернуться к моему примеру с приборами. У ganjustas'а, как оказалось, "нет времени" приводить пример API без наследования реализаций, а я бы с удовольствием обсудил.
Re[10]: Почему объектно-ориентированное программирование про
Здравствуйте, vdimas, Вы писали:
V>Здравствуйте, gandjustas, Вы писали:
G>>Любые свои типы это классы ООП? G>>Я вот знаю много разных типов: кортежи, списки, варианты, записи.
V>Там вопрос был "оно модель?", а не "оно ООП?"
Модель это или нет зависит от того кто проектирует.
G>>Даже боюсь спрашивать что есть ПИД. V>Неужели в гугле нашел?
Не искал.
V>>>Она там рождается, разумеется, и в плоском тексте мы лишь стараемся максимально приближенно к предметной области выразить, то, что родилось в голове. С переменным успехом, разумеется.
G>>А зачем вы стараетесь так делать? Какой положительный эффект для кода от этого образуется, желательно метриками. V>А чтобы не оперировать понятиями, взятыми от балды.
Никакие понятия от балды не берутся в любом случае.
V>>>Пример программы — не модели. G>>Я уже приводил, читай тему. V>Сорри, не могу себе такое позволить, если не трудно кинь ссылку.
Лень искать. Тебе надо — ты ищи.
G>>>>Тут все понимают интефейс, как явно указанный набор методов\свойств, которые реализует объект.
V>>>Еще раз, клиентам объектов до фени. Или ты о том, что в некоторых платформах вызовы абстрактных методов и методов интерфейсов компилируются в разные инструкции? Ну дык, для того ЯВУ и нужны, чтобы мы от этих вещей абстрагировались.
G>>Видимо я неправильно понял чем отличаются твои абстрактные интерфейсы от неабстрактных. G>>Может объяснишь?
V>Вопрос терминологии конкретного языка. V>
V>class C {
V> public void M1() {}
V> public void M2() {}
V>}
V>
V>Публичный интерфейс класса С составляют методы М1, М2. Коль эти методы содержат реализацию, интерфейс не абстрактный. Знаешь, наверно полезней погуглить по фразе "полностью абстрактный интерфейс". Просто, если такое, значит бывает и "неполностью абстрактный".
Гугл вообще не дает точного совпадения по фразе "полностью абстрактный интерфейс". Приведи в порядок терминологию, потом продолжим разговор.
G>>
V>>>>>Рациональное зерно в наследовании абстрактных интерфейсов для построения объектной иерархии разумеется есть. И чем больше иерархия, тем больше в этом смысла.
G>>Я же тебе говорю что в .NET нету больших иерархий абстрактных интерфейсов.
V>Там нет больших иерархий, наверно.
То есть то что ты писал практикой не подтверждается.
G>>То что сегодня не проблема завтра может стать проблемой. Наследование — очень сильная связь между классами, её тяжело разрывать. V>Ну так, если связь эта не столь сильна, что ее придется разрывать, нафига там наследование? Заканчивай сам с собой спорить.
Затем что заранее ты не сможешь сказать придется связь разрывть или нет. Зато есть стремление создавать большие иерархии.
Суть проблемы понимаешь?
V>>>>>Вы в пылу спора всё время забываете, что вся эта абстрактность — вторична. G>>>>Абстрактность ты придумал. Я использую интерфейс для отделения вещей друг от друга.
V>>>И сие не есть абстрагирование? http://ru.wikipedia.org/wiki/%D0%90%D0%B1%D1%81%D1%82%D1%80%D0%B0%D0%BA%D1%86%D0%B8%D1%8F
G>>Третья ссылка ни о чем. Приведи что ли конкретный фрагмент, в котором будет написано что "разделение" является "абстракцией".
V>Твое выделил. А вот по ссылке "ни о чем": V>
V>Абстрагирование — это мысленное выделение, вычленение некоторых элементов конкретного множества и отвлечение их от прочих элементов данного множества. Это один из основных процессов умственной деятельности человека,
Я не про "мысленное явление" писал.
V>Добавлю от себя, что процесс абстрагирования — это процесс связанный с допущениями/упрощениями, угу, для выделения сути. Поэтому понятие" абстрактного класса" для меня прочно ассоциируется с "упрощенным классом", в интерфейсе которого описана лишь суть порождаемой им иерархии.
Очередная черезчур заумная фраза.
Re[11]: Почему объектно-ориентированное программирование про
Здравствуйте, vdimas, Вы писали:
V>Здравствуйте, samius, Вы писали:
S>>Согласен лишь с тем что при группировке относительно большого кол-ва элементов необходимость рефакторинга возрастает. Но кто заставляет группировать много элементов?
V>А ты сторонник объектов с одним полем и одним методом? Если нет, то сказанное в силе.
Нет, не сторонник. Но SRP уважаю и начинаю нервничать когда число полей у объекта, который по сути не является property-bag-ом, начинает увеличиваться.
S>>Все же здесь проблеммы не в самом ООП, а в отсутствии четких критериев группировки полей и методов.
V>Не может быть никаких четких критериев.
Позывы к рефакторингку сформулированы более-менее четко. Но что-то заставляет писать сначала как шарахнет, а потом рефакторить, даже если требования не менялись.
S>>Согласен. Но все же ООП не запрещает свободные функции. В рамках ООП их можно рассматривать их как объект с одним методом. Т.е. если мы возьмем ФП программу и свободные функции преобразуем в объекты, необходимости к рефакторингу не прибавится.
V>В какие объекты? Функциональные? Я их тоже за ф-ии считаю.
V>А по существу... V>... Что мы делаем в ответ на разбухание кода? Мы вводим новые "слои" в наш ООП, выделяем "хелперы" и целые "независимые подсистемы" и так до бесконечности. Вот что имелось ввиду, когда утверждалось, что ООП обречен на постоянный рефакторинг, то бишь на постоянное переписывание кода.
Неа, новые слои и хелперы могут быть реакцией на уточнение требований. А имелось ввиду следующее:
Я уверен, что ООП методологически неверна. Она начинает с построения классов. Это как если бы математики начинали бы с аксиом. Но реально никто не начинает с аксиом, все начинают с доказательств. Только когда найден набор подходящих доказательств, лишь тогда на этой основе выводится аксиома. Т.е. в математике вы заканчиваете аксиомой. Тоже самое и с программированием: сначала вы должны начинать развивать алгоритмы, и только в конце этой работы приходите к тому, что вы в состоянии сформулировать четкие и непротиворечивые интерфейсы. Именно из-за этой неразберихи в ООП так популярен рефакторинг — из-за ущербности парадигмы вы просто обречены на переписывание программы, уже в тот самый момент, когда только задумали её спроектировать в ООП-стиле.
т.е. даже без изменений требований, формулировка непротиворечивых интерфейсов в начале написания программы проблематична. Чем в этом плане лучше ФП при проектировании сверху — для меня не очевидно.
V>фП думает от данных и потоков их обработки. Им всю программу приходится писать в терминах "хелперов" и "подсистем" с самого начала. Плюс продумывать тщательно, как "протаскиваются" эти данные и прочий контекст в процессе вычисления. Вот и выходит, что по мере роста функционала им ничего переписывать не приходится, всё уже переписано с самого начала и заведомо декомпозировано до уровня плинтуса. В отличие от "черных ящиков" ООП.
Получается что ООП — это сверху вниз, а ФП — снизу вверх?
ИМХО, ООП не мешает продумывать тщательно как "протаскиваются" данные. Или можно сказать что мешает не ООП, а проектирование сверху в какой-то мере, или даже не проектирование а реализация сверху. Именно она обеспечивает нас неизбежным рефакторингом.
V>Справедливости ради, в ООП тоже сей подход можно использовать. Т.е. брать у ФП не только модную здесь иммутабельность и замыкания (порой до экстаза), но саму программу плясать от данных и небольших объектов, представляющих эти данные с одной стороны, и осуществляющие обработку этих данных с другой стороны.
О!
V>Заметь, это отход от парадигмы общепринятой парадигмы ООП, хотя используются ООП ср-ва.
С некоторых пор я отделяю общепринятую парадигму ООП от взглядов Кея "Всё является объектом...". Мне даже кажется что на чисто ФП программу можно смотреть через призму "Все является объектом... Объекты взаимодействуют, посылая и получая сообщения", в то время как общепринятое ООП ожидает от программы доминирования трех китов в традиционном ООП понимании.
V>Итоговый дизайн должен представлять из себя большое кол-во легковесных объектов минимальнейшей функциональности, которые не потребует рефакторинга ни при каких обстоятельствах. ИМХО, такой стиль — дело привычки. Типичная "лакмусовая бумажка" для ситуации, когда такой стиль не только стоит применять из сображений "хорошего тона", но когда только он и спасает проект — это если подмечаешь объекты, в которых относительно мало полей, но очень много методов. Применять ООП-декомпозицию тут бессмысленно, ибо в таких случаях обычно невозможно декомпозировать состояние. Поэтому поступаешь просто — объект превращаешь в "контекст". Остальное разбивается либо на маленькие объекты, которые используются как временные "стековые" при вычислении (value-type в дотнете просто рулез для такого), а что не требует промежуточного состояния при вычислении — вовсе разносишь на свободные ф-ии.
Да, т.е. двумя словами — рефакторинг в ООП может быть сведен к минимуму при некоторых правильных привычках. И обилие рефакторинга в ООП не может быть предъявлено как причина его провала в качестве серебрянной пули. Это я и имел ввиду изначально.
S>>Проблема ООП в отношении рефакторинга лишь в том, что существует тенденция лепить все в существующие уже классы дабы "не плодить сущности".
V>Ну дык правильно. Ведь эти классы обычно отражают первоначальное видение дизайна, т.е. не случайны. И в этих классах могут находится нужные нам данные, поэтому мы и пихаем функциональность в них, дабы не нарушать нашу любимую "инкапсуляцию".
Меняется видение — нужно менять класс, а не пихать в него пока он не лопнет. Менять проще пока класс и его ответственность обозримы.
V>А ее по мере роста программы нарушать все-равно придется. Правда, не факт, что при этом пострадает надежность, ведь по-прежнему можно обеспечить безопасный набор любых операций, просто этот набор после декомпозиции будет более "мелкогранулирован".
Правильное слово какое. По поводу размеров грануляции соображения следующие: крупная грануляция тяготеет к рефакторингу, а мелкая — к усложнению композиции на верхнем уровне. И это вне парадигм. Решение может быть в ведении дополнительных уровней/этажей абстракции.
S>>Все ИМХО, без претензий на абсолютную истину.
V>Окстись, мы тут максимум личными наблюдениями делиться можем, а они субъективны априори.
Просто эти 4 буквы отпугивают любителей разоблачать, понижают температуру дебатов и дают понять что я не настроен воинственно. В общем, на всякий случай
Re[24]: Почему объектно-ориентированное программирование про
Здравствуйте, vdimas, Вы писали:
V>Здравствуйте, artelk, Вы писали:
A>>Ээ.. А причем тут гомоморфность?
V>Иерархии, следующие LSP автоматически выходят гомоморфными.
Впечатление, что, либо у тебя каша в голове, либо ты чего-то не договариваешь. Я, конечно, телепат, но тут случай слишком сложный — даже для меня . Говоря о гомоморфности, ты как-то намекаешь на множественную диспечеризацию?
Допустим, создаю я некий класс и реализую в нем некий интерфейс (например, IEnumerable<T>). Начинай доказывать, что я не должен добавлять в него ни одного вируального метода, чтобы это не противоречило LSP...
V>>>Вопрос в силе: с чего ты взял, что конечный объект должен участвовать лишь в одной иерархии? A>>Это ко мне вопрос? Где я такое утверждал или имел ввиду?
V>Парой постов выше.
Ок, допустим мы имеем некий (с) Очень Объектно Ориентированный язык программирования. Все есть объекты, включая классы. Фунции — тоже первокласные сущности. Классы представляют собой фабрики объектов на основе прототипов или как-то еще. Более того, класс объекту можно назначить динамически — просто скопировать в него соответствующие поля и методы. Таким образом, типом объекта будет просто набор сингатур методов, которые у него можно вызвать, плюс некая семантика, стоящая за ними и их объединяющая. Можно создать некий безликий Object, а потом последовательно назначить ему несколько классов. Если у этих классов есть совпадающие по сигнатуре методы, то они переопределяются в зависимости от порядка назначения этих классов объекту. Ты подобную ситуацию имел ввиду, говоря об участии объекта в нескольких иерархиях?
Re[2]: Почему объектно-ориентированное программирование пров
VE>"Ну и где мы теперь, с этой вашей красивой теорией относительности, кто-нибудь может мне назвать хоть какие-то реально-практические результаты её применения в вашей обыденной жизни после целого века её ковыряния и массового насаждения?"- как всегда язвительно вопрошает Гэбриел.
VE>Гэбриел не в курсе про существование GPS что ли?
Но существует одно качество, которое нельзя купить, — это надежность. Цена надежности — погоня за крайней простотой. Это цена, которую очень богатому труднее всего заплатить.
Хоар
Re[25]: Почему объектно-ориентированное программирование про
Здравствуйте, artelk, Вы писали:
V>>Иерархии, следующие LSP автоматически выходят гомоморфными.
A>Говоря о гомоморфности, ты как-то намекаешь на множественную диспечеризацию?
Какая связь?
A>Допустим, создаю я некий класс и реализую в нем некий интерфейс (например, IEnumerable<T>). Начинай доказывать, что я не должен добавлять в него ни одного вируального метода, чтобы это не противоречило LSP...
По справедливости, никто никому ничего не должен.
Строго говоря, данный критерий можно выполнить и без гомоморфизма. Если производный класс содержит дополнительные открытые функции, их можно просто не вызывать из клиента базового класса. Постойте-ка… а зачем добавлять открытые функции, если их не использовать? Если в одном производном классе были добавлены одни скрытые функции, а в другом — другие, со временем в вашей программе наверняка отыщется точка, в которой их нельзя свободно поменять местами.
Настоящая опасность заключается втом, чо без выполнения этого критерия клиентам придется думать о производных классах, а не только о базовом классе, который они знают и любят. Если бы в Dad присутствовали дополнительные открытые члены, клиента Grandpa со временем мог бы спросить свой объект: «Долой притворство — что ты представляешь собой в действительности?» В итоге было бы нарушено столько принципов модульного строения и инкапсуляции, что об этом можно было бы написать целую книгу.
Самый простой способ обеспечить взаимозаменяемость — воспользоваться гомоморфизмом. По крайней мере, для интерфейсов гомоморфизм обеспечивает взаимозаменяемость по определению, поскольку клиентам Grandpa не придется беспокоиться о существовании других функций, с которыми им положено работать.
И в реальной разработке я видел многократно, когда IEnumerable<T> приводят к List<T>, T[] или к некоему своему уникальному типу. Только LSP тут уже не при чем.
A>Ок, допустим мы имеем некий (с) Очень Объектно Ориентированный язык программирования. Все есть объекты, включая классы. Фунции — тоже первокласные сущности. Классы представляют собой фабрики объектов на основе прототипов или как-то еще. Более того, класс объекту можно назначить динамически — просто скопировать в него соответствующие поля и методы. Таким образом, типом объекта будет просто набор сингатур методов, которые у него можно вызвать, плюс некая семантика, стоящая за ними и их объединяющая. Можно создать некий безликий Object, а потом последовательно назначить ему несколько классов. Если у этих классов есть совпадающие по сигнатуре методы, то они переопределяются в зависимости от порядка назначения этих классов объекту. Ты подобную ситуацию имел ввиду, говоря об участии объекта в нескольких иерархиях?
Нет, я обращал внимание на то, что нарушение LSP происходит не в месте проектирования иерархии, а в месте ее использования. Т.е. рассматривать каждую иерархию в отдельности при использовании надо как гомоморфную. Явная гомоморфность иерархии — это просто способ заранее дать себе линейкой по рукам, дабы неповадно.
Re[26]: Почему объектно-ориентированное программирование про
Здравствуйте, vdimas, Вы писали:
V>Здравствуйте, artelk, Вы писали:
A>>Говоря о гомоморфности, ты как-то намекаешь на множественную диспечеризацию?
V>Какая связь?
Говорю же, телепатический канал на твоей волне что-то шумит...
A>>Допустим, создаю я некий класс и реализую в нем некий интерфейс (например, IEnumerable<T>). Начинай доказывать, что я не должен добавлять в него ни одного вируального метода, чтобы это не противоречило LSP...
V>По справедливости, никто никому ничего не должен. V>
V>Строго говоря, данный критерий можно выполнить и без гомоморфизма. Если производный класс содержит дополнительные открытые функции, их можно просто не вызывать из клиента базового класса. Постойте-ка… а зачем добавлять открытые функции, если их не использовать? Если в одном производном классе были добавлены одни скрытые функции, а в другом — другие, со временем в вашей программе наверняка отыщется точка, в которой их нельзя свободно поменять местами.
V>Настоящая опасность заключается втом, чо без выполнения этого критерия клиентам придется думать о производных классах, а не только о базовом классе, который они знают и любят. Если бы в Dad присутствовали дополнительные открытые члены, клиента Grandpa со временем мог бы спросить свой объект: «Долой притворство — что ты представляешь собой в действительности?» В итоге было бы нарушено столько принципов модульного строения и инкапсуляции, что об этом можно было бы написать целую книгу.
V>Самый простой способ обеспечить взаимозаменяемость — воспользоваться гомоморфизмом. По крайней мере, для интерфейсов гомоморфизм обеспечивает взаимозаменяемость по определению, поскольку клиентам Grandpa не придется беспокоиться о существовании других функций, с которыми им положено работать.
Чем дальше в лес — тем злее дятлы... А кто ж заставляет работать с объектами через сылки на самую дальнюю базу? В .NET, например, есть огромное количество различных методов, принимающих IEumerable<T>. Только ничто не запрещает переменным иметь более точный тип IList<T>, Dictionary<T1, T2> и т.п.
Код:
class SomeClass
{
private List<int> items = new List<int>();
public void SomeMethod1()
{
//...
var x = items.Count(_ => _ > 10);
//...
}
public void SomeMethod2()
{
//...
items.Add(42);
//...
}
}
Почему этот код должен быть переписан в:
class SomeClass
{
private IEnumerable<int> items = new List<int>();
public void SomeMethod1()
{
//...
var x = items.Count(_ => _ > 10);
//...
}
public void SomeMethod2()
{
//...
((IList<int>)items).Add(42);
//...
}
}
?
V>И в реальной разработке я видел многократно, когда IEnumerable<T> приводят к List<T>, T[] или к некоему своему уникальному типу. Только LSP тут уже не при чем.
Действительно непричем.
<...>
V>Нет, я обращал внимание на то, что нарушение LSP происходит не в месте проектирования иерархии, а в месте ее использования. Т.е. рассматривать каждую иерархию в отдельности при использовании надо как гомоморфную. Явная гомоморфность иерархии — это просто способ заранее дать себе линейкой по рукам, дабы неповадно.
Нифига не понятно.
Re[27]: Почему объектно-ориентированное программирование про
Здравствуйте, artelk, Вы писали:
V>>Нет, я обращал внимание на то, что нарушение LSP происходит не в месте проектирования иерархии, а в месте ее использования. Т.е. рассматривать каждую иерархию в отдельности при использовании ее через корень иерархии надо как гомоморфную. Явная гомоморфность иерархии — это просто способ заранее дать себе линейкой по рукам, дабы неповадно.
A>Нифига не понятно.
Тем не менее, в этом вся соль. Добавил выделенное курсивом, вдруг поможет.
Re[11]: Почему объектно-ориентированное программирование про
V>>>>Пример программы — не модели. G>>>Я уже приводил, читай тему. V>>Сорри, не могу себе такое позволить, если не трудно кинь ссылку. G>Лень искать. Тебе надо — ты ищи.
Так и запишем. Примера программы, не являющейся моделью, нет.
G>Гугл вообще не дает точного совпадения по фразе "полностью абстрактный интерфейс".
Попробуй по фразе "абстрактный интерфейс", или "интерфейс класса". Прояви воображение, поищи не только на русском.
Смотри, что пишут даже по языку Java, где это ключевое слово, если не ошибаюсь, было встречено во второй раз, после IDL:
An interface in the Java programming language is an abstract type that is used to specify an interface (in the generic sense of the term) that classes must implement. Interfaces are declared using the interface keyword, and may only contain method signatures and constant declarations (variable declarations which are declared to be both static and final). An interface may never contain method definitions.
Обрати внимание на выделенное. Ну и на этой же странице есть ссылка на определение понятия interface в IT.
G>Приведи в порядок терминологию, потом продолжим разговор.
Ты уже 10-й пост демонстрируешь, что путаешь понятие "интерфейс" с особым типом и ключевым словом конкретного языка. Воистину, вот и выросло next generation. ИМХО, остальное обсуждать бессмысленно, пока не сдвинемся с этой мертвой точки.
V>>Там нет больших иерархий, наверно. G>То есть то что ты писал практикой не подтверждается.
Я писал для случая больших иерархий. Т.е. пример с небольшими иерархиями ничего не подтверждает, а всего-лишь неподходит. Ну и, они таки есть, эти большие иерархии, в прикладных либах дотнета, хоть и используется больше техника абстрактных классов, чем интерфейсов. Коментарии по этому поводу уже давал в этой же ветке, ты невнимателен. Так же предлагал сравнить с библиотеками GUI от Java, например AWT. Очень показательно применение интерфейсов в больших иерархиях. Поверь, тут есть куда двигаться дальше, а не топтаться с этим вопросом на месте. Был бы интерес. Пока ты хотя бы краем глаза не посмотришь, обсуждать практически нечего.
G>Затем что заранее ты не сможешь сказать придется связь разрывть или нет. Зато есть стремление создавать большие иерархии. G>Суть проблемы понимаешь?
Понимаю. Это называется детской болезнью, переходящей, в случае поражения предрассудками, в инженерный идиотизм и заканчивающейся смертельным диагнозом "это придется переделать заново". Лечится гибкостью ума и желанием обучаться, с дополнительными припарками в виде зачатков анализа функциональных требований, с выходом хоть на какой-то список сценариев до написания первого класса. Более подробно высказался здесь
V>>Абстрагирование — это мысленное выделение, вычленение некоторых элементов конкретного множества и отвлечение их от прочих элементов данного множества. Это один из основных процессов умственной деятельности человека,
G>Я не про "мысленное явление" писал.
Не явление, а выделение. Смени там у себя шрифт.
Или вообще имеешь ввиду, что мыслительного явления в твоей работе не происходит? т.е. тебе удается разделять вещи друг от друга, не прибегая к услугам мозгов? Не поделишься сей техникой? Мне бы пригодилось, чтобы книжки почитывать, пока руки программу пишут.
V>>Добавлю от себя, что процесс абстрагирования — это процесс связанный с допущениями/упрощениями, угу, для выделения сути. Поэтому понятие" абстрактного класса" для меня прочно ассоциируется с "упрощенным классом", в интерфейсе которого описана лишь суть порождаемой им иерархии.
G>Очередная черезчур заумная фраза.
Мде. Как ты экзамены сдавал, интересно...
Re[12]: Почему объектно-ориентированное программирование про
Здравствуйте, vdimas, Вы писали:
V>Не обращал тут внимание на мнения коллег, что иерархии/системы ООП относительно неплохо работают на небольших и средних задачах (уточнять размеры сейчас не будем)?
Это кто такое говорил? Я другое обычно вижу, говорят — что ООП работает хорошо на средних и больших задачах, а вот на маленьких как раз ФП его заруливает многократно.
V>Я, размеется, не призываю всех тут же удариться в глубокий анализ и прочее. Тем более, что на некоторых языках/средах/IDE пошаговый рефакторинг может оказаться более дешевым решением, чем углубленный предварительный анализ.
Рефакторинг и анализ не противоречат друг другу, непонятно с чего ты их противопоставляешь.
V>Может так оказаться, что это была последняя добавленная функциональность в класс, и нафига тогда делать работу, которую никто не оценит?
Стремный очень подход, как на мой вкус.
... << RSDN@Home 1.2.0 alpha 5 rev. 1495 on Windows 7 6.1.7600.0>>
Здравствуйте, vdimas, Вы писали:
V>Здравствуйте, gandjustas, Вы писали:
V>>>>>Пример программы — не модели. G>>>>Я уже приводил, читай тему. V>>>Сорри, не могу себе такое позволить, если не трудно кинь ссылку. G>>Лень искать. Тебе надо — ты ищи. V>Так и запишем. Примера программы, не являющейся моделью, нет.
Не сливай так откровенно. Ты задавал вопрос, ты не захотел искать хотя я ответ давал.
G>>Гугл вообще не дает точного совпадения по фразе "полностью абстрактный интерфейс". V>Попробуй по фразе "абстрактный интерфейс", или "интерфейс класса". Прояви воображение, поищи не только на русском.
Ну хватит уже выкручиваться. Нету определения абстрактного интерфейса.
V>Смотри, что пишут даже по языку Java, где это ключевое слово, если не ошибаюсь, было встречено во второй раз, после IDL: V>
V>An interface in the Java programming language is an abstract type that is used to specify an interface (in the generic sense of the term) that classes must implement. Interfaces are declared using the interface keyword, and may only contain method signatures and constant declarations (variable declarations which are declared to be both static and final). An interface may never contain method definitions.
V>Обрати внимание на выделенное. Ну и на этой же странице есть ссылка на определение понятия interface в IT.
И че? Ты выделил несколько слов, которые на русский переводятся "в общем смысле этого слова". Где тут про абстрактный интерфейс?
G>>Приведи в порядок терминологию, потом продолжим разговор.
V>Ты уже 10-й пост демонстрируешь, что путаешь понятие "интерфейс" с особым типом и ключевым словом конкретного языка. Воистину, вот и выросло next generation. ИМХО, остальное обсуждать бессмысленно, пока не сдвинемся с этой мертвой точки.
Так я и говорю, ты приведи в порядок терминологию, чтобы я или кто-то другой не путал твои понятия интерфейсов.
V>>>Там нет больших иерархий, наверно. G>>То есть то что ты писал практикой не подтверждается.
V>Я писал для случая больших иерархий. Т.е. пример с небольшими иерархиями ничего не подтверждает, а всего-лишь неподходит.
Так приведи пример, который подтверждает твои слова.
V>Ну и, они таки есть, эти большие иерархии, в прикладных либах дотнета, хоть и используется больше техника абстрактных классов, чем интерфейсов.
Но мы говорили про интерфейсы.
V>Коментарии по этому поводу уже давал в этой же ветке, ты невнимателен.
Ты пытался увести тему разговора. Что бы ты не забыл напомню твое утверждение: что имеют смысл большие иерархии интерфейсов.
Это утверждение с практикой расходится, никто не создает такие иерархии, они никому не нужны.
V>Так же предлагал сравнить с библиотеками GUI от Java, например AWT.
Мимо кассы, в GUI фреймворках иерархии создают большой процент повторного использования кода. Но чем более глубокая иерархия, тем больше с ней возникает проблем (сколько человек могут навскидку сказать от какого класса надо наследоваться в WPF для создания своего контрола?)
V>Очень показательно применение интерфейсов в больших иерархиях. Поверь, тут есть куда двигаться дальше, а не топтаться с этим вопросом на месте. Был бы интерес. Пока ты хотя бы краем глаза не посмотришь, обсуждать практически нечего.
Я все видел много раз. А ты мог бы привести пример "показательного использования", а не писать пустые слова.
Re[7]: Почему объектно-ориентированное программирование пров
Здравствуйте, vdimas, Вы писали:
V>Здравствуйте, samius, Вы писали:
S>>Получается что ООП — это сверху вниз, а ФП — снизу вверх? S>>ИМХО, ООП не мешает продумывать тщательно как "протаскиваются" данные. Или можно сказать что мешает не ООП, а проектирование сверху в какой-то мере, или даже не проектирование а реализация сверху. Именно она обеспечивает нас неизбежным рефакторингом.
V>Не так. Оба подхода применимы для разработки снизу и сверху. Акцент не на "снизу vs сверху", а на "данные vs акторы".
согласен. Про сверху и снизу — мне показалось что речь об этом. V>Что происходит при отталкивании от данных? Очень простая, но важная вещь: мы выполняем гораздо больший анализ происходящего ДО созревания цельной картинки, то бишь дизайна, в голове. Мы банально начинаем обладать большей информацией. В советской школе программирования учили разрабатывать сначала данные и алгоритмы их обработки. А выделение в модули — это уже результат анализа получаемого решения, фактически выходит автоматически из анализа кол-ва связей по передаче данных, и деления программы по принципу наибольшей связанности внутри модуля и наименьшей — м/у модулями (древнейший принцип, идет еще из электроники/автоматики).
ООП тоже пытается управлять связностью, но действительно, видимо посылки отличаются. В ООП сначала свыше приходят квадратики, а потом предпринимаются усилия по контролю связей между ними. Во всяком случае у меня так бывает.
V>Разве можно это разделение выполнить, не обладая достаточно подробным списком этих самых связей, то бишь не обладая достаточно полным списком используемых алгоритмов и структурами оперируемых данных? В общем, разработка сверху в ООП в клиническом своем варианте, за который его критикуют — это предварительное разделение на "модули" то бишь относительно независимые единицы — объекты, без обладания достаточной информацией о подробностях реализации. Ну и потом, по мере реализации, эти подробности всплывают, уточняется наше собственное видение решения, и мы наше первоначальное решение вынуждены модифицировать.
У меня возникает обратный вопрос. Разве нельзя оставаясь в рамках ООП выполнить это разделение обладая достаточно подробным списком связей? ООП по Кею — это "все есть объект", а не руководство по декомпозиции на модули.
V>В общем, проблема не в ООП, а в заблуждении относительно того, что предварительная стадия анализа может быть минимальной для большой задачи. Не обращал тут внимание на мнения коллег, что иерархии/системы ООП относительно неплохо работают на небольших и средних задачах (уточнять размеры сейчас не будем)? ИМХО, это от того, что вероятность допустить ошибку при "беглом" анализе на небольших системах меньше.
Да, обращал. Но собственного опыта в ФП нет, кроме как на микрозадачах. Про то как оно будет на небольших и средних — могу только догадываться и экстраполировать опыт с микрозадач.
V>Я, размеется, не призываю всех тут же удариться в глубокий анализ и прочее. Тем более, что на некоторых языках/средах/IDE пошаговый рефакторинг может оказаться более дешевым решением, чем углубленный предварительный анализ. Опять же, пошаговость разработки позволяет получать успешные результаты на каждом шаге, что тоже есть гут, бо позволяет уточнять функциональные требования через обратную связь с заказчиком. Но описанные наблюдения "удачных кейзов" стоит держать в голове, и пытаться формировать в ООП заведомо относительно небольшие "экосистемы" типов, дабы переделки внутри этой экосистемы как можно меньше задевали окружающее. Мое замечание относительно ФП в предыдущем посте лишь показывало, что такая независимость при проектировании от данных получается автоматически, т.е. каждая такая экосистема сама формируется вокруг конкретной структуры данных и алгоритмов по трансформации/обработки этих данных.
Встречный вопрос. глубокий предварительный анализ потоков данных не препятствует итеративной разработке с уточнением требований?
S>>Да, т.е. двумя словами — рефакторинг в ООП может быть сведен к минимуму при некоторых правильных привычках. И обилие рефакторинга в ООП не может быть предъявлено как причина его провала в качестве серебрянной пули. Это я и имел ввиду изначально.
V>Например, основные требования — знать что есть ООП (если набирают програмистов на ООП-языки), знать основные паттерны ООП и библиотеки целевого языка. И еще этот, как его... XML. Это что, требования к профессионалу-программисту?
Да, эта проблема в ООП практике существует. С одной стороны, если взять джуниора, скормить ему ООП, паттерны — это безусловно расширит арсенал среднего джуниора. С другой стороны — такой джуниор во всем начинает видеть иерархии и паттерны, часто не замечая простые решения. Тут все зависит от того, на какую почву лег ООП и паттерны. Лишним оно не будет, так что требовать понимание ООП у профессионала можно. Так это еще и удобно — погонять по 3м китам и перечню ГОФ.
Потому встречный вопрос — что требовать и спрашивать (что бы потенциальный профессионал не ушел к конкуренту)?
S>>Меняется видение — нужно менять класс, а не пихать в него пока он не лопнет. Менять проще пока класс и его ответственность обозримы.
V>Это ты подтверждаешь верность исходного постулата. Конечно, классы меняют, модернизируют. Но не заранее, а когда налицо симптомы такой надобности. Не факт, что перед каждым добавлением новой функциональности стоит заранее всё рефакторить. Может так оказаться, что это была последняя добавленная функциональность в класс, и нафига тогда делать работу, которую никто не оценит? В том смысле, что результаты декомпозии не будут востребованы т.е. не будет последующего добавления функциональности в этот участок кода.
Проблема такого подхода в том, что каждый добавляющий функциональность, думает что он последний. Последующему приходится погружаться в более нагроможденный код.
S>>Правильное слово какое. По поводу размеров грануляции соображения следующие: крупная грануляция тяготеет к рефакторингу, а мелкая — к усложнению композиции на верхнем уровне. И это вне парадигм. Решение может быть в ведении дополнительных уровней/этажей абстракции.
V>Они и так сами получаются. Деление на слои процесс как бы автоматический, управляется сложностью единичного элемента, которую может обозреть человек. Какое там правило для ф-ий и методов — не больше 1-2 экранов кода? Примерно так.
Автоматический для тех кто уделяет этому достаточно внимания
S>>Просто эти 4 буквы отпугивают любителей разоблачать, понижают температуру дебатов и дают понять что я не настроен воинственно. В общем, на всякий случай
V>Почему нет, кстати? Если воинственность будет означать большее желание что-то доказать и в итоге означает большую аргументированность и полезность информации — это даже кул. Спор с интересным собеседником во-первых, раскручивает его на дележ информации, которую он бы в ответ на простой вопрос давать бы не стал (хотя бы из-за лени или снобизма).
Часто воинственный спор с интересным собеседником заканчивается вместе с желанием начинать его в другой раз. V>Ну и построение собственных аргументов всегда способсвует наведению порядка в собственной же голове, что тоже всегда гут.
Этим можно заниматься и без состояния войны
Re[6]: Почему объектно-ориентированное программирование пров
Здравствуйте, AndrewVK, Вы писали:
AVK>У тебя исходный тезис — что рефакторинг это зло — неверен.
Зло здесь проявляется лишь в обязательности рефакторинга в ООП по мере роста сложности программы. Это банально мешает при совместной разработке. Остальных причин рефакторинга мы вроде не касались, бо они не исключительны для ООП.
Re[8]: Почему объектно-ориентированное программирование пров
V>>Не обращал тут внимание на мнения коллег, что иерархии/системы ООП относительно неплохо работают на небольших и средних задачах (уточнять размеры сейчас не будем)?
AVK>Это кто такое говорил? Я другое обычно вижу, говорят — что ООП работает хорошо на средних и больших задачах, а вот на маленьких как раз ФП его заруливает многократно.
Наверно уточнять размеры таки будем, если выйдем на следующую итерацию. Что касается больших проектов, ИМХО, пока спасает только компонентное программирование. И твое высказываемое наблюдение, что в больших иерархиях удобнее реализовывать интерфейсы, а не наследовать реализации, тому пример. Это же КОП чистой воды. Хотя сей способ на иерархиях среднего размера, скажем прямо, себя не окупает — не тот уровень распараллеливания работы по людям и по собственным мозгам.
AVK>Рефакторинг и анализ не противоречат друг другу, непонятно с чего ты их противопоставляешь.
Второй раз похожее замечание... Наверно от того, что весь рефакторинг был свален в одну кучу. В общем, речь шла не только о рефакторинге, но и об откровенных переделках. Хотя сие на жаргоне мы тоже называли рефакторингом, согласно термина это и не так, разумеется, так что поправка принимается.
Теперь по теме. ИМХО, рефакторинг/переделки, вызванные пересмотром состава и ролей объектов, связан(ы) обратно с уровнем проведенного анализа. Прочие процедуры рефакторинга, которые есть "прихорашивания" и не меняют семантику отдельных объектов, по мне не достойны рассмотрения, т.к. ни на что не влияют. Но первый случай может быть очень болезненным, т.к. может требовать заметной трудоемкости по обеспечению безопасности операций над обновленным множеством инкапсулированных состояний. А в случае конкретного рассмотренного кейза (вынужденного рефакторинга/переделки всвязи с "утяжелением" объектов), это практически всегда требует дополнительной борьбы с ухудшающейся инкапсуляцией. И не факт, что сия борьба оправдана, а не ведется на автомате, по аналогии с другими объектами программы... вот если бы заранее, еще на уровне дизайна, допустить, что можно рассматривать как данные, а что нельзя....
В общем, анализ — это сбор информации о предстоящем проекте, её упорядочивание, и попытка рассмотреть как можно больше сценариев заранее, с целью минимизации "ломающих" изменений в будущем. Собсно эти "изменения" я анализу и противопоставляю.
V>>Может так оказаться, что это была последняя добавленная функциональность в класс, и нафига тогда делать работу, которую никто не оценит?
AVK>Стремный очень подход, как на мой вкус.
Практичный, ничто не мешает в комментах пометить тип как претендент на рефакторинг при повторении симптомов. Мы же не на выставку код готовим, описанное может являться временным решением, и некая необходимая переделка может быть произведена совсем в другом месте, а упомянутый класс будет освобожден от этой временной "кривой" функциональности. В совместной работе стадии рефакторинга/переделок должны быть отделены от стадий разработки, но иногда возникают "блокеры" по функциональности, когда что-то необходимо добавить срочно, дабы не держать коллег. Так что список таких "кандидатов на рассмотрение" может копиться себе в течении дня или нескольких, но реальная трудоемкость по переделке затем может быть потрачена согласно степени устаканивания решения. Желательно не раньше... особенно если используются языки, где не существуют автоматические ср-ва рефакторинга, сравнимого с IDEA/Resharper. В общем, сия тонкость тоже влияет на приоритеты и принимаемые решения.
==================
Ты не самый интересный момент комментируешь. Суть этих постов была в замеченном факте, что давая больше доступа к обрабатываемым данным во внутреннем АПИ, надобность структурного рефакторинга, того самого, когда заметно меняется состав объектов и еще более заметно их роли, почти всегда выходит ниже.
Re[8]: Почему объектно-ориентированное программирование пров
S>ООП тоже пытается управлять связностью, но действительно, видимо посылки отличаются. В ООП сначала свыше приходят квадратики, а потом предпринимаются усилия по контролю связей между ними. Во всяком случае у меня так бывает.
У всех так. Я же говорю — сначала разбили программу на квадратики, а потом к концу разработки смотрим, сколько у них там связей вышло. Вроде и удобно, но и телега впереди лошади вышла.
S>У меня возникает обратный вопрос. Разве нельзя оставаясь в рамках ООП выполнить это разделение обладая достаточно подробным списком связей? ООП по Кею — это "все есть объект", а не руководство по декомпозиции на модули.
А это вообще больное место. Не существует формальных способов ООП-дизайна. Во всех примерах ООП-анализа в литературе столько творчества, что единственный полезный совет тут — это потщательнее грызть карандаш.
На самом деле, достаточно помнить, что ООП-не серебрянная пуля, т.е. сам по себе не самодостаточный инструмент. Поэтому стоит использовать (хотя бы очень поверхностно) наработки современных процессов по организации разработки ПО. Тем более, что те индифферентны к выбранной технологии. Я вот всем 19-е и 34-е госты рекомендую. Хотя бы раз в жизни прочесть их стоит (с конспектированием интересного). Ну или RUP, который близок по духу.
Понятное дело, что ГОСТы помимо процесса зачастую навязывают вид и состав документации, что в условиях отсутствия автоматизированный ср-в для этого не кажется полезным/обязательным в реальной разработке. Поэтому стоит использовать лишь наработки по организации процессов и составу работ. Это помогает планировать, расставлять приоритеты и поменьше грызть карандаш.
V>>В общем, проблема не в ООП, а в заблуждении относительно того, что предварительная стадия анализа может быть минимальной для большой задачи. Не обращал тут внимание на мнения коллег, что иерархии/системы ООП относительно неплохо работают на небольших и средних задачах (уточнять размеры сейчас не будем)? ИМХО, это от того, что вероятность допустить ошибку при "беглом" анализе на небольших системах меньше. S>Да, обращал. Но собственного опыта в ФП нет, кроме как на микрозадачах. Про то как оно будет на небольших и средних — могу только догадываться и экстраполировать опыт с микрозадач.
А не обязательно чистое ФП, со всеми модными фокусами. ФП сидит на функциональной декомпозиции, а это практически первое, чему учатся при обучении программированию. Ну и если есть опыт по созданию/использованию делегатов в том же C#, то еще одним "китом" ФП ты уже владеешь. Прочие ленивости и замыкания — это лишь доп. выразительные ср-ва инструмента, т.е. те, которые не критичны, т.к. в случае надобности реализуются "в лоб". Хотя со вторым упомянутым в шарпе тоже порядок. Ну и плюс, ФП в "чистом" виде не совсем удобно (лично мне, например). Какая-никакая группировка функциональности в объекты помогает в восприятии происходящего в собственной программе, сие факт. Поэтому речь была не о переходе на чистое ФП, а о заимствовании полезных подсмотренных практик, кои не только в иммутабельности заключаются, но во взгляде на шаги решения задачи как на стадии трансформации данных. Отсекая заранее спекуляции — разумеется и это не для всех задач удобный поинт. Речь о том, чтобы расширить взгляд на задачу, не подгоняя его заведомо под рамки ООП. Называя вещи своими именами — дать ООП роль "низкоуровневого" инструмента, призванного обеспечивать наш "высокоуровневый" взгляд на вещи. Тоже самое касается чистого ФП — это всё низкоуровневые подробности реализации.
S>Встречный вопрос. глубокий предварительный анализ потоков данных не препятствует итеративной разработке с уточнением требований?
Нет. Речь шла о хоть каком-то анализе алгоритмов и данных vs проектирование от квадратиков. И там и там на кончике карандаша всю систему разработать проблематично, но первая модель будет ближе к реально происходящему уже на первой итерации. У тебя будет банально больше информации в первом случае, чтобы нарисовать более удачный вариант квадратиков.
S>Потому встречный вопрос — что требовать и спрашивать (что бы потенциальный профессионал не ушел к конкуренту)?
Если так ставить вопрос — то ничего.
Я же говорю — дефицит вменяемой программистской рабсилы. ИМХО, спросить можно, на сколько он хочет пополнить свои знания в сравнении с сегодняшним уровнем. Або я встречал "спецов", которые неплохо владеют языками, фактически на уровне дословного знания спецификаций, но полны различных предрассудков, с которыми тяжело бороться. Приходится заставлять писать тестовые примеры, дабы лечить от предрассудков. А перед этим еще приходится объяснять, почему надо писать эти "нелепые" примеры...
S>Проблема такого подхода в том, что каждый добавляющий функциональность, думает что он последний. Последующему приходится погружаться в более нагроможденный код.
Практика комментирования коммитов и щедрость на TODO помогает упорядочивать. Главное, чтобы команда преследовала общие цели, и если кто-то видит, что образуется потенциально слабое место — поставил сигнальный флажок на нем.
V>>Они и так сами получаются. Деление на слои процесс как бы автоматический, управляется сложностью единичного элемента, которую может обозреть человек. Какое там правило для ф-ий и методов — не больше 1-2 экранов кода? Примерно так. S>Автоматический для тех кто уделяет этому достаточно внимания
Всё-равно автоматически по достижении некоторого порога. Однажды становится трудно просто прочесть код, даже если он хорош. И единственно правильное решение — декомпозировать, передокументировать и прочесть заново. Это может сэкономить часы и это дополнительный review кода. Оно как эффект катастрофы в природе, во вменяемой команде выполняется на автомате всеми участниками.
Re[10]: Почему объектно-ориентированное программирование про
Здравствуйте, FR, Вы писали:
V>>Ты не самый интересный момент комментируешь. Суть этих постов была в замеченном факте, что давая больше доступа к обрабатываемым данным во внутреннем АПИ, надобность структурного рефакторинга, того самого, когда заметно меняется состав объектов и еще более заметно их роли, почти всегда выходит ниже.
FR>Кстати функциональщина как раз поощряет (АТД и ПМ) такой больший доступ.
Да там способа другого нет. Это позволило обнаружить рассматриваемую полезную практику, ведь ничто не мешает перетащить ее в ООП.
Re[9]: Почему объектно-ориентированное программирование пров
Здравствуйте, vdimas, Вы писали:
V>Что касается больших проектов, ИМХО, пока спасает только компонентное программирование.
КОП и ООП в мейнстриме тесно связаны.
V> И твое высказываемое наблюдение, что в больших иерархиях удобнее реализовывать интерфейсы, а не наследовать реализации, тому пример. Это же КОП чистой воды.
Конечно же нет. Во-первых реализация интерфейсов нужна исключительно для полиморфизма, что к КОП имеет весьма опосредованное отношение. Во-вторых дело далеко не в удобстве, я это стопицот раз уже писал.
V> Хотя сей способ на иерархиях среднего размера, скажем прямо, себя не окупает — не тот уровень распараллеливания работы по людям и по собственным мозгам.
Вот так вот прям всегда и везде? Однако.
AVK>>Рефакторинг и анализ не противоречат друг другу, непонятно с чего ты их противопоставляешь.
V>Второй раз похожее замечание... Наверно от того, что весь рефакторинг был свален в одну кучу. В общем, речь шла не только о рефакторинге, но и об откровенных переделках.
Какие то очень размытые термины и неуместная генерализация. Размер и проблемность рефакторинга в большей степени зависит от частоты проведения рефакторинга и вообще отношения к качеству кода, а не от количества свободных функций и классов.
V>Теперь по теме. ИМХО, рефакторинг/переделки, вызванные пересмотром состава и ролей объектов, связан(ы) обратно с уровнем проведенного анализа.
Т.е. ты считаешь, что если хорошо проанализировать, то можно с первой итерации создать финальный детальный дизайн приложения?
V>Но первый случай может быть очень болезненным, т.к. может требовать заметной трудоемкости по обеспечению безопасности операций над обновленным множеством инкапсулированных состояний.
Опять ты чего о путаешь. Подобные проблемы возникают исключительно из-за низкого качества кода, типа большого количества тяжелых изменяемых состояний. И, сюрпрайз, наследование реализаций это одна из тех вещей, которая этому (проблемам с рефакторингом) способствует.
V>>>Может так оказаться, что это была последняя добавленная функциональность в класс, и нафига тогда делать работу, которую никто не оценит? AVK>>Стремный очень подход, как на мой вкус.
V>Практичный
Практичный он только на очень коротких временных интервалах. Либо на специфичных проектах, где код модифицируется редко. На моем опыте почему то вся на первый взгляд безобидная халява обязательно вылазит в виде граблей позже.
V>Ты не самый интересный момент комментируешь. Суть этих постов была в замеченном факте, что давая больше доступа к обрабатываемым данным во внутреннем АПИ, надобность структурного рефакторинга, того самого, когда заметно меняется состав объектов и еще более заметно их роли, почти всегда выходит ниже.
Мои замечания относятся к исходным предпосылкам. Поскольку они неверны, то вывод, как минимум, необоснован. И да, на практике я замечаю прямо противоположное — чем меньше связность кода, тем проще, легче и безболезненнее рефакторинг.
... << RSDN@Home 1.2.0 alpha 5 rev. 1495 on Windows 7 6.1.7600.0>>
Здравствуйте, vdimas, Вы писали:
V>Зло здесь проявляется лишь в обязательности рефакторинга в ООП по мере роста сложности программы.
Рефакторинг, конечно, не обязателен. Но крайне желателен, независимо от того, ООП это, ФП или структурное программирование в чистом виде.
V> Это банально мешает при совместной разработке.
Куда больше мешает деградация качества кода при отсутствии рефакторинга.
... << RSDN@Home 1.2.0 alpha 5 rev. 1495 on Windows 7 6.1.7600.0>>
Здравствуйте, vdimas, Вы писали:
V>Нужен меньше. По опыту плюсов, чем меньше создаешь классов, т.е. чем больше функциональности удается разнести в свободные ф-ии, тем меньше надобность рефакторинга.
И наоброт — чем больше функциональности в свободных функций, тем сильнее нужен рефакторинг, например из за того, что слишком много функций зависит от одного класса.
>ИМХО, это объяснимо, т.к. объект в ООП — это группировка в "одно целое" относительно большого кол-ва элементов программы. И весь рефакторинг, по-сути, это перетасовка элементов таких групп.
Как то ты странно ООП понимаешь
>Пройдись по формальным методам рефакторинга: 90% рефакторинга — это способы перемещения методов и полей м/у объектами таким образом, чтобы не поломать случайно исходное поведение программы.
Ты вероятно Фаулера читал Рефакторинг это реорганизация обязанностей и зависимостий при сохранении НАБЛЮДАЕМОГО поведения программы.
Если ты понаписывал много свободных функций и оставил мало функциональности в классе, то это вовсе не значит, что рефакторинг не нужен. Зависимости ведь реально никуда не делись и обязанности тож
Соответственно при изменении требований выявляются проблемы — изменил класс, измени и сотню свободных фунций. Все, приехали.
Re[5]: Почему объектно-ориентированное программирование пров
Здравствуйте, vdimas, Вы писали:
V>А по существу... Не проблема преобразовать. Проблема в том, что дается механизм, достаточно легкий для дизайна "верхнего уровня", который практически сразу позволяет набросать основной скелет программы и всё выходит красивым и очевидным. Это ООП, и это его несомненное достоинство. От этого трудно отказаться, поэтому это используют. Не зря коллеги говорят, что дизайн верхнего уровня в ООП смотрится лучше всего. Так в чем засада? ИМХО, проблемы в ООП начинаются там, где объекты начинают "тяжелеть", а иерархии разрастаться. А они это делают не потому что кто-то дурак, а по объективным мотивам: уточняется функциональность, растет список сценариев и т.д. Что мы делаем в ответ на разбухание кода? Мы вводим новые "слои" в наш ООП, выделяем "хелперы" и целые "независимые подсистемы" и так до бесконечности. Вот что имелось ввиду, когда утверждалось, что ООП обречен на постоянный рефакторинг, то бишь на постоянное переписывание кода.
Рефакторинг это _не_ переписывание.
"Мы вводим новые "слои" в наш ООП, выделяем "хелперы" и целые "независимые подсистемы" и так до бесконечности."
Конечно, не у каждого есть видение самого конечного дизайна. Скажем если потратил на ООП-решение год, то это вовсе не означает, что на ФП ты сходу выдашь точно такое же или лучшее.
V>При большом объеме функционала нужно что-то легковесное, чтобы была возможность легко и непринужденно этой функциональностью ворочать, без рефакторинга на каждый чих. В ФП нет возможности вот так красиво описать статическую структуру участников. фП думает от данных и потоков их обработки. Им всю программу приходится писать в терминах "хелперов" и "подсистем" с самого начала. Плюс продумывать тщательно, как "протаскиваются" эти данные и прочий контекст в процессе вычисления. Вот и выходит, что по мере роста функционала им ничего переписывать не приходится, всё уже переписано с самого начала и заведомо декомпозировано до уровня плинтуса. В отличие от "черных ящиков" ООП.
Это так кажется. Код всегда можно улучшить. Хоть ФП, хоть ООП. Рефакторинг это один из способов улучшения кода, инструмент решения проблем.
V>Справедливости ради, в ООП тоже сей подход можно использовать. Т.е. брать у ФП не только модную здесь иммутабельность и замыкания (порой до экстаза), но саму программу плясать от данных и небольших объектов, представляющих эти данные с одной стороны, и осуществляющие обработку этих данных с другой стороны. Заметь, это отход от парадигмы общепринятой парадигмы ООП, хотя используются ООП ср-ва. Итоговый дизайн должен представлять из себя большое кол-во легковесных объектов минимальнейшей функциональности, которые не потребует рефакторинга ни при каких обстоятельствах. ИМХО, такой стиль — дело привычки.
SOLID — это и есть ООП Правильно распознать все обязанности, зависимости, провести границу детализации — это не дело привычки, это адский труд.
Re[5]: Почему объектно-ориентированное программирование пров
Здравствуйте, FR, Вы писали:
I>>И наоброт — чем больше функциональности в свободных функций, тем сильнее нужен рефакторинг, например из за того, что слишком много функций зависит от одного класса.
FR>Не нужен, такие классы ничего лишнего не содержат и их внешний интерфейс менять практически не приходится, зато рефакторить внутренности таких классов намного легче
То есть, если надо внести изменения в этот класс, то функции сами собой перепишутся ?
Или менять функции никогда не придется ?
Никакой SOLID не отменяет необходимости рефакторинга Ну разве что сразу взять да написать идеально с учетом требований на 100 лет вперёд.
Re[10]: Почему объектно-ориентированное программирование про
Здравствуйте, AndrewVK, Вы писали:
AVK>КОП и ООП в мейнстриме тесно связаны.
В плюсах КОП в чистом виде накладен.
V>> И твое высказываемое наблюдение, что в больших иерархиях удобнее реализовывать интерфейсы, а не наследовать реализации, тому пример. Это же КОП чистой воды.
AVK>Конечно же нет. Во-первых реализация интерфейсов нужна исключительно для полиморфизма, что к КОП имеет весьма опосредованное отношение.
Тем не менее, полиморфизм в КОП так же доступен и используется так же. И вопрос ради любопыства: у тебя никогда не бывает так, что некий интерфейс реализован лишь однажды? Именно в production, не учитывая тестовых реализаций? (бо для тестовых случаев есть другие техники)
AVK>Во-вторых дело далеко не в удобстве, я это стопицот раз уже писал.
А что есть "удобство" в плане разработки/поддержания ПО, как не снижение суммарной трудоемкости?
V>> Хотя сей способ на иерархиях среднего размера, скажем прямо, себя не окупает — не тот уровень распараллеливания работы по людям и по собственным мозгам.
AVK>Вот так вот прям всегда и везде? Однако.
Угу, "всегда и везде" это конечно сильно, не возразишь. Тем не менее, "полу-абстрактные" классы (в которых не все методы абстрактны) по-прежнему эффективны и активно используются в заметных по размеру иерархиях того же дотнета.
AVK>Размер и проблемность рефакторинга в большей степени зависит от частоты проведения рефакторинга и вообще отношения к качеству кода, а не от количества свободных функций и классов.
От количества связей проблемность больше зависит. Иногда "простой" рефакторинг базовой функциональности может потянуть за собой много изменений, не поддающихся автоматическому рефакторингу, в "клиентском" месте использования. Например, как произошло с некоторыми коллекциями для SL в сравнении с обычным .Net FW.
V>>Теперь по теме. ИМХО, рефакторинг/переделки, вызванные пересмотром состава и ролей объектов, связан(ы) обратно с уровнем проведенного анализа.
AVK>Т.е. ты считаешь, что если хорошо проанализировать, то можно с первой итерации создать финальный детальный дизайн приложения?
Было сказано "более удачный". Речь шла о выявлении наиболее частоупотребимых сценариев на уровне анализа, сие помогает выявить функциональность с наибольшим повторным использованием. И это нужно для меньшей болезненности описанного абзацем выше.
V>>Но первый случай может быть очень болезненным, т.к. может требовать заметной трудоемкости по обеспечению безопасности операций над обновленным множеством инкапсулированных состояний.
AVK>Опять ты чего о путаешь. Подобные проблемы возникают исключительно из-за низкого качества кода, типа большого количества тяжелых изменяемых состояний. И, сюрпрайз, наследование реализаций это одна из тех вещей, которая этому (проблемам с рефакторингом) способствует.
Тяжелые изменяемые состояния, да еще транзакционно изменяемые, могут быть частью предметной области. И это мы еще не договорились, что есть тяжелые, а что нет. По мне, проблема — это когда вокруг обсуждаемого состояния очень много функциональности. Т.е. проблемы по связанности начинаются уже внутри объекта, а не за его пределами. а этой функциональности может быть много просто по характеру предметной области. Тогда такое состояние стоит выносить из инкапсуляции, делать безопасный интерфейс именно к состоянию и рассматривать его как данные. А если даже состояние "большое", но по нему пару операций — это обычно не проблема. Даже для последующего рефакторинга. В общем, проблемой считаю большое кол-во кол-во изменений в коде, связанных с небольшим изменением композиции состояний. Это даже через интерфейсы может задеть многое, из-за надобности сии интерфейсы корректировать.
AVK>Практичный он только на очень коротких временных интервалах.
Недельный цикл разработки — это "долго"? Про ситуацию с блокерами уже делал замечание. Собсно, на них такое и происходит. Но это не повод, всё бросать и тут же переделывать, особенно если над тем же кодом работает/использует 5 и более человек.
AVK>Либо на специфичных проектах, где код модифицируется редко.
Не редко, а упорядоченно. Т.е. не одновременно с активной разработкой, чтобы не тратить по часу на ручной мерж веток.
AVK>На моем опыте почему то вся на первый взгляд безобидная халява обязательно вылазит в виде граблей позже.
Ну, пока все TODO в исходниках не закрыты, сдавать код никто не будет. Конечно, без некоей культуры совместной разработки никуда. Но это не только рефакторинга касается.
V>>Ты не самый интересный момент комментируешь. Суть этих постов была в замеченном факте, что давая больше доступа к обрабатываемым данным во внутреннем АПИ, надобность структурного рефакторинга, того самого, когда заметно меняется состав объектов и еще более заметно их роли, почти всегда выходит ниже.
AVK>Мои замечания относятся к исходным предпосылкам. Поскольку они неверны, то вывод, как минимум, необоснован.
Я пока не увидел, насчет "неверны". Тяжелые состояния, низкое качество кода и т.д. — требует определения.
По мне, низкое качество кода, это такое, которое для удовлетворения всех функциональных и нефункциональных требований к нему потребует значительной переделки/рефакторинга как в нем так и по зависимостям. И через непродуманные интерфейсы в т.ч. По сути, практически весь недописанный код некачественный. Т.е. метрика степени его некачественности — это суммарное кол-во телодвижений, требуемых до доведения до качественного.
Остальное, типа читабельности, "красоты" и прочее доводиться локально без каких-либо дерганий окружения, по сему мало волнует. Даже переименование, задевающее сотни мест использования, не составляет никакой проблемы. Ручного-то вмешательства не требуется. А читабельность и так доводится в процессе взаимного ревью. ИМХО, "читателями" лучше всего и доводится.
AVK>И да, на практике я замечаю прямо противоположное — чем меньше связность кода, тем проще, легче и безболезненнее рефакторинг.
Правильно, я высказывал мысли, как этого достичь в полуавтоматичном режиме. Выделяя некое состояние как "данные", мы фиксируем безопасный "интерфейс" доступа к данным, оставляя на свободе функционал вокруг них. И вот это множество, составляющее функционал, само по себе выходит слабо м/у собой связанным. Дело в том, что полно ситуаций, когда набор данных меняется редко (не путать с добавлением других данных), а вот операции, даже по устаканенным данным, пересматриваются/уточняются часто. Рефакторинг, связанный с декомпозицией состояния объектов (например, поля тусуем из наследников в базу и обратно или в другой агрегированный объект) по моему наблюдению вызывается развитием именно функциональности. И вот для удовлетворения этого развития нам одни и те же инкапсулированные данные становятся нужны в разных местах, где ранее их надобность не представлялась очевидной. Или наоборот, новая "маленькая" функциональность объекта требует для своей работы как всё остальное состояние, так и еще пару, нужных только для нее, полей. После нескольких таких добавлений требуется переделка. Это обычные происходящие в разработке вещи, именно они и приводят к последующему рефакторингу с пересмотром инкапсуляции. Потому и предлагалось, в расширение обычной практики, посмотреть на вариант, не будет ли удобным часть состояний сразу рассматривать как данные/контекст и т.д. А это без списка сценариев и предварительной прикидки алгоримов по ним не угадаешь.
Re[6]: Почему объектно-ориентированное программирование пров
Здравствуйте, Ikemefula, Вы писали:
I>Конечно, не у каждого есть видение самого конечного дизайна. Скажем если потратил на ООП-решение год, то это вовсе не означает, что на ФП ты сходу выдашь точно такое же или лучшее.
Конечно не выдашь. Я лишь делюсь, как удается использовать большее кол-во наработок без переделки.
V>>При большом объеме функционала нужно что-то легковесное, чтобы была возможность легко и непринужденно этой функциональностью ворочать, без рефакторинга на каждый чих. В ФП нет возможности вот так красиво описать статическую структуру участников. фП думает от данных и потоков их обработки. Им всю программу приходится писать в терминах "хелперов" и "подсистем" с самого начала. Плюс продумывать тщательно, как "протаскиваются" эти данные и прочий контекст в процессе вычисления. Вот и выходит, что по мере роста функционала им ничего переписывать не приходится, всё уже переписано с самого начала и заведомо декомпозировано до уровня плинтуса. В отличие от "черных ящиков" ООП.
I>Это так кажется. Код всегда можно улучшить. Хоть ФП, хоть ООП. Рефакторинг это один из способов улучшения кода, инструмент решения проблем.
Повторю — требуется нечто легковесное, когда требуется ворочать большим накопленным функционалом. Именно для того, чтобы не бояться играть дизайном верхнего уровня, беспокоясь что все остальное отлетит. Конечно, без развития дизайна никуда. Вопрос в том, чтобы это развитие сделать максимально дешевым. Кто-то тут настаивает на постоянном рефакторинге. Ну что же, если есть для используемого языка хороший тул по рефакторингу, возможно, что это вариант. Хотя на C# сия легковесность тоже прекрасно работает с тем же эффектом.
I>SOLID — это и есть ООП Правильно распознать все обязанности, зависимости, провести границу детализации — это не дело привычки, это адский труд.
Но ведь не факт, что в первой итерации будет удачно, правильно? Почему бы начинать не с максимально закрытой инкапсуляции, а местами с открытой, закрывая потом частности по мере устаканивания собственного видения происходящего? Еще раз, объектная декомпозиция — это практически всегда разделение состояния, т.е. ухудшение инкапсуляции, т.е. всё больше подробностей реализации начинает торчать наружу, да еще добавляются обвески в плане того, что новые объекты должны "правильно" друг друга использовать. Вот эти меняющиеся информационные составляющие, да еще когда 90% из них временны и живут лишь до следующей переделки/рефакторинга — тоже немалая часть балласта в период разработки.
Re[4]: Почему объектно-ориентированное программирование пров
>>ИМХО, это объяснимо, т.к. объект в ООП — это группировка в "одно целое" относительно большого кол-ва элементов программы. И весь рефакторинг, по-сути, это перетасовка элементов таких групп.
I>Как то ты странно ООП понимаешь
Не само ООП, а связь ООП с рефакторингом.
>>Пройдись по формальным методам рефакторинга: 90% рефакторинга — это способы перемещения методов и полей м/у объектами таким образом, чтобы не поломать случайно исходное поведение программы.
I>Ты вероятно Фаулера читал Рефакторинг это реорганизация обязанностей и зависимостий при сохранении НАБЛЮДАЕМОГО поведения программы.
I>Если ты понаписывал много свободных функций и оставил мало функциональности в классе, то это вовсе не значит, что рефакторинг не нужен. Зависимости ведь реально никуда не делись и обязанности тож
Было наоборот сказано, что нужно нечто, чем можно "легко ворочать". Т.е. развитие дизайна — это нормально, речь о суммарном количестве связанных с этим телодвижений.
I>Соответственно при изменении требований выявляются проблемы — изменил класс, измени и сотню свободных фунций. Все, приехали.
Если заметно меняются данные, то изменения будут во всех задевающих их ф-иях, независимо от того, свободные они, или являются методами объектов. А вот при доработке функциональности по имеющимся данным — картинка уже совсем другая.
Обрати внимание, как неплохо вписались методы-расширения в C# и с каким удовольствием народ это использует. Потребуется ли тебе рефакторинг таких методов расширения из нейспейса, например, Linq? "А с какой стати?", ты спросишь, и будешь прав, ибо необходимые себе методы-расширения ты можешь нарисовать "рядом", не вступая в конфликт с имеющимся. В общем, это примерно то, о чем так долго говорила Коммунистическая Партия. (С) Глобальные ф-ии отбрасывать не стоит. Ну а по замыканиям и прочим ф-ным объектам мы уже проходились тут неоднократно.
Re[7]: Почему объектно-ориентированное программирование пров
Здравствуйте, vdimas, Вы писали:
I>>Конечно, не у каждого есть видение самого конечного дизайна. Скажем если потратил на ООП-решение год, то это вовсе не означает, что на ФП ты сходу выдашь точно такое же или лучшее.
V>Конечно не выдашь. Я лишь делюсь, как удается использовать большее кол-во наработок без переделки.
Из твоих слов не совсем ясно, как должны выглять свободные функции, а хаос можно на раз воплотить с абсолютно любым подходом.
Соответсвенно если ты имел ввиду SOLID, то хватило бы и пяти букв а не пространных изречений
I>>Это так кажется. Код всегда можно улучшить. Хоть ФП, хоть ООП. Рефакторинг это один из способов улучшения кода, инструмент решения проблем.
V>Повторю — требуется нечто легковесное, когда требуется ворочать большим накопленным функционалом. Именно для того, чтобы не бояться играть дизайном верхнего уровня, беспокоясь что все остальное отлетит. Конечно, без развития дизайна никуда. Вопрос в том, чтобы это развитие сделать максимально дешевым.
Один из путей достижения этой цели — рефакторинг.
V>Но ведь не факт, что в первой итерации будет удачно, правильно? Почему бы начинать не с максимально закрытой инкапсуляции, а местами с открытой, закрывая потом частности по мере устаканивания собственного видения происходящего?
Начинается обычно с той формы, которая наилучшим способом вписывается в проект.
Если ты начинаешь с открытой реализации, то в ряде случаев есть сильный шанс что закрыть просто не сможешь.
>Еще раз, объектная декомпозиция — это практически всегда разделение состояния, т.е. ухудшение инкапсуляции,
Что значит разделение состояния ? На примере.
>Вот эти меняющиеся информационные составляющие, да еще когда 90% из них временны и живут лишь до следующей переделки/рефакторинга — тоже немалая часть балласта в период разработки.
В ФП точно так же. В идеале хорошо бы в коде задавать аналитическое описание системы. Но факт в том, что начиная с определнного порога сложные системы уже невозможно описывать аналитически. До этого порога рулит ФП. После этого порога рулит уже ООП — как минимум согласовывать между собой всякие модули написаные как с ФП так и без него.
Re[5]: Почему объектно-ориентированное программирование пров
Здравствуйте, vdimas, Вы писали:
I>>Ты вероятно Фаулера читал Рефакторинг это реорганизация обязанностей и зависимостий при сохранении НАБЛЮДАЕМОГО поведения программы.
V>Фаулера терпеть ненавижу. V>Пройдись по формальному описанию методов рефакторинга для C#.
Это слабенькая литература. Про рефакторинг тот же лучше отрыть Майлка Физерса http://www.ozon.ru/context/detail/id/4311012/
V>Если заметно меняются данные, то изменения будут во всех задевающих их ф-иях, независимо от того, свободные они, или являются методами объектов. А вот при доработке функциональности по имеющимся данным — картинка уже совсем другая.
Устранять дублирование кода, реорганизовывать зависимости, обязанности все равно надо, независимо от того, что у тебя меняется функции или данные
V>Обрати внимание, как неплохо вписались методы-расширения в C# и с каким удовольствием народ это использует. Потребуется ли тебе рефакторинг таких методов расширения из нейспейса, например, Linq?
Мне — нет. А вот Микрософту вполне возможно. В своем коде Linq-провайдер еще предстоит рефакторить хотя он и написан в том духекак ты говоришь — чз всякие свободные функции
Re[8]: Почему объектно-ориентированное программирование пров
Здравствуйте, Ikemefula, Вы писали:
I>В ФП точно так же. В идеале хорошо бы в коде задавать аналитическое описание системы. Но факт в том, что начиная с определнного порога сложные системы уже невозможно описывать аналитически. До этого порога рулит ФП. После этого порога рулит уже ООП — как минимум согласовывать между собой всякие модули
написаные как с ФП так и без него.
То что ты называешь тут ООП на самом деле является SOA. Это просто взяли ООП и выкинули оттуда наследование реализации и идентичность объектов. Остались только сервисы (интерфейсы) и их эндпоинты. А внутри них может быть как ООП (с наследованием реализации), так и ФП, и actor model.
Re[11]: Почему объектно-ориентированное программирование про
Здравствуйте, vdimas, Вы писали:
AVK>>КОП и ООП в мейнстриме тесно связаны.
V>В плюсах КОП в чистом виде накладен.
Это личные проблемы плюсов.
AVK>>Конечно же нет. Во-первых реализация интерфейсов нужна исключительно для полиморфизма, что к КОП имеет весьма опосредованное отношение.
V>Тем не менее, полиморфизм в КОП так же доступен и используется так же.
Но не является обязательной частью, в отличие от.
V> И вопрос ради любопыства: у тебя никогда не бывает так, что некий интерфейс реализован лишь однажды?
Редко. В основном в местах, где вероятен подключаемый сторонний код.
AVK>>Вот так вот прям всегда и везде? Однако.
V>Угу, "всегда и везде" это конечно сильно, не возразишь. Тем не менее, "полу-абстрактные" классы (в которых не все методы абстрактны) по-прежнему эффективны и активно используются в заметных по размеру иерархиях того же дотнета.
У нас что, иерархии FW уже идеальный образец? Косяков дизайна там примерно столько же, сколько в большинстве более менее приличного промышленного кода в среднем.
AVK>>Размер и проблемность рефакторинга в большей степени зависит от частоты проведения рефакторинга и вообще отношения к качеству кода, а не от количества свободных функций и классов.
V>От количества связей проблемность больше зависит.
Количество связей есть функция от качества дизайна. А качество дизайна завист в том числе и от количества и качества рефакторингов.
V> "простой" рефакторинг базовой функциональности может потянуть за собой много изменений, не поддающихся автоматическому рефакторингу
Это именно то, о чем я и говорю — если забить на рефакторинг, то связность будет расти, и, как следствие, любое изменение кода, не только рефакторинг, будет обходится все дороже и дороже.
Только какое это имеет отношение к тому, что ООП приводит к усложнению рефакторинга? Ты считаешь, что ООП решения всегда более связные, нежели чисто структурные?
AVK>>Т.е. ты считаешь, что если хорошо проанализировать, то можно с первой итерации создать финальный детальный дизайн приложения?
V>Было сказано "более удачный". Речь шла о выявлении наиболее частоупотребимых сценариев на уровне анализа, сие помогает выявить функциональность с наибольшим повторным использованием. И это нужно для меньшей болезненности описанного абзацем выше.
Я только не понимаю, почему ты агитируешь за крайности? Нужно искать баланс между предварительным проектированием и доработками по ходу создания. В каждом случае он разный, универсального и хорошо работающего рецепта нет, чтобы не утверждали адепты обеих крайностей.
V>Тяжелые изменяемые состояния, да еще транзакционно изменяемые, могут быть частью предметной области.
Вот поэтому архитекторам и платят денежку. Есть целая куча способов минимизировать вред от подобного. Начиная от простейших вещей типа паттерна state и заканчивая сложными системами типа современных СУБД и систем поддержки long running transactions.
V> И это мы еще не договорились, что есть тяжелые, а что нет. По мне, проблема — это когда вокруг обсуждаемого состояния очень много функциональности. Т.е. проблемы по связанности начинаются уже внутри объекта, а не за его пределами. а этой функциональности может быть много просто по характеру предметной области.
Функциональности обычно всегда много. Надо уметь ее хорошо декомпозировать. Это все банальности.
V>Я пока не увидел, насчет "неверны". Тяжелые состояния, низкое качество кода и т.д. — требует определения.
Если хочешь поговорить о терминах, то я пас. Не интересно.
AVK>>И да, на практике я замечаю прямо противоположное — чем меньше связность кода, тем проще, легче и безболезненнее рефакторинг.
V>Правильно, я высказывал мысли, как этого достичь в полуавтоматичном режиме.
Этого гарантированно нельзя добиться в сколько нибудь автоматическом режиме. Именно это чуть менее чем полностью определяет интеллектуальное наполнение большинства современных продуктов (за исключением вещей с уникальной алгоритмикой, но таких сейчас очень мало). И именно поэтому сия область состоит чуть более чем полностью из эвристик и представлений о правильном.
V> Выделяя некое состояние как "данные", мы фиксируем безопасный "интерфейс" доступа к данным, оставляя на свободе функционал вокруг них.
КО? Это все здорово, но это только декларация. Примитив. А на практике есть огромная куча деталей.
Не, ты всерьез веришь, что для борьбы со связностью достаточно такого простенького правила?
V> И вот это множество, составляющее функционал, само по себе выходит слабо м/у собой связанным. Дело в том, что полно ситуаций, когда набор данных меняется редко (не путать с добавлением других данных), а вот операции, даже по устаканенным данным, пересматриваются/уточняются часто.
Ты вообще это серьезно? Мне казалось, что азбучные истины для всех участников топика очевидны. Если ты пытаешься сказать, что уменьшение связности благотворно сказывается на сложности изменений, то это и так всем понятно. Только при чем тут ООП?
... << RSDN@Home 1.2.0 alpha 5 rev. 1495 on Windows 7 6.1.7600.0>>
Здравствуйте, gandjustas, Вы писали:
G>То что ты называешь тут ООП на самом деле является SOA. Это просто взяли ООП и выкинули оттуда наследование реализации и идентичность объектов. Остались только сервисы (интерфейсы) и их эндпоинты. А внутри них может быть как ООП (с наследованием реализации), так и ФП, и actor model.
То о чем я говорю, это просто ООП.
Re[8]: Почему объектно-ориентированное программирование пров
Здравствуйте, Ikemefula, Вы писали:
I>Из твоих слов не совсем ясно, как должны выглять свободные функции, а хаос можно на раз воплотить с абсолютно любым подходом. I>Соответсвенно если ты имел ввиду SOLID, то хватило бы и пяти букв а не пространных изречений
Э нет, хаос можно наворотить, даже применяя все подходы, парадигмы и эти, как их, паттерны. Поэтому требуется некая почва под ногами: например степень соответствия функциональным и нефункциональным требованиям и стоимость по ее обеспечению, если где-то есть расхождения. Кстати, глобальные ф-ии и ф-ии высших порядков — это друзъя сервисов, близких по духу к stateless, т.е. в них твое DI работает тоже на ура. Собсно, только оно нормально и работает при глубокой декомпозиции функциональности. Пример алгоритмов STL когда-то уже обсуждали. Ну и еще реактивный подход, к которому тяготеет дизайн от данных, тоже способствует разделению не по участникам, а по шагам обработки данных, и здесь DI тоже удобно для абстрагирования от конкретной реализации каждого шага.
I>Один из путей достижения этой цели — рефакторинг.
Рефакторинг по определению такие изменения, которые не меняют функционал. А когда надо именно менять функционал? Тогда приходится сначала рефакторить, потом уже менять функционал. Рефакторинг тоже имеет свою трудоемкость, и если его надобность однозначно определяется самим фактом развития функциональности, то что-то здесь не так.
I>Начинается обычно с той формы, которая наилучшим способом вписывается в проект. I>Если ты начинаешь с открытой реализации, то в ряде случаев есть сильный шанс что закрыть просто не сможешь.
Если действительно не сможешь закрыть, то поверь, на это же выйдешь с "другой стороны" — постепенно уменьшая инкапсуляцию. А если принципиальная возможность согласно функциональности есть — то она достижима в одну итерацию рефакторинга. Но! мы уже будем видеть зависимости, по крайней мере для текущей версии софта. Я уже приводил пример взгляда на состояние как на контекст. Я выделяю объект-контекст из просто структур/объектов, представляющих данные тем, что в в контексте не всё состояние доступно извне, он может содержать инкапсулированное состояние. Но, в отличие от самодостаточного объекта, его цель — предоставлять безопасный интерфейс другим объектам для работы, то бишь он служит сервисом/инфраструктурой, не исполняя самостоятельно прикладных задач. Ну и нужен для того, чтобы его передавали друг-другу в процессе вычисления. Иногда такие контексты можно выносить даже в паблик. Например, в дотнете хватает объектов без публичных конструкторов и даже без публичных методов. Сценарий работы с этими объектами таков: его выдают клиентскому коду как результат работы некоей функциональности, но клиент должен использовать сии объекты для использования "потом". Конечно, инкапсуляция страдает, но это всегда, когда многошаговые операции приходится выполнять не нам, а клиентскому коду. Выход есть в DI, согласен, но не очень будет удобно, если наша либа будет требовать DI от клиента, ведь это лишнее идущее с либой ограничение. Могут не понять и взглянуть на решение конкурента.
Понятно, что это все еще ООП, но в котором идет сосредоточение не столько только на акторах, сколько на характере обмениваемых ими сообщений. Считай что идет агитация выносить состояния из статики в динамику, в большую россыпь мелких временных объектов, не имеющих самостоятельной ценности, но обеспечивающих инфраструктуру или представляющих собой целевые данные. Повторюсь, было лишь замечено, что если не пугаться глобальных (статических) ф-ий или функторов, то диагноз насчет необходимости сделать тот или иной сегмент какого-нибудь состояния таким "динамическим" получается как бы сам собой при попытке реализовать нужную функциональность.
>>Еще раз, объектная декомпозиция — это практически всегда разделение состояния, т.е. ухудшение инкапсуляции,
I>Что значит разделение состояния ? На примере.
Та бери любой. Навскидку — был у нас объект, отвечающий за сериализацию/десериализацию данных в файл или еще куда-нить. Потом добавляем версионность, делаем уже иерархию форматтеров под разные версии, и уже где-то рядом — менеджер-ресолвер форматтеров под разные версии. И сценарий использования десериализации во всех местах поменялся. Самый плохой случай, когда мы заинкапсулировали это все нафик, применив какой-нить поведенческий паттерн, чтобы внешний сценарий не менялся, а некий менеджер сделали статическим полем, который будет нам создавать внутренний класс, осуществляющий собственно десериализацию. Статическое поле — это косяк, может случиться так, что таки потребуется переработка потом именно в месте использования для отказа от глобального состояния. А теперь посмотри, что будет, если применить функциональную декомпозицию. Мы имеем некий контекст вычислений в клиентском месте, вызываем ф-ию для создания контекста десериализации из нужного файла, передавая текущий контекст как параметр, получаем сразу нужную реализацию контекста десериализации с правильным встроенным форматтером. При добавлении версий внешний сценарий не поменяется. В дотнете это сделано более-менее по уму. Умнее чем в Java, и как раз согласно проводимой здесь рекламе.
А в более прикладном уровне таких случаев вообще вагон и маленькая тележка. Имеем некие поля в прикладной области. Потом можем обнаружить, что некоторые сочетания полей встречаются не только в этой прикладной структуре, но и еще во многих, и по ним идут одинаковые/похожие операции. Конечно, выносим эти поля в одну внешнюю структуру или легковесный объект. Например, пара полей: "дата начала"/"дата конца" чего-либо. Можно создать легковесный тип Period, который либо сам содержит необходимые операции, либо, если этих операций много и они добавляются относительно децентрализовано, использовать его как ATD с минимумом собственных св-в, наращивая свободный хелперный функционал вокруг.
>>Вот эти меняющиеся информационные составляющие, да еще когда 90% из них временны и живут лишь до следующей переделки/рефакторинга — тоже немалая часть балласта в период разработки.
I>В ФП точно так же. В идеале хорошо бы в коде задавать аналитическое описание системы. Но факт в том, что начиная с определнного порога сложные системы уже невозможно описывать аналитически. До этого порога рулит ФП. После этого порога рулит уже ООП — как минимум согласовывать между собой всякие модули написаные как с ФП так и без него.
Ну я тоже как бэ высказался, что мне ООП удобнее. Речь все еще идет о подглядывании в удобные практики других методологий, а не о полном переходе на них. Тем более, что на самом верхнем уровне действительно сложных систем сейчас рулит КОП.
Re[6]: Почему объектно-ориентированное программирование пров
I>Устранять дублирование кода, реорганизовывать зависимости, обязанности все равно надо, независимо от того, что у тебя меняется функции или данные
Отличное замечание насчет дублирования кода. Вот она в разных объектах лично мною наблюдается чаще, из-за обилия приватной функциональности. В одном из проектов насчитывал до 11 внутренних методов, не самых тривиальных, делающих ровно одно и тоже. А предоставь первый же из них в публичный доступ, не завязанный на конкретную специфику использующего объекта, не было бы 10-ти клонов.
Re[9]: Почему объектно-ориентированное программирование пров
Здравствуйте, vdimas, Вы писали:
I>>Один из путей достижения этой цели — рефакторинг.
V>Рефакторинг по определению такие изменения, которые не меняют функционал. А когда надо именно менять функционал? Тогда приходится сначала рефакторить, потом уже менять функционал.
Рефакторинг это про наблюдаемое поведение,а не про функционал.
Если надо изменить фунционал, то меняй, сколько хочешь. Как правило, изменения чередуются с рефакторингом.Более того, отделить толком рефакторин от собственно внесения изменений достаточно трудно.
>Рефакторинг тоже имеет свою трудоемкость, и если его надобность однозначно определяется самим фактом развития функциональности, то что-то здесь не так.
Все так — трудоемкость внесения изменений без рефакторинга выше, чем с рефакторингом. Разница это Затраты на дебаг, сопровождение, последующие модификации.
V>Если действительно не сможешь закрыть, то поверь, на это же выйдешь с "другой стороны" — постепенно уменьшая инкапсуляцию. А если принципиальная возможность согласно функциональности есть — то она достижима в одну итерацию рефакторинга.
Ну и дела Откуда ты вывел эту одну итерацию ? И ежу понятно, что придешь к одному результату. Только в одном случае у тебя может появиться n-пользователей твоего открытого кода, а в другом случае их не появится.
Ну, как пример, АПИ какого фреймворка, который разрабатывается по стадиям а не в один заход. Если изначально раскрыть слишком много деталей, то есть шанс что фреймворк никогда не будет дописан
I>>Что значит разделение состояния ? На примере.
V>Та бери любой. Навскидку — был у нас объект, отвечающий за сериализацию/десериализацию данных в файл или еще куда-нить. Потом добавляем версионность, делаем уже иерархию форматтеров под разные версии, и уже где-то рядом — менеджер-ресолвер форматтеров под разные версии. И сценарий использования десериализации во всех местах поменялся. Самый плохой случай, когда мы заинкапсулировали это все нафик, применив какой-нить поведенческий паттерн, чтобы внешний сценарий не менялся, а некий менеджер сделали статическим полем, который будет нам создавать внутренний класс, осуществляющий собственно десериализацию.
Ты кажется изобрел зависимости и обязанности
Re[7]: Почему объектно-ориентированное программирование пров
Здравствуйте, vdimas, Вы писали:
I>>Устранять дублирование кода, реорганизовывать зависимости, обязанности все равно надо, независимо от того, что у тебя меняется функции или данные
>В одном из проектов насчитывал до 11 внутренних методов, не самых тривиальных, делающих ровно одно и тоже. А предоставь первый же из них в публичный доступ, не завязанный на конкретную специфику использующего объекта, не было бы 10-ти клонов.
Без конкретного примера этих нетривиальных методов говорить не о чем.
Лично мне всегда стремно выносить нетривиальный метод в публичный доступ, ибо получается монолит с которым работать еще хуже чем с десятков клонов.
Re[10]: Почему объектно-ориентированное программирование про
Здравствуйте, Ikemefula, Вы писали:
V>>Та бери любой. Навскидку — был у нас объект, отвечающий за сериализацию/десериализацию данных в файл или еще куда-нить. Потом добавляем версионность, делаем уже иерархию форматтеров под разные версии, и уже где-то рядом — менеджер-ресолвер форматтеров под разные версии. И сценарий использования десериализации во всех местах поменялся. Самый плохой случай, когда мы заинкапсулировали это все нафик, применив какой-нить поведенческий паттерн, чтобы внешний сценарий не менялся, а некий менеджер сделали статическим полем, который будет нам создавать внутренний класс, осуществляющий собственно десериализацию.
I>Ты кажется изобрел зависимости и обязанности
Опять не туда смотришь. Это как чтение журнала "Здоровье" в советские годы. Читать не рекомендовалось, або каждый начинал находить у себя те или иные симптомы. Так и ты, видать начитался намедни.
Прочисть сознание, плиз. Разумеется, мы ищем зависимости и раздаем роли (обязанности), и не только в ООП. Я упоминал, что сия раздача элементам нашей программы обязанностей — недетерминированный ни в коем случае процесс, а зависит более от точки зрения на проблему. В общем, зависит от построенной модели происходящего. И способов решения одной и той же задачи достаточно высокого уровня обычно великое множество. Это, повторюсь, было упомянуто в первом же посте в этой ветке, чтобы было понятно, о чем именно пойдет речь. Предлагаются лишь альтернативные общепринятым в ООП точки зрения, путем кражи практик из функциональной декомпозиции и обсуждаются бенефиты. Вот и все.
Re[11]: Почему объектно-ориентированное программирование про
Здравствуйте, vdimas, Вы писали:
I>>Ты кажется изобрел зависимости и обязанности
V>Опять не туда смотришь. Это как чтение журнала "Здоровье" в советские годы. Читать не рекомендовалось, або каждый начинал находить у себя те или иные симптомы. Так и ты, видать начитался намедни.
Ты бы писал не простынями, а короткими понятными фразами
V>Прочисть сознание, плиз.
<> — сестра таланта ?
>Разумеется, мы ищем зависимости и раздаем роли (обязанности), и не только в ООП. Я упоминал, что сия раздача элементам нашей программы обязанностей — недетерминированный ни в коем случае процесс, а зависит более от точки зрения на проблему. В общем, зависит от построенной модели происходящего. И способов решения одной и той же задачи достаточно высокого уровня обычно великое множество. Это, повторюсь, было упомянуто в первом же посте в этой ветке, чтобы было понятно, о чем именно пойдет речь. Предлагаются лишь альтернативные общепринятым в ООП точки зрения, путем кражи практик из функциональной декомпозиции и обсуждаются бенефиты. Вот и все.
И таки ты изобрел зависимости и обязанности и назвал это "разделением состояния".
Re[14]: Почему объектно-ориентированное программирование про
Здравствуйте, AndrewVK, Вы писали:
AVK>Глупость ты написал. Такое ощущение, что ты пытаешься своими терминами и не очень понятными образами выразить азбучные истины.
Увы, ничего не меняется. Разве хоть одно обсуждение с тобой заканчивалось по-другому? Вставить некую истину, обозвав оппонента дураком, ну как отказать себе в этом удовольствии?
AVK>Любой дизайн стремится к минимизации связности (coupling) и максимизации зацепления (cohesion). Соотв. любая декомпозиция в идеале должна уменьшать первое, сохраняя на приемлемом уровне второе. Любая.
Ты всерьез сейчас утверждаешь, что декомпозиция всегда производится с целью минимизации связанности и максимизации зацепления? И кто тут пишет глупости?
Ну и процитировал ты фразу про ухудшение инкапсуляции, да еще в неоконченном виде. Какая связь с твоей репликой? Не хочешь в свою очередь по Бучу освежить?
AVK>Скажи честно, ты Буча давно перечитывал?
Скажи честно, ты ведь по диагонали форум читаешь? Рассматриваемая причина декомпозиции была упомянута практически в каждом посте. Как и Бучем (надеюсь ты об этой книге?)
При проектировании сложной программной системы необходимо разделять ее на все меньшие и меньшие подсистемы, каждую из которых можно совершенствовать независимо. В этом случае мы не превысим пропускной способности человеческого мозга: для понимания любого уровня системы нам необходимо одновременно держать в уме информацию лишь о немногих ее частях (отнюдь не о всех). В самом деле, как заметил Парнас, декомпозиция вызвана сложностью программирования системы, поскольку именно эта сложность вынуждает делить пространство состояний системы.
Коллега, стоило ли так торопиться, путая причины проведения некоей декомпозиции с критериями оценки её удачности?
Ну и главное, связанность это относительная метрика. Фактически, сложность системы при декомпозиции повышается, за счет снижения сложности составных частей и уменьшения этой относительной метрики связанности. А эффект снижения сложности при декомпозиции происходит лишь в клинических случаях, например при обнаружении несвязанного функционала, механически объединенного через объединение состояний в некоем элементе/объекте. Сорри, конечно, но я позволил себе исходить из того, что сии ошибки дизайна мы рассматривать не будем. Хотя бы чтобы не предполагать, что читатель обязательно идиот.
Ну и "гвоздевой" рассматриваемый случай по всей ветке, когда состояние невозможно декомпозировать, но со сложностью функционала побороться охота, ты старательно избегаешь, комментируя частности и вырезки из контекста. Более того, предлагалось намеренно ухудшать инкапсуляцию, и сей момент обговаривается особо. Да и ссылку знакомую уже давали: http://www.softcraft.ru/coding/sm/sm01.shtml Хотя много лет назад мы это уже обсуждали, при участии Павла Кузнецова, и я твое мнение на этот счет помню. Похоже, все остались при своих.
Re[9]: Почему объектно-ориентированное программирование пров
Здравствуйте, vdimas, Вы писали:
V>Увы, ничего не меняется. Разве хоть одно обсуждение с тобой заканчивалось по-другому? Вставить некую истину, обозвав оппонента дураком, ну как отказать себе в этом удовольствии?
Ну понятно, проблема во мне. Тебе, правда, другие то же самое пишут, но это тоже в них проблема. Истинный гуру здесь, понятно, один.
V>Ты всерьез сейчас утверждаешь, что декомпозиция всегда производится с целью минимизации связанности и максимизации зацепления?
Не с целью, а с учетом.
V>Коллега, стоило ли так торопиться, путая причины проведения некоей декомпозиции с критериями оценки её удачности?
Я как раз ничего ен путаю. Но то, что ты начал цеплятся к словам — показательно.
... << RSDN@Home 1.2.0 alpha 5 rev. 1495 on Windows 7 6.1.7600.0>>
Здравствуйте, Ikemefula, Вы писали:
I>Без конкретного примера этих нетривиальных методов говорить не о чем.
Было связано с обработкой строк. Как раз занимался тем, что писал специальную либу под прикладную задачу для целей обработки строк, вынося каждый частный случай из привата объектов.
I>Лично мне всегда стремно выносить нетривиальный метод в публичный доступ, ибо получается монолит с которым работать еще хуже чем с десятков клонов.
Дык, функциональная декомпозиция тоже бывает. Нетривиальный метод, по мере обобщения, считай что будет "точкой входа" и/или композицией более тривиальных шагов. Тут задача в повышении повторного использования кода, ибо для работы над таким кодом выделяется больше ресурсов, такой код имеет шанс выйти надежнее и эффективнее, чем каждое уникальное решение "по месту".
Re[12]: Почему объектно-ориентированное программирование про
Здравствуйте, AndrewVK, Вы писали:
V>>В плюсах КОП в чистом виде накладен.
AVK>Это личные проблемы плюсов.
Дык, для коробочного продукта под десктоп и это и есть мейнстрим. Хотя не суть.
AVK>>>Конечно же нет. Во-первых реализация интерфейсов нужна исключительно для полиморфизма, что к КОП имеет весьма опосредованное отношение.
V>>Тем не менее, полиморфизм в КОП так же доступен и используется так же.
AVK>Но не является обязательной частью, в отличие от.
Если вспомнить твои размышления, что интерфейс рассматривается как контракт, то тут вообще вид полиморфизма от реализации языка зависит. Например, утиный тоже подойдет. Как и для реализации КОП, однофигственно. ИМХО, полиморфизм при использовании интерфейсов не цель, а лишь "двоичная" техника обеспечения контракта для некоторых языков из мейнстрима. Кстати, накладывающая свои ограничения, например, на явную зависимость от типа-контракта (об этом еще пройдусь ниже подробнее). Например, для библиотек шаблонов С++ порой подходит другой вид полиморфизма и есть возможность отвязаться от зависимости на конкретные типы.
AVK>У нас что, иерархии FW уже идеальный образец? Косяков дизайна там примерно столько же, сколько в большинстве более менее приличного промышленного кода в среднем.
Склоняюсь, что не всегда "случайный" косяк, а намеренно из соображений эффективности. В дотнете виртуальный метод класса быстрее вызывается и доступен для оптимизации в обычный вызов и даже в инлайнинг, если компилятор "видит" жизненный цикл объекта. В случае интерфейсов это не работает.
AVK>Количество связей есть функция от качества дизайна. А качество дизайна завист в том числе и от количества и качества рефакторингов.
Это если предположить, что простое применение рефакторинга само по себе обеспечивает качество дизайна. А это зависит от.
Ну и не отрицался рефакторинг вообще, а предполагалось уменьшить его объем для случаев, если декомпозиция производится исключительно для борьбы со сложностью. А не исключить его как таковой, например для случая обнаруженного архитектурного косяка или возможных улучшений.
V>> "простой" рефакторинг базовой функциональности может потянуть за собой много изменений, не поддающихся автоматическому рефакторингу
AVK>Это именно то, о чем я и говорю — если забить на рефакторинг, то связность будет расти, и, как следствие, любое изменение кода, не только рефакторинг, будет обходится все дороже и дороже.
Вот. Одно из решений по уменьшению роста связанности ты предложил. Я предлагал рассмотреть еще одно решение. И оно тоже работает. Тем более, что по факту от рефакторинга никто не отказывается. Он все равно неизбежен, ведь косяки в дизайне допускают все, надо лишь уметь их находить и исправлять. Просто на плюсах к рефакторингу подходишь, как бы это сказать... тщательнее, продуманнее, с подготовленным списком изменений. Бо трудоемко. И сей факт наталкивает на поиски путей минимизации общей требуемой трудоемкости, и путей избежания лишнего рефакторинга в т.ч.
AVK>Только какое это имеет отношение к тому, что ООП приводит к усложнению рефакторинга? Ты считаешь, что ООП решения всегда более связные, нежели чисто структурные?
Нет, я считаю, что в ООП первоначальное решение обычно дальше всех от конечного, чем в какой-либо другой технике. Т.е. путь трансформации кода заведомо больше. Полезный исполняемый код некоего функционала может поменять много классов-владельцев до релиза. Каждый раз "немного" модифицируясь. Потому как современное ООП тяготеет к проектированию "сверху" статической архитектуры. И популярные ООП-метрики по большей части — статические. И про чисто структурные решения никто не говорил. Просто предлагается техника, согласно которой, всё, что можно сделать вне объекта — лучше делать вне объекта. А в особом, упомянутом не раз в этой ветке случае, я даже настаиваю, что это самая хорошая идея. Характерно, что речь не только о свободном функционале как таковом, но и о проектировании АПИ объектов под ф-ии и функторы. Т.е. под "DI с одним методом". В классическом ООП нам нужно приседать, чтобы получить DI, т.е. разрабатывать дополнительные DI-интерфейсы, увеличивая суммарную сложность проекта. А тут вместо расписывания иерархии и интерфейсов — отгородились сигнатурой функционального объекта, на этом вся абстракция и закончилась. Ты же сам охотно используешь делегаты и лямбды там, где в их отсутствие потребовалось бы городить уникальный интерфейс "по месту"? Просто утверждение, что ФП рулит только на маленьких задачах — неверное. Хорошие практики рулят на любом уровне сколь угодно большой иерархии. В данном случае, ориентирование дизайна на DI с интерфейсами в один-пару методов позволяет уйти от россыпи интерфейсов и их классов-реализаций (пусть простейших), т.е. обойти искуственно вводимое в статически-типизированных языках ограничение на конкретный применимый тип интерфейса, использовав вместо него сигнатуру нужного функтора, ну или небольшой тупл из оных. В подобных сценариях, если брать метрику связанности, то классическое ООП, мягко говоря, сосет на нагибаясь. Хотя "все остальное" может быть выполнено с использованием ООП, но описанная вещь за рамки ООП выходит. Зато экономит кол-во разрабатываемых/оперируемых типов в несколько раз.
V>>Было сказано "более удачный". Речь шла о выявлении наиболее частоупотребимых сценариев на уровне анализа, сие помогает выявить функциональность с наибольшим повторным использованием. И это нужно для меньшей болезненности описанного абзацем выше.
AVK>Я только не понимаю, почему ты агитируешь за крайности? Нужно искать баланс между предварительным проектированием и доработками по ходу создания. В каждом случае он разный, универсального и хорошо работающего рецепта нет, чтобы не утверждали адепты обеих крайностей.
Крайность — это предварительное написание системы на "кончике пера". От этого давно отказались даже в IBM. Я пока вижу противоположную крайность — сразу разработку высокоуровневых иерархий и выход на список сценариев лишь в процессе. А такое "в процессе" может потребить само по себе прилично трудоемкости, и автоматическим рефакторингом с помощью даже современных утилит не всегда разруливается, приходится ручками приседать. Можно сказать, что я хитрю: предлагая бенефит, в виде экономии на необходимом рефакторинге, предлагаю посмотреть на программу с т.з. потоков обрабатываемых данных. То бишь, продвинуться всего на один шаг дальше проектирования статической архитектуры. По сравнению с культурой проектирования хотя бы 15-летней давности, это просто уровень "0" предварительного анализа.
V>> И это мы еще не договорились, что есть тяжелые, а что нет. По мне, проблема — это когда вокруг обсуждаемого состояния очень много функциональности. Т.е. проблемы по связанности начинаются уже внутри объекта, а не за его пределами. а этой функциональности может быть много просто по характеру предметной области.
AVK>Функциональности обычно всегда много. Надо уметь ее хорошо декомпозировать. Это все банальности.
Опять 25. ООП декомпозиция пляшет от декомпозиции состояния. Даже метрика "виртуального метода" идет от него идет. Можно сто раз уметь, но коль состояние недекомпозируемо в принципе (для некоторой конкретики), ООП декомпозиция не работает. Нужны другие практики, если все еще хотим бороться с этой сложностью.
AVK>Этого гарантированно нельзя добиться в сколько нибудь автоматическом режиме. Именно это чуть менее чем полностью определяет интеллектуальное наполнение большинства современных продуктов (за исключением вещей с уникальной алгоритмикой, но таких сейчас очень мало).
Кач-во кода и полнота/удобство функциональности тоже определяют. Обычно кривые внутри, но хорошо отлаженные продукты продаются всяко лучше, чем наоборот. Хотя, будучи перфекционистом по натуре, это я скорее себе должен регулярно повторять, чем кому-то.
AVK>И именно поэтому сия область состоит чуть более чем полностью из эвристик и представлений о правильном.
Сие тоже упоминалось, справедливости ради. Как и то, что эвристики не всегда уникальны, а иногда очень неплохо воспроизводимы, особенно на похожих по характеру проектах. Например, там где упор на обработку/трансформацию информации, надо приоритеты "эвристики" расставлять соответственно. Т.е. смотреть на проблему с соотв. точки зрения. Например, строить модель ПО, отталкиваясь от динамики, и выходя на его статическую архитектуру как следствие удовлетворения нужд динамики. Чем не хорошая "эвристика"?
А высказался столь пространно по теме (уже завязываю тут, сорри), потому как чуть менее, чем всегда (С) вижу ОО-проектирование, пляшущее исключительно от статической архитектуры. И даже деплой заранее расписывается, до первой строчки кода, угу. ИМХО, такая "эвристика" только вредит. И... требует больше рефакторинга.
V>> Выделяя некое состояние как "данные", мы фиксируем безопасный "интерфейс" доступа к данным, оставляя на свободе функционал вокруг них. AVK>КО? Это все здорово, но это только декларация. Примитив. А на практике есть огромная куча деталей.
Мы года 4-5 назад об этом спорили, все остались при своих. Я вспомнил этот момент лишь по причине удобства оперирования подобной функциональностью на всех уровнях, не прибегая к рефакторингу каждый раз для тюнинга текущей степени абстракции/инкапсуляции.
AVK>Не, ты всерьез веришь, что для борьбы со связностью достаточно такого простенького правила?
Через единицы лет нам будет по 20 лет рабочего стажа. Фигли тут спрашивать заведомую ерунду? Тем паче, что сложность — величина абсолютная, а связанность — относительная. Не ты ли делал замечание насчет понимания, что не всегда O(n) хуже чем O(n^2)? Из той же оперы, всегда зависит от частностей.
Не верю ничему, если вопрос был про веру.
V>> И вот это множество, составляющее функционал, само по себе выходит слабо м/у собой связанным. Дело в том, что полно ситуаций, когда набор данных меняется редко (не путать с добавлением других данных), а вот операции, даже по устаканенным данным, пересматриваются/уточняются часто.
AVK>Ты вообще это серьезно? Мне казалось, что азбучные истины для всех участников топика очевидны. Если ты пытаешься сказать, что уменьшение связности благотворно сказывается на сложности изменений, то это и так всем понятно. Только при чем тут ООП?
Обсуждались пути кратчайшего выхода на эту наименьшую связанность. А насчет очевидностей и прочего. Или как ты говорил "дизайн управляется тем-то и тем-то, идите читайте классиков". Он не управляется метриками, по справедливости говоря, а оценивается. Это немаловажный момент, механически применимых правил нет, и даже ты в этом согласился. ИМХО, степень этого "управления" зависит от кол-ва шагов (грубо), на которые разработчик способен заглянуть вперед. Вот обсуждается возможность саму последовательность работ построить так, чтобы заглядывание вперед происходило на большее число шагов "само", лишь как следствие перетасовки последовательности работ. Это окупается, если над проектом одновременно работает заметное число людей, бо изменения архитектуры не бесплатны. У людей копится багаж знаний о собственном проекте, а после очередного "глобального" рефаторинга все оказывается "черти где" на их взгляд. Начиная от самих файлов с кодом, над которыми они работали накануне, и которые теперь перименовались вместе с типами и даже лежат в другом проекте. Повторюсь, это всегда при совместной разработке болезненно, поэтому такой рефакторинг стоит планировать и делать его эффективным, т.е. делать большее кол-во полезных изменений за меньшее число подходов. А так же использовать любые пособы для снижения надобности в нем. И уж тем более, постараться избавиться от надобности оного просто в ответ на рост сложности. Не обратил внимание, что чем больше людей участвует в каких-нить открытых проектах, тем более скупые идут диффы минорных версий? Не от хорошей жизни.
Понятное дело, что меньше связанность — меньше проблем. Это действительно банальность, и такой вывод можно сделать, лишь читая ветку по диагонали. Хотелось обсудить, как на эту меньшую связанность выйти за меньшее кол-во шагов (переделок). И почему это должно сработать.
Повторю, тут мы по-любому можем обсуждать каждый свой субъективный опыт. Последние годы мне приходилось работать над обработкой сигналов, данных, диспатчингом десятков-сотен тысяч сообщений в секунду и т.д. В общем, вопросами эффективной обработки информации. И было замечено, что заведомое сосредоточение на подробностях прикладной обработки данных (фактически анализ одновреемнно с полезной разработкой) дает бенефиты, в сравнении с привычной разработкой архитектуры сверху. Но бенефиты наработок проявляются только в том виде, в каком можно потом эти наработки использовать в различных сочетаниях без надобности тюнинга/переделки "иерархий" под конкретные сценарии использования. Способ сей декомпозиции озвучен, и он не совсем в духе ООП. Хотя используются ООП языки и пости все пользовательские типы оформлены в виде классов. Это так же нельзя назвать разработкой снизу, как тут пытались упростить происходящее, т.к. этапы обработки данных тоже удобно разрабатывать, начиная от крупных этапов с постепенным уточнением частностей, т.е. классический нисходящий итерационный процесс удобен и тут. Это просто отталкивание от потоков данных, т.е. динамики, а не от статической архитектуры и списка "действующих лиц". Получавшаяся затем меньшая надобность рефакторинга — лишь замеченный эффект, и то далеко не сразу. Причем, замеченный не только на плюсах, бо системы гетерогенные.
Ну и последнее замечание насчет "очевидности". Это для тебя может быть уже все давно очевидно, и столкнувшись с подобными задачами, ты бы может и пришел бы к похожим наблюдениям довольно быстро... Но мне тут на "заумность" пеняли буквально в соседнем топике, хотя речь шла о куда как более простых вещах. Так что сорри, но порой надо на пальцах.
За сим позволю себе закруглиться, або 5-й раз по кругу.
Re[12]: Почему объектно-ориентированное программирование про
Здравствуйте, Ikemefula, Вы писали:
I>И таки ты изобрел зависимости и обязанности и назвал это "разделением состояния".
Таки нет. Декомпозиция состояния — это и есть декомпозиция в стиле классического ООП. Ты опять всё напутал. Зависимости ни изобретаются — они получаются, мы можем лишь пытаться улучшить их относительное кол-во. Ну а насчет обязанностей? В рамках ООП лучше говорить — "ролей". Вот их приходится изобретать, это да, в этом ООП-анализ и состоит. Но не про это было и близко. Ты не понял ни строчки обсуждения, сорри.
Re[9]: Почему объектно-ориентированное программирование пров
Здравствуйте, vdimas, Вы писали:
I>>Лично мне всегда стремно выносить нетривиальный метод в публичный доступ, ибо получается монолит с которым работать еще хуже чем с десятков клонов.
V>Дык, функциональная декомпозиция тоже бывает. Нетривиальный метод, по мере обобщения, считай что будет "точкой входа" и/или композицией более тривиальных шагов. Тут задача в повышении повторного использования кода, ибо для работы над таким кодом выделяется больше ресурсов, такой код имеет шанс выйти надежнее и эффективнее, чем каждое уникальное решение "по месту".
Ты по моему сравниваешь плохое vs хорошее При чем здесь по месту ? Как ты будешь тестировать свой нетривиальный метод ? Повторное использование это круто, но не тогда когда это монолит.
Re[13]: Почему объектно-ориентированное программирование про
Здравствуйте, vdimas, Вы писали:
V>Здравствуйте, Ikemefula, Вы писали:
I>>И таки ты изобрел зависимости и обязанности и назвал это "разделением состояния".
V>Таки нет. Декомпозиция состояния — это и есть декомпозиция в стиле классического ООП.
Ну тогда напримере паттернов враппер, адаптер, прокси, суррогат, декоратор поясни, где тут разделение состояния.
Re[15]: Почему объектно-ориентированное программирование про
Здравствуйте, vdimas, Вы писали:
I>>Ну тогда напримере паттернов враппер, адаптер, прокси, суррогат, декоратор поясни, где тут разделение состояния.
V>Адаптер — это не декомпозиция, а наоборот — композиция, т.е. усложнение. Структурные паттерны решают вопросы совместимости интерфейсов в системе статической типизации за счет дополнительных посредников.
Правильно тебя понял, ты не можешь придумать примера когда использование обозначеных паттернов будет являться декомпозицией системы ?
Re[13]: Почему объектно-ориентированное программирование про
V>>Так и запишем. Примера программы, не являющейся моделью, нет. G> G>Не сливай так откровенно. Ты задавал вопрос, ты не захотел искать хотя я ответ давал.
Давай попробуем слова, типа "слил" оставлять в СВ? Возможно кому-то и давал. Мне мог дать хотя бы ключевую фразу для поиска этого поста через гугл... ты же совсем оторвался от реальности, требуешь прочесать нехилый топик.
G>Ну хватит уже выкручиваться. Нету определения абстрактного интерфейса.
Все-таки, посмотреть когда и как упоминается точное совпрадение по фразе мы не хотим?
В общем, дабы закрыть эту бодягу, хоть я и надеялся на озарение и даже дал все подсказки...
Есть определение "абстрактного метода" и "интерфейса класса". Последнее, если обратил внимание, не есть нечто неделимое, это — совокупность публичных членов класса. Члены интерфейса класса могут быть абстрактными, а могут быть и нет. Когда кто-то говорит об абстрактном интерфейсе класса, имеется ввиду его публичный интерфейс или его часть, представленная абстрактными членами. Но это же длинно в написании, согласись? ИМХО, для коллег понятен и более короткий вариант.
V>>Ты уже 10-й пост демонстрируешь, что путаешь понятие "интерфейс" с особым типом и ключевым словом конкретного языка. Воистину, вот и выросло next generation. ИМХО, остальное обсуждать бессмысленно, пока не сдвинемся с этой мертвой точки. G>Так я и говорю, ты приведи в порядок терминологию, чтобы я или кто-то другой не путал твои понятия интерфейсов.
Т.е., ты противишься термину "интерфейс класса"? Даже сейчас? Сколько тебе еще надо итераций?
V>>Я писал для случая больших иерархий. Т.е. пример с небольшими иерархиями ничего не подтверждает, а всего-лишь неподходит. G>Так приведи пример, который подтверждает твои слова.
Приводил, AWT в Java.
V>>Ну и, они таки есть, эти большие иерархии, в прикладных либах дотнета, хоть и используется больше техника абстрактных классов, чем интерфейсов. G>Но мы говорили про интерфейсы.
G>Ты пытался увести тему разговора. Что бы ты не забыл напомню твое утверждение: что имеют смысл большие иерархии интерфейсов. G>Это утверждение с практикой расходится, никто не создает такие иерархии, они никому не нужны.
Как ты определил "большую иерархию"? В глубину, или в ширину? Иерархия объектов — мы же имеем дело не с одной иерархией наследования, обычно под "иерархией" сокращенно понимают все иерархии взаимодействующих объектов/интерфейсов.
Ну а что именно говорилось, пожалуй напомню:
Рациональное зерно в наследовании абстрактных интерфейсов для построения объектной иерархии разумеется есть. И чем больше иерархия, тем больше в этом смысла. Мы избавляем такую иерархию от подробностей реализации составляющих её элементов, т.е. банально уменьшаем информационную сложность иерархии.
Еще раз — допустим, что полная система иерархий всех оперируемых объектов большая. Выписываем ее только на интерфейсах — получаем маааленькую.
Так понятно? Или еще на один круг пойдем?
Примеры из дотнета? — мильон. Бери интерфейсы из System.Linq: IGrouping<>, ILookup<>. Глубина иерархии наследования — 3, наследников членов иерархии — не счесть. И это еще глубоко, бо на интерфейсах как раз в 1 уровень выписывать все связи обычно получается.
G>Я все видел много раз. А ты мог бы привести пример "показательного использования", а не писать пустые слова.
Коллега, ты просто образец лени. Были же даны все ключевые слова, по которым в гугле за два клика оказываемся тут: java.awt.peer diagram
На случай, если и там нужной иерархии интерфейсов не найдешь, вот одна из первых ссылок: http://www.webbasedprogramming.com/Java-Unleashed-Second-Edition/fb-12.gif Ну и на случай, если опять что-то не понятно, это именно интерфейсы. В Java не принято начинать идентификаторы интерфейсов через I.
Re[16]: Почему объектно-ориентированное программирование про
Здравствуйте, Ikemefula, Вы писали:
V>>Адаптер — это не декомпозиция, а наоборот — композиция, т.е. усложнение. Структурные паттерны решают вопросы совместимости интерфейсов в системе статической типизации за счет дополнительных посредников.
I>Правильно тебя понял, ты не можешь придумать примера когда использование обозначеных паттернов будет являться декомпозицией системы ?
Если под обозначенными ты понимаешь структурные, то я уверен, что и ты не сможешь. Попытайся, опровергнуть, будет любопытно посмотреть.
Если не получится — не беда:
Структурные паттерны решают вопрос о том, как из уже имеющихся классов и объектов оптимально получить более крупные структуры и образования.
Re[17]: Почему объектно-ориентированное программирование про
Здравствуйте, vdimas, Вы писали:
V>>>Адаптер — это не декомпозиция, а наоборот — композиция, т.е. усложнение. Структурные паттерны решают вопросы совместимости интерфейсов в системе статической типизации за счет дополнительных посредников.
I>>Правильно тебя понял, ты не можешь придумать примера когда использование обозначеных паттернов будет являться декомпозицией системы ?
V>Если под обозначенными ты понимаешь структурные, то я уверен, что и ты не сможешь. Попытайся, опровергнуть, будет любопытно посмотреть.
Ты не увиливай. Твои слова "Еще раз, объектная декомпозиция — это практически всегда разделение состояния".
Здравствуйте, Ikemefula, Вы писали:
V>>Если под обозначенными ты понимаешь структурные, то я уверен, что и ты не сможешь. Попытайся, опровергнуть, будет любопытно посмотреть.
I>Ты не увиливай. Твои слова "Еще раз, объектная декомпозиция — это практически всегда разделение состояния".
Дык, ты спросил про структурные паттерны, я ответил.
I>код ниже, покажи, где там разделение состояния.
Никто пока не увиливает, ты лишь сумбурно задаешь вопросы.
Давай разберем твой пример. Итак, для начала введем состояние в первоначальный объект, прежде чем делать выводы. Это поможет понять происходящее, выявить связи. Вот есть твои методы PreDo() и PostDo(). Они требовали для своей работы каких-то внутренних полей первоначального класса Doer? Если требовали, то тебе надо обеспечить доступ к этим полям в новом объекте PreAndPostDoerDecorator, ЧТД. Если не требовали, то что они делали в этом классе? Если же подразумевалось некое "внешнее глобальное состояние", то нам его надо ввести в модель в виде некоего объекта в одном экземпляре и сослаться на него из использующих классов. Но ЧТД остается при этом в силе, потому как после декомпозиции этой ссылкой будет владеть PreAndPostDoerDecorator.
В общем, давай попытку №2, это будет полезно.
Re[19]: Почему объектно-ориентированное программирование про
Здравствуйте, vdimas, Вы писали:
V>>>Если под обозначенными ты понимаешь структурные, то я уверен, что и ты не сможешь. Попытайся, опровергнуть, будет любопытно посмотреть.
I>>Ты не увиливай. Твои слова "Еще раз, объектная декомпозиция — это практически всегда разделение состояния".
V>Дык, ты спросил про структурные паттерны, я ответил.
Т.е. под объектной декомпозицией ты имел ввиду все случаи декомпозиции кроме использования структурных паттернов ?
I>>код ниже, покажи, где там разделение состояния.
V>Никто пока не увиливает, ты лишь сумбурно задаешь вопросы.
V>Давай разберем твой пример. Итак, для начала введем состояние в первоначальный объект, прежде чем делать выводы.
Не надо ничего вводить State+Flyweight тоже состояние требуют ?
>Это поможет понять происходящее, выявить связи. Вот есть твои методы PreDo() и PostDo(). Они требовали для своей работы каких-то внутренних полей первоначального класса Doer?
Разумеется не требовали и это элементарно.
>Если требовали, то тебе надо обеспечить доступ к этим полям в новом объекте PreAndPostDoerDecorator, ЧТД.
Во первых, не требовали. Во вторых, они могут пользоваться методами базового класса
>Если не требовали, то что они делали в этом классе?
Это ж элементарно — мне надо изменить поведение некоторый реализаций не переписывая все разновидности и клиенты IDoer
Re[20]: Почему объектно-ориентированное программирование про
Здравствуйте, Ikemefula, Вы писали:
I>Т.е. под объектной декомпозицией ты имел ввиду все случаи декомпозиции кроме использования структурных паттернов ?
Согласно определению, структурные паттерны осуществляют композицию.
I>Не надо ничего вводить State+Flyweight тоже состояние требуют ?
Да, паттерн State требует введения нового поля, хранящего объект-state как минимум. Ну и еще каждый объект, представляющий этот State может иметь собственные поля. В любом случае, само состояние кодируется, даже без случая полей в объектах-state, и это закодированное состояние — суть ссылка на некую таблицу виртуальный ф-ий.
Flyweight вообще к структуре объекта не имеет отношение, это просто техника кеширования экземпляров.
>>Это поможет понять происходящее, выявить связи. Вот есть твои методы PreDo() и PostDo(). Они требовали для своей работы каких-то внутренних полей первоначального класса Doer?
I>Разумеется не требовали и это элементарно.
Нет, не элементарно. Если не было зависимостей прямых или косвенность от состояния, то им нечего было делать в объекте.
>>Если требовали, то тебе надо обеспечить доступ к этим полям в новом объекте PreAndPostDoerDecorator, ЧТД.
I>Во первых, не требовали. Во вторых, они могут пользоваться методами базового класса
Тогда нам придется рассматривать и состояние базового класса тоже и необходимость его декомпозиции в т.ч. Все эти ООП-наработки работают до любой глубины иерархии.
ОК, пусть будет базовый класс DoerBase и мы имеем такую иерархию до:
Doer <= DoerBase
В приведенном примере так или иначе придется обосновать наличие методов PreDo()/PostDo(), пусть даже через зависимости в базовом классе. Я лишь хочу показать, что эти зависимости рано или поздно должны выйти на состояние объекта. Мы же не можем в этих методах брать данные ниоткуда или ничего не делать (иначе такие методы были бы не нужны).
А потом мы построим полный граф зависимостей, пусть даже через предложенное тобой усложнение — базовый класс. Поверь, абсолютно ничего не изменится. Далее тебе придется показать, что полностью сохраняется зависимость Doer от DoerBase, а не от некоторой его части. Т.е., может получиться так, что согласно всем критериям дизайна, уместным будет декомпозировать этот DoerBase на просто DoerBase и PreAndPostDoerDecoratorBase. По крайней мере, из твоего примера пока следует, что это будет отличная идея, ведь тогда мы можем похожим образом применить сей аспект к другому типу объектов, скажем, Doer2.
Вариант №2.
Класс DoerBase нам недоступен для модификации, например идет из либы. Обсуждать нечего. Собсно, этот вариант и обслуживают структурные паттерны, позволяя создавать разной степени удачности композиции из закрытых реализаций.
Re: Почему объектно-ориентированное программирование провали
Здравствуйте, Игорь САВЧУК, Вы писали: ИС>Попробуем разобраться и ответить на главный вопрос, почему всё же объектно-ориентированное программирование провалилось?
а ты точно знаешь, что оно уже провалилось?
Sergey
Re[21]: Почему объектно-ориентированное программирование про
Здравствуйте, vdimas, Вы писали:
I>>Т.е. под объектной декомпозицией ты имел ввиду все случаи декомпозиции кроме использования структурных паттернов ?
V>Согласно определению, структурные паттерны осуществляют композицию.
То есть когда один объект был разделен на две части это композиция ?
А когда один объект с разделяется на две части с разделением состояния, это декомпозиция ?
Ну и дела
I>>Не надо ничего вводить State+Flyweight тоже состояние требуют ?
V>Да, паттерн State требует введения нового поля, хранящего объект-state как минимум.
Необязательно. Тебе никто не мешает создавать инстанс когда придется и вычислять нужный экземпляр. Скажем в парсере так и будет зачастую.
I>>Разумеется не требовали и это элементарно.
V>Нет, не элементарно. Если не было зависимостей прямых или косвенность от состояния, то им нечего было делать в объекте.
Опаньки — сначала было состояние, а теперь уже зависимости
I>>Во первых, не требовали. Во вторых, они могут пользоваться методами базового класса
V>Тогда нам придется рассматривать и состояние базового класса тоже и необходимость его декомпозиции в т.ч. Все эти ООП-наработки работают до любой глубины иерархии.
Ну так нет разделения состояния наследник может вообще не знать про состояние базового, а только вызыват метод базового.
V>В приведенном примере так или иначе придется обосновать наличие методов PreDo()/PostDo(),
Очень интересно — ты придумал вариант для своего определения а вариант, котоырй под твое определение не походит взял и не стал обсуждать.
Re[10]: Почему объектно-ориентированное программирование про
Здравствуйте, Ikemefula, Вы писали:
I>>>Лично мне всегда стремно выносить нетривиальный метод в публичный доступ, ибо получается монолит с которым работать еще хуже чем с десятков клонов.
V>>Дык, функциональная декомпозиция тоже бывает. Нетривиальный метод, по мере обобщения, считай что будет "точкой входа" и/или композицией более тривиальных шагов. Тут задача в повышении повторного использования кода, ибо для работы над таким кодом выделяется больше ресурсов, такой код имеет шанс выйти надежнее и эффективнее, чем каждое уникальное решение "по месту".
I>Ты по моему сравниваешь плохое vs хорошее
По моему, ты удивительный чтец м/у строк. Сравнивались эффекты открытости/доступности большей ф-сти при использовании ФП декомпозиции с закрытостью оной из ООП. + примеры из жизни.
I>При чем здесь по месту ?
Попробуй прочесть еще раз.
I>Как ты будешь тестировать свой нетривиальный метод ?
Не вижу каких-либо особенностей в сравнении с другой тестируемой ф-стью. Если было сказано, что эту функциональность я выделил, значит была принципиальная возможность её выделить.
I>Повторное использование это круто, но не тогда когда это монолит.
Можно по-русски?
Re[11]: Почему объектно-ориентированное программирование про
Здравствуйте, AndrewVK, Вы писали:
AVK>Но, если разнести наследование интерфейсов и реализаций по независимым механизмам, языки от этого только выиграют.
Как это может выглядеть? Наподобие приватного наследования в C++?
Re[12]: Почему объектно-ориентированное программирование про
Здравствуйте, Ikemefula, Вы писали:
V>>Да, паттерн State требует введения нового поля, хранящего объект-state как минимум.
I>Необязательно.
Обязательно, или это будет уже другой паттерн.
I>Тебе никто не мешает создавать инстанс когда придется и вычислять нужный экземпляр. Скажем в парсере так и будет зачастую.
Плохо представляю себе весь сценарий, но догадываюсь, что речь о создании временного объекта, который "живет на стеке". Это ты что-то фабричное упомянул и не понятно, при чем тут.
V>>Нет, не элементарно. Если не было зависимостей прямых или косвенность от состояния, то им нечего было делать в объекте.
I>Опаньки — сначала было состояние, а теперь уже зависимости
Гм... Вообще-то зависимости как раз и вычисляются м/у состоянием и методами. Если методы класса не связанны прямо или коссвенно с его собственным состоянием, то "тут что-то не так". По крайней мере, популярные метрики показывают наихудшее/вырожденное значение для этого случая.
I>Ну так нет разделения состояния наследник может вообще не знать про состояние базового, а только вызыват метод базового. I>...а вариант, котоырй под твое определение не походит взял и не стал обсуждать.
А ты думал, проедешь нахаляву? Запретил декомпозицию базового класса, и продолжаешь требовать декомпозиции наследника. Хорошо себя чувствуешь?
ИМХО, в своем примере ты сам не можешь разобраться. Пойми, если ты настаиваешь, что там есть базовый, недоступный для модификации класс (хотя в первоначальном виде его не было), то ты не можешь требовать декомпозиции в этом случае. Сосредоточься: ограничение на этот третьесторонний класс дано как условие, соответственно, на этом участке у нас принципиально восходящее проектирование. Для таких случаев есть официально-рекомендуемые костыли в виде структурных паттернов, а они по-определению служат для композиции объектов.
Поэтому, если тебе все еще охота пободаться насчет именно декомпозиции, давай играть честно — вернемся к нисходящему проектированию, и берем как данность, что у меня будет возможность подвергать анализу и изменять любые объекты иерархии.
Попробуем итерацию №3? Или уже и так ясно?
Re[22]: Почему объектно-ориентированное программирование про
Здравствуйте, vdimas, Вы писали:
V>Здравствуйте, samius, Вы писали:
S>>У меня возникает обратный вопрос. Разве нельзя оставаясь в рамках ООП выполнить это разделение обладая достаточно подробным списком связей? ООП по Кею — это "все есть объект", а не руководство по декомпозиции на модули.
V>А это вообще больное место. Не существует формальных способов ООП-дизайна. Во всех примерах ООП-анализа в литературе столько творчества, что единственный полезный совет тут — это потщательнее грызть карандаш.
Я немного не об этом. Вот возьмем некий алгебраический тип и функцию, которая принимает его и возвращает новый экземпляр. Можно трактовать этот процесс по Кею следующим образом: экземпляру АТД отправляем сообщение (передаем его функции) и получаем результат сообщения (новый АТД). Естественно, что традиционному ООП это поперек горла. Но в рамках Кея ФП и ООПК(ООП по Кею) можно в каком-то роде совмещать. Это мое предположение, и я без понятия как к этому отнесся бы сам Кей.
Т.е. как бы можно взять за основу ФП декомпозицию, подменить кортежи бездушными структурами, АДТ подменить на гомоморфные иерархии, где в базе будет абстрактный интерфейс, составленный из набора функций, работающих с этим АДТ. Иммутабельность сохраняется. В итоге получается как бы и ООП, но с ФП дизайном.
В том что это возможно, я нисколько не сомневаюсь, т.к. сам тяготею к такому стилю. Интересно обсудить его в плане обилия рефакторинга.
V>На самом деле, достаточно помнить, что ООП-не серебрянная пуля, т.е. сам по себе не самодостаточный инструмент. Поэтому стоит использовать (хотя бы очень поверхностно) наработки современных процессов по организации разработки ПО. Тем более, что те индифферентны к выбранной технологии. Я вот всем 19-е и 34-е госты рекомендую. Хотя бы раз в жизни прочесть их стоит (с конспектированием интересного). Ну или RUP, который близок по духу.
V>Вот, пробеги глазами:
Пробег. Информация безусловно полезная, но применительно к дизайну, она просто добавит карандашей, которые нужно сгрызть.
V>А не обязательно чистое ФП, со всеми модными фокусами. ФП сидит на функциональной декомпозиции, а это практически первое, чему учатся при обучении программированию.
Дык и проблема в том что чистое ФП технически сложно на языках имеющих парадигму менее чем гибридную по отношению к ФП. Так или иначе получается адская мешанина. Но мешанина эта мне нравится чуть более чем ООП. Она ближе к трансформации данных.
V> Ну и если есть опыт по созданию/использованию делегатов в том же C#, то еще одним "китом" ФП ты уже владеешь.
Я бы сказал что знаком с китом, а не владею.
V>Прочие ленивости и замыкания — это лишь доп. выразительные ср-ва инструмента, т.е. те, которые не критичны, т.к. в случае надобности реализуются "в лоб". Хотя со вторым упомянутым в шарпе тоже порядок.
В шарпе — да. Куда сложнее на C++ без 0x, с которым приходится иметь дело.
V>Ну и плюс, ФП в "чистом" виде не совсем удобно (лично мне, например).
Мне довольно удобно. неудобно как раз видеть решение в ФП виде и адаптировать его к ООП.
S>>Встречный вопрос. глубокий предварительный анализ потоков данных не препятствует итеративной разработке с уточнением требований?
V>Нет. Речь шла о хоть каком-то анализе алгоритмов и данных vs проектирование от квадратиков. И там и там на кончике карандаша всю систему разработать проблематично, но первая модель будет ближе к реально происходящему уже на первой итерации. У тебя будет банально больше информации в первом случае, чтобы нарисовать более удачный вариант квадратиков.
ООП ведь не запрещает анализ!
S>>Проблема такого подхода в том, что каждый добавляющий функциональность, думает что он последний. Последующему приходится погружаться в более нагроможденный код.
V>Практика комментирования коммитов и щедрость на TODO помогает упорядочивать. Главное, чтобы команда преследовала общие цели, и если кто-то видит, что образуется потенциально слабое место — поставил сигнальный флажок на нем.
V>>>Они и так сами получаются. Деление на слои процесс как бы автоматический, управляется сложностью единичного элемента, которую может обозреть человек. Какое там правило для ф-ий и методов — не больше 1-2 экранов кода? Примерно так. S>>Автоматический для тех кто уделяет этому достаточно внимания
V>Всё-равно автоматически по достижении некоторого порога. Однажды становится трудно просто прочесть код, даже если он хорош. И единственно правильное решение — декомпозировать, передокументировать и прочесть заново. Это может сэкономить часы и это дополнительный review кода. Оно как эффект катастрофы в природе, во вменяемой команде выполняется на автомате всеми участниками.
(выделил чуть выше)
Дело в том, что код становится плохочитаемым не сам по себе, а в процессе изменений. И тут все-таки нужен рефакторинг, желательно в тот момент, когда код модифицирован, т.к. он только что прочитан и детали свежи. TODO здесь поможет только в том случае, когда видно что плохо, но цель не ясна, т.к. связано с кодом, который в другом владении, либо неясна общая концепция.
В моей практике TODO имеют меньшие приоритеты чем issue в трэкере, потому плодятся как кролики. Стараюсь рефакторить сразу.
Re[11]: Почему объектно-ориентированное программирование про
Здравствуйте, vdimas, Вы писали:
I>>Как ты будешь тестировать свой нетривиальный метод ?
V>Не вижу каких-либо особенностей в сравнении с другой тестируемой ф-стью. Если было сказано, что эту функциональность я выделил, значит была принципиальная возможность её выделить.
Выделить и сделать тестируемой это разные вещи и бывает между собой никак не связаные.
I>>Повторное использование это круто, но не тогда когда это монолит.
V>Можно по-русски?
Это по русски.
Re: Почему объектно-ориентированное программирование провали
ИС>Среди множества идей, которые звучат красиво скорее в теории, чем на практике, объектно-ориентированное программирование занимает особое место.
Попробуем разобраться и ответить на главный вопрос, почему всё же объектно-ориентированное программирование провалилось?
Уже даже не смешно читать очередной раз перевранную цитату Степанова, которого с легкой руки какого-то козла в рунете сделали противником ООП'а. Мало того, что его цитата неправильно переведена, так еще и вырвана из контекста. Степанов много чего критикует, но никогда не разочаровывался в ООП вцелом. Та цитата была вырвана из разговора про Generic Programming. Под ООП в данном случае он имел классическую схему наследования и отметил, что она неэффективна для алгоритмических задач, где входные данные могут быть любым.
В статье есть интересные идеи, но написано слишком пафосно и надергано ненужного бреда из случайных источников.
Re[23]: Почему объектно-ориентированное программирование про
Здравствуйте, vdimas, Вы писали:
V>Вдогонку, для указанных ограничений будет такое итоговое решение V>
V>// тут наследуем, т.к. PreDo()/PostDo() требуют особого доступа к базе по условию,
V>class PreAndPostDecorator : ThirdPartyClass
V>{
V> public void PreDo() {}
V> public void PostDo() {}
V>}
V>}
А метод Do куда ты дел ? :)))
V>interface IDoer
V>{
V> void Do();
V>}
V>
V>Но оно не интересно. Ибо, чем больше ограничений, тем меньше надо думать.
Наоборот, чем больше ограничений тем бОльше надо думать. А когда ограничений мало — чуть мозг напряг, выдал первое попавшееся решение и оно сгодится ибо ограничений мало.
Re[23]: Почему объектно-ориентированное программирование про
Здравствуйте, vdimas, Вы писали:
V>>>Да, паттерн State требует введения нового поля, хранящего объект-state как минимум.
I>>Необязательно.
V>Обязательно, или это будет уже другой паттерн.
Хранение инстанца в State вещь абсолютно необязательная. Главный принцип — частичное изменение типа. Хочешь, храни инстанс, хочешь — не храни
class Transmit
{
public void Do()
{
_state.Do();
}
}
или
class Transmit
{
public void Do()
{
State().Do();
}
}
I>>Тебе никто не мешает создавать инстанс когда придется и вычислять нужный экземпляр. Скажем в парсере так и будет зачастую.
V>Плохо представляю себе весь сценарий, но догадываюсь, что речь о создании временного объекта, который "живет на стеке". Это ты что-то фабричное упомянул и не понятно, при чем тут.
Паттерны в Гоф это не руководство к действию, о чем и сказано. Хранение инстанца это не более чем оптимизация.
I>>Опаньки — сначала было состояние, а теперь уже зависимости
V>Гм... Вообще-то зависимости как раз и вычисляются м/у состоянием и методами. Если методы класса не связанны прямо или коссвенно с его собственным состоянием, то "тут что-то не так". По крайней мере, популярные метрики показывают наихудшее/вырожденное значение для этого случая.
I>>Ну так нет разделения состояния наследник может вообще не знать про состояние базового, а только вызыват метод базового. I>>...а вариант, котоырй под твое определение не походит взял и не стал обсуждать.
V>А ты думал, проедешь нахаляву? Запретил декомпозицию базового класса, и продолжаешь требовать декомпозиции наследника. Хорошо себя чувствуешь?
Я тебе показал пример что объектная декомпозиция может не иметь разделения состояния.
V>ИМХО, в своем примере ты сам не можешь разобраться. Пойми, если ты настаиваешь, что там есть базовый, недоступный для модификации класс (хотя в первоначальном виде его не было), то ты не можешь требовать декомпозиции в этом случае.
Это пример из жизни.
V>Поэтому, если тебе все еще охота пободаться насчет именно декомпозиции, давай играть честно — вернемся к нисходящему проектированию,
Ты пока внятно не пояснил что же у тебя объектная декомпозиция.
Раз тебе не нравится структурный паттерн, возьмем поведенческий. Код ниже. Покажи, где же там "разделение состояния"
старый пример после рефакторинга
abstract class Doer()
{
void Do()
{
PreDo();
DoInternal();
PostDo();
}
}
class Doer2 : Doer
{
public override void PreDo()
{
...
}
public override void PostDo()
{
...
}
}
Re[24]: Почему объектно-ориентированное программирование про
V>>Не вижу каких-либо особенностей в сравнении с другой тестируемой ф-стью. Если было сказано, что эту функциональность я выделил, значит была принципиальная возможность её выделить.
I>Выделить и сделать тестируемой это разные вещи и бывает между собой никак не связаные.
Делать пригодной к тестированию надо любую функциональность. Или выкидывать такой код сразу на помойку.
I>>>Повторное использование это круто, но не тогда когда это монолит.
V>>Можно по-русски?
I>Это по русски.
Тогда похоже на неоконченный разговор с самим собой.
Re[24]: Почему объектно-ориентированное программирование про
Здравствуйте, Ikemefula, Вы писали:
V>>Обязательно, или это будет уже другой паттерн.
I>Хранение инстанца в State вещь абсолютно необязательная. Главный принцип — частичное изменение типа.
Главный принцип — изменение поведения, в зависимости от состояния.
I>Хочешь, храни инстанс, хочешь — не храни
Второй случай на state не тянет.
I>Паттерны в Гоф это не руководство к действию, о чем и сказано. Хранение инстанца это не более чем оптимизация.
ОК, пусть даже ты его конструируешь каждый раз заново перед каждой операцией. Вопрос, конструируешь каждый раз один и тот же "вспомогательный" тип, или разные?
V>>А ты думал, проедешь нахаляву? Запретил декомпозицию базового класса, и продолжаешь требовать декомпозиции наследника. Хорошо себя чувствуешь?
I>Я тебе показал пример что объектная декомпозиция может не иметь разделения состояния.
Да ничего ровным счетом ты не показал. Я, справедливости ради, надеялся выйти на анализ, и показать, что сию декомпозицию проводим НЕ ср-вами ООП, коль речь пойдет о свободном функционале вокруг объектов. Твое дополнительное условие насчет "специфической недоступной для модификации базы" — это уловки, и что происходит в этом случае объяснил подробно. Но тут мы уже умываем руки, бо нас ограничили. И ты даже не представляешь, насколько ты не прав, считая, что проще без ограничений. В условиях сохранения все тех же требований к эффективной реализации, лучшего дизайна и оценок по ним, это банально больше работы.
V>>ИМХО, в своем примере ты сам не можешь разобраться. Пойми, если ты настаиваешь, что там есть базовый, недоступный для модификации класс (хотя в первоначальном виде его не было), то ты не можешь требовать декомпозиции в этом случае.
I>Это пример из жизни.
V>>Поэтому, если тебе все еще охота пободаться насчет именно декомпозиции, давай играть честно — вернемся к нисходящему проектированию,
I>Ты пока внятно не пояснил что же у тебя объектная декомпозиция.
Ну мы рассматривали нисходящее проектирование. Что оно есть, применительно к ООП? Это когда функциональность объектов верхнего уровня всё более выражается/уточняется за счет объектов все более низкого уровня. А в твоем примере — наоборот, данных как объективная реальность объектов низкого уровня, нам необходимо слепить объект более высокого уровня, реализующего некий интерфейс. Это восходящее проектирование.
Мне вообще хотелось показать, что простой разнос функциональности по объектам не всегда является или обязан быть выполнен в виде объектной декомпозиции.
Об этом, собсно, в этой ветке и говорил. При небольшой доработке АПИ объектов, приличная часть функционала может быть выполнена как внешняя по отношению к объектам. Причем, нам доступны как техника вызова свободных внешний ф-ий, так и функциональное DI, когда объект ожидает функтор в кач-ве параметра метода/конструктора/установки св-в, и потом его дергает в нужных местах. Цимус в том, что такое функциональное DI не требует описания интерфейсов с 1-м методом, наподобие IDoer, и за счет использования ФП-средств языков (по крайней мере C# и C++), такие ООП-ФП адаптеры (делегаты) могут создаваться весьма локально, не загружая прикладную систему типов проекта.
I>Раз тебе не нравится структурный паттерн, возьмем поведенческий. Код ниже. Покажи, где же там "разделение состояния"
I>
Я тут декомпозиции не вижу. Если утверждаешь, что она имела место, какая картинка была до нее? Все так же два объекта Doer и Doer2, но не связанные наследованием? Это не декомпозиция.
Re[13]: Почему объектно-ориентированное программирование про
Здравствуйте, AndrewVK, Вы писали:
V>>Как это может выглядеть? Наподобие приватного наследования в C++?
AVK>Думать надо, экспериментировать. В реализованном виде есть несколько вариаций на тему миксинов, есть автоматическое делегирование реализаций.
Тут главное, чтобы синтаксис не вышел переусложненным для простых вещей.
Введение защищенного/приватного наследования в С++ было лаконичным способом отрубить наследование интерфейса при наследовании реализации. Заметь, приватное наследование сделано по-умолчанию, т.е. для наследования публичного интерфейса класса нужно указать это явно. ИМХО, лаконично и продуманно. Потому плюсовики тему дуальности наследования реализации и интерфейса никогда не обсуждают.
Re[26]: Почему объектно-ориентированное программирование про
Здравствуйте, Ikemefula, Вы писали:
I>Да, я сразу не сообразил, что один класс у тебя явно лишний и по прежнему нет никакого разделения состояния.
Какой из них лишний? согласно всем твоим уточнениям насчет недоступности модификации базового класса?
I>Для чего было городить огород на ровном месте ?
ы?
Re[13]: Почему объектно-ориентированное программирование про
Здравствуйте, vdimas, Вы писали:
I>>Выделить и сделать тестируемой это разные вещи и бывает между собой никак не связаные.
V>Делать пригодной к тестированию надо любую функциональность. Или выкидывать такой код сразу на помойку.
Ты точно хотел это сказать ?
Твой код ниже. В декораторе есть зависимость от класса, чьи методы " требуют особого доступа к базе по условию"
Как видишь, протестировать твой декоратор не представляется возможным, т.к. есть ЖОСТКАЯ зависимость от базы данных.
Следовательно, твой код согласно твоему же правилу выбрасыватся на помойку.
// тут наследуем, т.к. PreDo()/PostDo() требуют особого доступа к базе по условию,class PreAndPostDecorator : ThirdPartyClass
{
public void PreDo() {}
public void PostDo() {}
}
// структурная композицияclass PreAndPostDoerDecorator : IDoer
{
private PreAndPostDecorator _decorator = new PreAndPostDecorator();
PreAndPostDoerDecorator(IDoer doer){ _doer = doer;}
void Do() {
_decorator.PreDo();
_doer.Do();
_decorator.PostDo();
}
}
Re[25]: Почему объектно-ориентированное программирование про
Здравствуйте, vdimas, Вы писали:
I>>Хранение инстанца в State вещь абсолютно необязательная. Главный принцип — частичное изменение типа.
V>Главный принцип — изменение поведения, в зависимости от состояния.
Ну как хошь называй.
I>>Хочешь, храни инстанс, хочешь — не храни
V>Второй случай на state не тянет.
То есть главный принцип не соблюдается ? Покажи на примере.
I>>Паттерны в Гоф это не руководство к действию, о чем и сказано. Хранение инстанца это не более чем оптимизация.
V>ОК, пусть даже ты его конструируешь каждый раз заново перед каждой операцией. Вопрос, конструируешь каждый раз один и тот же "вспомогательный" тип, или разные?
Тот, который требуется в данный момент.
V>Да ничего ровным счетом ты не показал. Я, справедливости ради, надеялся выйти на анализ, и показать, что сию декомпозицию проводим НЕ ср-вами ООП, коль речь пойдет о свободном функционале вокруг объектов. Твое дополнительное условие насчет "специфической недоступной для модификации базы" — это уловки,
Это не уловки. Это тривиальный пример. Например тебе надо логировать начало и конец операции. А може время мерять. А может в базу писать. Ничего из этого не трубует "разделения состояния", при этом зависимости есть.
V>Ну мы рассматривали нисходящее проектирование. Что оно есть, применительно к ООП? Это когда функциональность объектов верхнего уровня всё более выражается/уточняется за счет объектов все более низкого уровня.
В моем примере как раз это и есть Просто это никакая не декомпозиция
V>Мне вообще хотелось показать, что простой разнос функциональности по объектам не всегда является или обязан быть выполнен в виде объектной декомпозиции.
Ты бы на примере показал, что же у тебя композиция, что декомпозиция, и что такое "разделение состояния".
По моему разумению тебе всего то нужно глянуть в словарь
I>>
I>>
V>Я тут декомпозиции не вижу. Если утверждаешь, что она имела место, какая картинка была до нее?
Картинку ты видел, это вверх по ветке.
>Все так же два объекта Doer и Doer2, но не связанные наследованием? Это не декомпозиция.
Честно говоря я и не знаю, что у тебя декомпозиция
В данном примере были выделены обязанности и эти обязанности вынесены в отдельный метод. т.е. было выполненоразбиение системы по функциональным признакам.
Далее, в соответствии с этим разбиением была сформирована новая структура.
И тож самое, кстати говоря, было сделано и в предыдущем примере с декоратором.
Как ты в курсе , разбиение системы по функциональным признакам есть функциональная декомпозиция.
Re[27]: Почему объектно-ориентированное программирование про
Здравствуйте, vdimas, Вы писали:
I>>Да, я сразу не сообразил, что один класс у тебя явно лишний и по прежнему нет никакого разделения состояния.
V>Какой из них лишний? согласно всем твоим уточнениям насчет недоступности модификации базового класса?
V>>Главный принцип — изменение поведения, в зависимости от состояния.
I>Ну как хошь называй.
Что называть как хочу? Паттерна? Я согласен все называть своими словами, но тебе надо будет давать больше деталей относительно своих объектных систем.
V>>ОК, пусть даже ты его конструируешь каждый раз заново перед каждой операцией. Вопрос, конструируешь каждый раз один и тот же "вспомогательный" тип, или разные?
I>Тот, который требуется в данный момент.
Т.е. конструируемый объект явным образом зависит от текущего состояния? Или только от входных данных?
Понимаешь, это принципиально разные сценарии, тянущие за собой кучу последствий, из области потокобезопасности/масштабируемости в т.ч. И удачности выбранной декомпозиции тоже. Хотя "с виду" могут быть похожи.
I>Это не уловки. Это тривиальный пример. Например тебе надо логировать начало и конец операции.
Наконец по делу. Я же говорю, дай хоть немного зависимостей и всё станет на свои места. Ссылка на логгер — это часть состояния. Соответственно, выделяя свои PreDo/PostDo, ты можешь вместе с ними забрать и ссылку на логгер.
I>А може время мерять. А может в базу писать. Ничего из этого не трубует "разделения состояния", при этом зависимости есть.
В этих случах декомпозируемый объект утащит с собой ссылку на таймер или на подключение к базе. Причем, "утащит", даже если эти объекты глобальные (помнишь про моделирование глобального состояния, например аспектов АПИ ОС, через единственный экземпляр некоего объекта, на который есть явная ссылка). Вот эта глобальность порой мешает видеть происходящее, как том в анекдоте: ты видишь сусликов — нет, а они есть.
V>>Ну мы рассматривали нисходящее проектирование. Что оно есть, применительно к ООП? Это когда функциональность объектов верхнего уровня всё более выражается/уточняется за счет объектов все более низкого уровня.
I>В моем примере как раз это и есть Просто это никакая не декомпозиция
Т.е. мы все это время про термин спорили? Гоподя... Термин "декомпозиция" применяется как к процессу, так и результату. Причем, к результату часто не всвязи с приведшим к нему процессом, а даже если процесс был обратным. В любом случае, наша система это "черный ящик" для зрителя снаружи, а внутри она состоит из множества элементов, и вот это множество зачастую на жаргоне зовут декомпозицией. Я же имел ввиду исключительно процесс и именно с т.з. практик ООП. Это разновидность структурной декомпозиции (вики).
А теперь посмотри внимательно на свой пример. В нем после анализа можно было провести сначала структурную декомпозицию, затем функциональную, после смены ролей объектов. Но для этого надо больше участников, вот логгер добавить, например. В текущем виде там надобность переделки этой системы объектов как бы неочевидна. И это будет примерно тот подход, который я предлагал по всей этой ветке.
Ну и плюс, зря мы вцепились в слово именно декомпозиция. Если из твоей системы 4-х объктов после переделки оставлю 3 объекта, будет ли это композицией или декомпозицией? Правильный ответ: в общем случае, при смене ролей объектов происходит и то и другое. А спор вообще был не про тонкости декомпозиций, а про её стоимость из-за рефакторинга.
Помнишь, ты говорил про SOLID. Для чего LSP, DI, интерфейсы и прочее? Какую именно связанность, то бишь, связанность чего с чем они призваны уменьшать? Все это служит для уменьшения связанности м/у наблюдаемым "поведением" некоей абстракции, и подробностями её устройства. Причем, инкапсулируются в первую очередь подробности организации хранения состояний.
I>Ты бы на примере показал, что же у тебя композиция, что декомпозиция, и что такое "разделение состояния".
Вынесение любого поля — разнос состояния. Даже просто разнос битов неких числовых кодов (хранимых изначально в одной переменной) по разным объектам, — это тоже декомпозиция состояний, просто очень явная. Бывает, что разносят диапазоны этих кодов, и т.д. Про коды упомянул, потому что так легче понять происходящее и разницу м/у паттернами. При декомпозиции состояния, каждый из новых объектов обладает меньшим пространством состояний, чем исходный объект. Но множество их состояний, наример, декартово произведение для случая разноса бит кодов, или просто сумма кол-ва возможных состояний при разнесении по диапазонам, должны в итоге покрывать исходное множество состояний. Замечу, что обычно при декомпозиции состояний растет избыточность, т.е. суммарно получаемое такое пространство состояние обычно больше (мощнее), чем исходное, но исключительно за счет невалидных состояний. Поэтому, декомпозиция требует определенных мер по обеспечению безопасности кода. Не всегда это просто, например, если требуется соблюдать "протокол", т.е. если требуется вызывать методы объекта в некоем "правильном" порядке. Оно, конечно, почти всегда так, но если кол-во шагов по обеспечению протокола становится заметным на фоне предоствляемой полезной функциональности, то говорят, что страдает инкапсуляция. Т.е., имеет место вынос подробностей функциональности наружу. Собсно, инкапсуляция почти всегда заметно страдает на самом низком уровне декомпозиции. Отсюда, такие вещи как модули (это ср-во инкапсуляции для ФП-декомпозиции), неплохо помогают и в ООП, решая ровно ту же задачу.
I>По моему разумению тебе всего то нужно глянуть в словарь
Ссылку на определения, с которыми я согласен, я уже дал. Если есть другой словарь, кинь ссылку, почитаем.
V>>Я тут декомпозиции не вижу. Если утверждаешь, что она имела место, какая картинка была до нее?
I>Картинку ты видел, это вверх по ветке.
Понятно. Это бестолковый пинг-понг. Если нет хотя бы минимальной постановки задачи, то и нечего решать. Ты называешь свои решения "элементарными", хотя из приведенного условия они не следуют. Начинаю уточнять — вылазит куча подробностей. Это уже должно было дать понять, что без всех подробностей принимать решения бесполезно. Хочешь — давай законченную подсистему, со всеми связями вплоть до полей. В минимально достаточном варианте. К этому этому добавить требования к функциональности/АПИ этой подсистемы, желательно с обоснованием. Або перед началом реализации функциональности и требований к АПИ, они (требования) должны быть проверены на наличие багов, т.е. на непротиворечивость и полноту. Затем мы сможем снять метрики до преобразования системы объектов, и после. Ну, чтобы иметь саму возможность узнать, стоила ли овчинка выделки.
I>Честно говоря я и не знаю, что у тебя декомпозиция
К несчастью, я это понял только на этом посте.
I>В данном примере были выделены обязанности и эти обязанности вынесены в отдельный метод. т.е. было выполненоразбиение системы по функциональным признакам.
Ну коль современные ООП-языки позволяют использовать свободные функции и функциональные объекты, почему была использована техника ООП-декомпозиции, хотя состояние тут никаким боком, по твоим же словам (хотя ты не прав)? Почему бы не так:
public delegate void Doer();
class Context
{
Logger _logger;
public void Pre() {}
public void Post() {}
}
static class DoerModule
{
public static Doer ApplySomeAspect(Doer doer, Context context) {
return ()=> {
context.Pre();
doer();
context.Post();
};
}
...
}
И вот практически никаких связей участников в статической структуре тут нет, но динамически мы эти связи порождаем "по месту", то бишь для данной локальной надобности. Такой подход лучше решает твою задачу, особенно это будет заметно, если ты догадаешься не хранить ссылку на логгер в полезных классах, да еще наследоваться от этих химер. К тому же, здесь больше участников, чем в твоем примере (внесена ясность насчет связанности методов Pre()/Post()), но при этом меньше кода.
I>Как ты в курсе , разбиение системы по функциональным признакам есть функциональная декомпозиция.
Уффф... Ну вопрос тем более в силе, при чем тут тогда твое требование провести объектную декомпозицию?
Re[28]: Почему объектно-ориентированное программирование про
Здравствуйте, Ikemefula, Вы писали:
I>чуть далее было сказано I>"мне надо изменить поведение некоторый реализаций не переписывая все разновидности и клиенты IDoer " I>Итого — менять AcceptDoer нельзя, ибо клиент. Менять разновидности IDoer тоже нельзя, но изменить их поведение — нужно. I>Соответсвенно, если все было понятно, то очевидно, PreAndPostDecorator : ThirdPartyClass лишний.
Э нет, твой пример решил следующие задачи:
1. Убрать из Doer::Do вызовы PreDo/PostDo
2. Сделать возможным накладывать аспект PreDo/PostDo на любой вызов IDoer::Do().
Я же тебе сразу сказал, что PreDo/PostDo выносятся нафиг при такой постановке задачи. Ты там что-то начал насчет неделимого базового класса, но это уже не ко мне. По-первых, без достаточных подробностей я даже не могу сказать, ты ошибаешься или прав. И симметрично, ты не в состоянии оценивать мое решение, коль не выдал подробности. С т.з. озвученного на сейчас — оно чуть лучше твоего, ибо учитывает связанность и пытается ее оптимизировать. Это если мы используем ООП-декомпозицию. А в ФП-стиле выходит еще проще: http://rsdn.ru/forum/philosophy/4170405.1.aspx
Здравствуйте, Ikemefula, Вы писали:
V>>Делать пригодной к тестированию надо любую функциональность. Или выкидывать такой код сразу на помойку.
I>Ты точно хотел это сказать ?
I>Твой код ниже. В декораторе есть зависимость от класса, чьи методы " требуют особого доступа к базе по условию" I>Как видишь, протестировать твой декоратор не представляется возможным, т.к. есть ЖОСТКАЯ зависимость от базы данных.
Вот еще. Я ввожу DAL, и тестирую декоратор через тестовую имплементацию этого DAL. Без базы. А для рабочей версии DAL обязательно надо писать тесты для проверки его взаимодействия с реальной DB. Например, MS SQL/Oracle имеют десктопные версии своих серверов, так что тестовое окружение настраивается аж бегом. Это вообще не вопрос. Мне приходилось неоднократно с целью комплексного тестирования писать эмуляторы удаленных узлов, работающих по совершенно уникальным протоколам (какая-нить CORBA или ASN.1 было бы за счастье, но фиг там), так что ситуация с базой — просто детский лепет, сравнивая трудоемкость воссоздания тестового окружения.
I>Следовательно, твой код согласно твоему же правилу выбрасыватся на помойку.
Торопишься с выводами.
Re[27]: Почему объектно-ориентированное программирование про
Здравствуйте, vdimas, Вы писали:
I>>Тот, который требуется в данный момент.
V>Т.е. конструируемый объект явным образом зависит от текущего состояния? Или только от входных данных? V>Понимаешь, это принципиально разные сценарии, тянущие за собой кучу последствий, из области потокобезопасности/масштабируемости в т.ч. И удачности выбранной декомпозиции тоже. Хотя "с виду" могут быть похожи.
Нет никаких принципиально разных сценариев.
V>Наконец по делу. Я же говорю, дай хоть немного зависимостей и всё станет на свои места. Ссылка на логгер — это часть состояния. Соответственно, выделяя свои PreDo/PostDo, ты можешь вместе с ними забрать и ссылку на логгер.
А кто тебе сказал, что есть ссылка на логгер ? Ты слишком много на С++ сидишь. Зависимость может быть, а вот состояния может и не быть и это нормально.
Соответственно никакого разделения состояния быть не может — декомпозиция проведена, а состояние где было там и осталось.
V>В этих случах декомпозируемый объект утащит с собой ссылку на таймер или на подключение к базе. Причем, "утащит", даже если эти объекты глобальные (помнишь про моделирование глобального состояния, например аспектов АПИ ОС, через единственный экземпляр некоего объекта, на который есть явная ссылка). Вот эта глобальность порой мешает видеть происходящее, как том в анекдоте: ты видишь сусликов — нет, а они есть.
Это в С++, сочувствую.
I>>В моем примере как раз это и есть Просто это никакая не декомпозиция
V>Т.е. мы все это время про термин спорили? Гоподя... Термин "декомпозиция" применяется как к процессу, так и результату. Причем, к результату часто не всвязи с приведшим к нему процессом, а даже если процесс был обратным. В любом случае, наша система это "черный ящик" для зрителя снаружи, а внутри она состоит из множества элементов, и вот это множество зачастую на жаргоне зовут декомпозицией. Я же имел ввиду исключительно процесс и именно с т.з. практик ООП.
Не ясно, как ты понимаешь эту декомпозицию. Из твоих примеров этого понимания вообще не следует.
V>А теперь посмотри внимательно на свой пример. В нем после анализа можно было провести сначала структурную декомпозицию, затем функциональную, после смены ролей объектов. Но для этого надо больше участников, вот логгер добавить, например.
Не надо.
>В текущем виде там надобность переделки этой системы объектов как бы неочевидна. И это будет примерно тот подход, который я предлагал по всей этой ветке.
Ога, сделать жосткую зависимость от другого класса
V>Помнишь, ты говорил про SOLID. Для чего LSP, DI, интерфейсы и прочее? Какую именно связанность, то бишь, связанность чего с чем они призваны уменьшать? Все это служит для уменьшения связанности м/у наблюдаемым "поведением" некоей абстракции, и подробностями её устройства. Причем, инкапсулируются в первую очередь подробности организации хранения состояний.
Опаньки, щас ты снова заговорил про связанность
V>Вынесение любого поля — разнос состояния.
Ты ведь говорил что объектная декомпозиция это вообще всегда разделение состояния, щас, похоже, ты хочешь сузить семантику своего высказыния задним числом
V>Ссылку на определения, с которыми я согласен, я уже дал. Если есть другой словарь, кинь ссылку, почитаем.
Вики в данном форуме, согласно твоим же словам, сам знаешь куда годится
V>Понятно. Это бестолковый пинг-понг. Если нет хотя бы минимальной постановки задачи, то и нечего решать. Ты называешь свои решения "элементарными", хотя из приведенного условия они не следуют. Начинаю уточнять — вылазит куча подробностей.
Ты не уточняешь, ты хочешь поменять условие в удобную для себя сторону.
V>Ну коль современные ООП-языки позволяют использовать свободные функции и функциональные объекты, почему была использована техника ООП-декомпозиции, хотя состояние тут никаким боком, по твоим же словам (хотя ты не прав)? Почему бы не так:
Потому что AcceptDoer нельзя модифицировать в силу ряда причин, например отсутствующий исходный код.
Система, как ты понимаешь, если понимаешь, пишется здесь и сейчас, а не для тех требований что будут через 10 лет.
V>И вот практически никаких связей участников в статической структуре тут нет, но динамически мы эти связи порождаем "по месту",
Это тот же декоратор При том не самый удачный. Например потому что есть зависимость от классов Context и DoerModule.
Реально же нужно решание с однозависимостью — от интерфейса IDoer.
I>>Как ты в курсе , разбиение системы по функциональным признакам есть функциональная декомпозиция.
V>Уффф... Ну вопрос тем более в силе, при чем тут тогда твое требование провести объектную декомпозицию?
объект == функциональный элемент
Re[29]: Почему объектно-ориентированное программирование про
Здравствуйте, vdimas, Вы писали:
I>>"мне надо изменить поведение некоторый реализаций не переписывая все разновидности и клиенты IDoer " I>>Итого — менять AcceptDoer нельзя, ибо клиент. Менять разновидности IDoer тоже нельзя, но изменить их поведение — нужно. I>>Соответсвенно, если все было понятно, то очевидно, PreAndPostDecorator : ThirdPartyClass лишний.
V>Э нет, твой пример решил следующие задачи: V>1. Убрать из Doer::Do вызовы PreDo/PostDo V>2. Сделать возможным накладывать аспект PreDo/PostDo на любой вызов IDoer::Do().
"мне надо изменить поведение некоторый реализаций не переписывая все разновидности и клиенты IDoer "
Вероятно у тебя какие то проблемы с этой фразой
V>Я же тебе сразу сказал, что PreDo/PostDo выносятся нафиг при такой постановке задачи.
А я тебе сразу показал, что есть код который менять нельзя и похоже ты просто хочешь спрыгнуть на какую то другую задачу
>Ты там что-то начал насчет неделимого базового класса, но это уже не ко мне.
Феерическая чушь. Вероятно у тебя какие то проблемы с фразой
"мне надо изменить поведение некоторый реализаций не переписывая все разновидности и клиенты IDoer "
V>P.S. AcceptDoer можно не менять, но обернуть его в функциональный адаптер. V>
Здравствуйте, vdimas, Вы писали:
I>>Твой код ниже. В декораторе есть зависимость от класса, чьи методы " требуют особого доступа к базе по условию" I>>Как видишь, протестировать твой декоратор не представляется возможным, т.к. есть ЖОСТКАЯ зависимость от базы данных.
V>Вот еще. Я ввожу DAL, и тестирую декоратор через тестовую имплементацию этого DAL. Без базы.
Ты сделал декоратор который невозможно протестировать в изолированом виде.
I>>Следовательно, твой код согласно твоему же правилу выбрасыватся на помойку.
V>Торопишься с выводами.
Покажи как твой декоратор можно протестировать в изолированом виде
Re[28]: Почему объектно-ориентированное программирование про
Здравствуйте, Ikemefula, Вы писали:
I>А кто тебе сказал, что есть ссылка на логгер ? Ты слишком много на С++ сидишь. Зависимость может быть, а вот состояния может и не быть и это нормально. I>Соответственно никакого разделения состояния быть не может — декомпозиция проведена, а состояние где было там и осталось.
Все ясно. Что есть по твоему "состояние"?
V>>В этих случах декомпозируемый объект утащит с собой ссылку на таймер или на подключение к базе. Причем, "утащит", даже если эти объекты глобальные (помнишь про моделирование глобального состояния, например аспектов АПИ ОС, через единственный экземпляр некоего объекта, на который есть явная ссылка). Вот эта глобальность порой мешает видеть происходящее, как том в анекдоте: ты видишь сусликов — нет, а они есть.
I>Это в С++, сочувствую.
При чем тут С++, если в дотнете есть статические методы и поля. Это и есть "глобальное состояние". Для дотнета, правда, ограниченное доменом, но для нашего обсуждения не принципиально. А характер получаемой инкапсуляции сравним с оной в модулях.
I>Не ясно, как ты понимаешь эту декомпозицию. Из твоих примеров этого понимания вообще не следует.
Декомпозиция — это разбиение сложного решения на части. Сам термин в чистом виде относится к случаю, когда сохраняется исходная функциональность, хотя мы тут его используем порой вольно, угу. В случае развития функциональности, как в твоем примере, тут минимум 2 шага: сначала декомпозиция исходного решения, потом его доработка.
>>В текущем виде там надобность переделки этой системы объектов как бы неочевидна. И это будет примерно тот подход, который я предлагал по всей этой ветке.
I>Ога, сделать жосткую зависимость от другого класса
Уточни, какая именно зависимость. Т.е. подставь сюда идентификаторы: X --> Y.
I>Опаньки, щас ты снова заговорил про связанность
Знакомое слово услышал? Дык, а конкретные детали декомпозиции я из каких, по-твоему, соображений совершаю?
V>>Вынесение любого поля — разнос состояния.
I>Ты ведь говорил что объектная декомпозиция это вообще всегда разделение состояния, щас, похоже, ты хочешь сузить семантику своего высказыния задним числом I>
Говорил, говорю и буду говорить. А вот тебе стоит перечитывать некоторые предложения по два раза. Хотя, я уже понял, где собака зарыта. Первый вопрос в силе.
V>>Ссылку на определения, с которыми я согласен, я уже дал. Если есть другой словарь, кинь ссылку, почитаем.
I>Вики в данном форуме, согласно твоим же словам, сам знаешь куда годится
И что? Для вики годится правило "доверяй, но проверяй". Т.е. вики может служить неплохой отправной точкой по некоторой теме. ИМХО, форумы RSDN и так на чат похожи, так что раскидываю ссылки заранее, чтобы сократить кол-во итераций нашего пинг-понга.
I>Ты не уточняешь, ты хочешь поменять условие в удобную для себя сторону.
Нет, я хочу понять — почему именно так. Т.е. выйти на "локальное ТЗ". Учитывая, что решений даже простых задач обычно гораздо больше одного, это тем более стоит сделать. И да, готов поучаствовать в публичной порке любого решения. Мне самому интересно, как народ сейчас думает. Бо лично по моим наблюдениям, несмотря на рекламу ФП, все большие корни пускает болезнь ООПнутости, даже там, где слишком очевидно её излишество или неэффективность. Что уж говорить о менее очевидных случаях. Как-то еще лет 10 или чуть более назад мейнстрим легко плясал от функциональной и алгоритмической декомпозиции, непринужденно сочетая ее с объектной на верхних уровнях. Наверно, сказывалось "тяжелое наследство" сей, паскалей, фортранов, лиспов, фортов и прочего. А сейчас правильно ФП-шники делают, что жужжат на всех углах, потому как мейнстрим разучился. Вернее, не умеет от рождения, бо на джаве/дотнете вырос. Разумеется, всё что я тут написал, еще лет 10 назад было бы неактуально, никого не надо было уговаривать. А теперь надо. И если бы только на форуме...
I>Потому что AcceptDoer нельзя модифицировать в силу ряда причин, например отсутствующий исходный код.
P.S. AcceptDoer можно не менять, но обернуть его в функциональный адаптер.
Не надо пытаться натягивать туда паттерны ООП, бо его там не осталось. В ФП чуть менее чем все паттерны пляшут от трех базовых комбинаторов и техники частичного применения.
I>Например потому что есть зависимость от классов Context и DoerModule.
Дык, это у тебя зависимость от какого-то базового класса (упомянутого устно), и от явно заданного типа IDoer. А у меня зависимости никакой нет, мы абстрагировались через функтор Doer. Берем и накладываем тот же аспект на совершенно левый класс:
// произвольный другой классclass AnotherDoer
{
void WTF(Boo arg) {}
}
...
// в некоей конкретике приспичило наложить тот же аспект:
Doer doer = DoerModule.ApplySomeAspect(()=>anotherDoer.WTF(booArg), context);
Итого, зависимость от аспекта присутствует только там, где мы явно его используем. Т.е. никаких там косвенных/неявных зависимостей нет и близко. Остальные входы и выходы развязаны через функциональный тип Doer. Посмотри теперь на свое решение. Если тебе надо будет наложить похожий Pre/Post аспект на другой класс, то в твоем решении надо будет вводить зависимость этого класса от IDoer, или порождать копию класса PreAndPostDoerDecorator, обслуживающего другой тип, отличный от IDoer (потому как на генериках это не обобщить). Ирония судьбы или с легким паром здесь в том, что таки правильней создавать копию PreAndPostDoerDecorator, чем натягивать интерфейс IDoer на все подряд, не прикладных зависимостей is-a ради, а токмо лишь для удовлетворения статической системы типов. Вот это и есть совершенно ненужная связанность. Как от нее избавляются, должно быть уже понятно. ИМХО, это просто удобно и не стоило такого длинного спора.
I>Реально же нужно решание с однозависимостью — от интерфейса IDoer.
Пока нет задачи целиком, твое "нужно" вполне может оказаться зависимой постановкой задачи для части выбранного решения, не более того. В общем, если есть желание, давай по мылу в личке разберем конкретный прикладной момент целиком. Может ты и прав, с т.з. всех условий, но по озвученной пока части — вовсе не очевидно.
V>>Уффф... Ну вопрос тем более в силе, при чем тут тогда твое требование провести объектную декомпозицию?
I>объект == функциональный элемент
С состоянием и поведением! Иначе это не объект, а просто юзерский тип, описанный ср-вами ООП-языка.
Re[30]: Почему объектно-ориентированное программирование про
G>Разговор был о проектировании, а ты как-то внезапно съехал на внутренности компилятора, подменяя суть терминов.
Просто я еще не видел компиляторов ООП-языков, чтобы при наследовании реализации наследник не агрегировал базу. Скажу больше, я даже не представляю, как это обойти. У тебя есть предложения?
Re[24]: Почему объектно-ориентированное программирование про
Здравствуйте, vdimas, Вы писали:
V>Здравствуйте, gandjustas, Вы писали:
G>>Разговор был о проектировании, а ты как-то внезапно съехал на внутренности компилятора, подменяя суть терминов.
V>Просто я еще не видел компиляторов ООП-языков, чтобы при наследовании реализации наследник не агрегировал базу.
Я тоже не видел. Более того, сама парадигма ООП этому противоречит.
V>Скажу больше, я даже не представляю, как это обойти. У тебя есть предложения?
typeclasses в хаскеле.
Re[17]: Почему объектно-ориентированное программирование про
Здравствуйте, vdimas, Вы писали:
V>Здравствуйте, Ikemefula, Вы писали:
I>>Покажи как твой декоратор можно протестировать в изолированом виде
V>Ну блин, техника изоляции при тестировании всегда одна — через заглушки. А способов исполнения сих заглушек множество:
Я скипнул порожний текст. Покажи, как ТВОЙ декоратор можно протестировать в изолированом виде.
Мне очень хочется посмотреть, как же ты зависимость от ThirdParty заменишь на заглушку.
Re[29]: Почему объектно-ориентированное программирование про
Здравствуйте, vdimas, Вы писали:
I>>А кто тебе сказал, что есть ссылка на логгер ? Ты слишком много на С++ сидишь. Зависимость может быть, а вот состояния может и не быть и это нормально. I>>Соответственно никакого разделения состояния быть не может — декомпозиция проведена, а состояние где было там и осталось.
V>Все ясно. Что есть по твоему "состояние"?
Элементарно — персистед данные.
I>>Это в С++, сочувствую.
V>При чем тут С++, если в дотнете есть статические методы и поля. Это и есть "глобальное состояние". Для дотнета, правда, ограниченное доменом, но для нашего обсуждения не принципиально. А характер получаемой инкапсуляции сравним с оной в модулях.
Принципиально. Состояния может и не быть, а зависимость будет в любом случае.
I>>Не ясно, как ты понимаешь эту декомпозицию. Из твоих примеров этого понимания вообще не следует.
V>Декомпозиция — это разбиение сложного решения на части. Сам термин в чистом виде относится к случаю, когда сохраняется исходная функциональность, хотя мы тут его используем порой вольно, угу. В случае развития функциональности, как в твоем примере, тут минимум 2 шага: сначала декомпозиция исходного решения, потом его доработка.
Вот посмотри внимательно ан мои примеры, я ажно дважды показал разбиение сложного решения на две части.И там и там разбиение по функциональному признаку.
I>>Ога, сделать жосткую зависимость от другого класса
V>Уточни, какая именно зависимость. Т.е. подставь сюда идентификаторы: X --> Y.
// тут наследуем, т.к. PreDo()/PostDo() требуют особого доступа к базе по условию,class PreAndPostDecorator : ThirdPartyClass // вот это жосткая зависимость
{
public void PreDo() {}
public void PostDo() {}
}
// структурная композицияclass PreAndPostDoerDecorator : IDoer
{
private PreAndPostDecorator _decorator = new PreAndPostDecorator(); // и это жосткая зависимость
PreAndPostDoerDecorator(IDoer doer){ _doer = doer;}
void Do() {
_decorator.PreDo();
_doer.Do();
_decorator.PostDo();
}
}
I>>Опаньки, щас ты снова заговорил про связанность
V>Знакомое слово услышал? Дык, а конкретные детали декомпозиции я из каких, по-твоему, соображений совершаю?
Ранее ты вещал про состояние
V>Нет, я хочу понять — почему именно так. Т.е. выйти на "локальное ТЗ".
Уже давно было дадено это "локальное ТЗ".
I>>Это тот же декоратор При том не самый удачный.
V>Не надо пытаться натягивать туда паттерны ООП, бо его там не осталось. В ФП чуть менее чем все паттерны пляшут от трех базовых комбинаторов и техники частичного применения.
Адаптер это паттерн более древний, чем ООП
I>>Например потому что есть зависимость от классов Context и DoerModule.
V>Дык, это у тебя зависимость от какого-то базового класса (упомянутого устно), и от явно заданного типа IDoer.
Враньё. Я говорил совсем друго. Про базовый клас ты выдумал. В очередной раз скипнул, ибо похоже ты уже сам поверил в свое вранье.
V>>>Уффф... Ну вопрос тем более в силе, при чем тут тогда твое требование провести объектную декомпозицию?
I>>объект == функциональный элемент
V>С состоянием и поведением! Иначе это не объект, а просто юзерский тип, описанный ср-вами ООП-языка.
Это в с++ тбе надо искать состояние.
Re[31]: Почему объектно-ориентированное программирование про
I>>Да, круто. Это равносильно обычному вызову AcceptDoer
V>Это абстрагирование от конкретного AcceptDoer. Почувствуй разницу.
"мне надо изменить поведение некоторый реализаций не переписывая все разновидности и клиенты IDoer "
Нахрена тебе AcceptDoer менять и абстрагироваться ?
Еще раз
1 Есть некоторые реализации IDoer. Их модифицировать нельзя, например за отсутствием исходного кода.
2 Есть конкретная реализация IDoer. Её модифицировать можно.
3 Есть AcceptDoer который модифицировать нельзя, например за отсутствием исходного кода.
Задача — модифицировать поведение AcceptDoer для ВСЕХ IDoer.
Чем тебе поможет абстрагирование от AcceptDoer в этой задаче ?
Re[24]: Почему объектно-ориентированное программирование про
Здравствуйте, vdimas, Вы писали:
G>>Разговор был о проектировании, а ты как-то внезапно съехал на внутренности компилятора, подменяя суть терминов.
V>Просто я еще не видел компиляторов ООП-языков, чтобы при наследовании реализации наследник не агрегировал базу. Скажу больше, я даже не представляю, как это обойти. У тебя есть предложения?
Вот это агрегирование базы ты похоже и называешь "разделение состояния"
Re[10]: Почему объектно-ориентированное программирование про
Здравствуйте, samius, Вы писали:
S>Я немного не об этом. Вот возьмем некий алгебраический тип и функцию, которая принимает его и возвращает новый экземпляр. Можно трактовать этот процесс по Кею следующим образом: экземпляру АТД отправляем сообщение (передаем его функции) и получаем результат сообщения (новый АТД). Естественно, что традиционному ООП это поперек горла. Но в рамках Кея ФП и ООПК(ООП по Кею) можно в каком-то роде совмещать. Это мое предположение, и я без понятия как к этому отнесся бы сам Кей.
Традиционному ООП это никак поперек горла быть не может
V>>Всё-равно автоматически по достижении некоторого порога. Однажды становится трудно просто прочесть код, даже если он хорош. И единственно правильное решение — декомпозировать, передокументировать и прочесть заново. Это может сэкономить часы и это дополнительный review кода. Оно как эффект катастрофы в природе, во вменяемой команде выполняется на автомате всеми участниками. S>(выделил чуть выше) S>Дело в том, что код становится плохочитаемым не сам по себе, а в процессе изменений. И тут все-таки нужен рефакторинг, желательно в тот момент, когда код модифицирован, т.к. он только что прочитан и детали свежи. TODO здесь поможет только в том случае, когда видно что плохо, но цель не ясна, т.к. связано с кодом, который в другом владении, либо неясна общая концепция. S>В моей практике TODO имеют меньшие приоритеты чем issue в трэкере, потому плодятся как кролики. Стараюсь рефакторить сразу.
Любой код имеет свой цикл жизни. Рефакторинг удлинняет этот цикл жизни. Но сделать бесконечным просто не получится. Ну и издержки по вермени/деньгами никто не отменял. В конечном итоге становится проще выбросить хотя бы некоторые части и написать их заново.
Re[11]: Почему объектно-ориентированное программирование про
Здравствуйте, vdimas, Вы писали:
V>Здравствуйте, samius, Вы писали:
S>>...Но в рамках Кея ФП и ООПК(ООП по Кею) можно в каком-то роде совмещать. Это мое предположение, и я без понятия как к этому отнесся бы сам Кей.
V>У функции нет собственного поведения, т.е. функциональности, зависящей от состояния, вот и все отличие.
Не совсем так. поведение функции может зависеть от состояния извне, переданного аргументом. Ключевое отличие — внутри или снаружи. Но и это отличие тает при упоминании о том что состояние передается неявно через this. Остается совсем незначительная деталь, отделяющая чистую функцию от метода объекта — функция не может менять внутреннюю память аргумента. (Уверен, ты все это знаешь. Я просто описываю ракурс, под которым я вижу немалую схожесть функции и объекта.) В таком ракурсе объект, не изменяющий свое внутреннее состояние, отлично воспринимается в виде функции и наоборот. Между делом в ООП нигде не сказано что объекты обязаны обладать изменяемым состоянием, хотя и многие ООП паттерны не перенесут иммутабельности.
V>Бенефит потоковой безопасности достигается так же локальностью ссылок. Тем не менее, иммутабельность на этапе обработки данных дает очень важное кач-во при последующей смене состояния. Ниже пройдусь.
потоковую безопасность я пока даже не рассматриваю.
V>ФП-подход — это подход, ориентированный на функции высших порядков, как я себе представляю, чем он отличается от обычного процедурного подхода. Конечно, тоже полезная штука для абстрагирования, но скорее как инструмент для избавления от лишних зависимостей и от россыпи маленьких интерфейсов, чем как цель дизайна.
Естественно ФП не цель, а средство.
S>>В том что это возможно, я нисколько не сомневаюсь, т.к. сам тяготею к такому стилю. Интересно обсудить его в плане обилия рефакторинга.
V>ФП подход сидит на алгоритмической декомпозиции. А та принципиально меньше тяготеет к рефакторингу, т.к. зависимостей в рамках одной ф-ии всяко меньше, чем сразу у группы оных.
V>Как уже тут было упомянуто, тяга к инкапсуляции подробностей реализации
извиняюсь, я буду скипать лирику, против которой ничего не имею.
V>А что, если это состояние составлять из неких "стандартных кубиков" под нашу задачу? Мы ведь в процессе тщательного рефакторинга и объектной декомпозиции и так к этому приходим, правильно? За много итераций.
да, но я все время пытаюсь перевести разговор в следующее русло: что бы было, если бы ООП кубики строили с ФП конца.
V>Но в случае процедурного подхода, и аналогично ФП-подхода, мы вынуждены эти "стандартные кубики" разрабатывать сразу, как результат попытки реализации функциональных требований к программе. По-сути, мы вынуждены будем разработать представление/абстракции ДАННЫХ, и завязать их на алгоритмы по их трансформации.
да. А теперь возьмем и нарисуем ООП кубики по ФП наброску.
V>В ФП-языках эти кубики выглядят как алгебраические типы или туплы, иногда именованные — структуры/кортежи. Все кишки наружу и АПИ к ним не нарисуешь, поэтому "чистое ФП" меня не торкает.
Слишком быстрый переход. Почему АПИ не нарисуешь? Рисовать можно все что угодно, кроме способов изменения внутренних состояний.
V>Применяя технику ООП, сии кубики можно сделать во-первых безопасными (располагаем инструментом инкапсуляции), во-вторых, нарисовать им удобный АПИ.
они абсолютно безопасные. инкапсуляция ФП не противоречит. И АПИ на иммутабельных объектах тоже может быть удобным, разве что менее привычным.
V>Ну и согласен, гомоморфные наборы этих кубиков, если делать на ООП — вообще убийственная сила в плане прозрачности дизайна.
Согласен. Но ничто не мешает ОО кубикам, построенным из ФП декомпозиции лежать в гомоморфной иерархии.
V>А что собственно произошло? Мы позволили процедурам и функторам принимать как аргументы и возвращать как результат объекты. Отличное дополнение к алгоритмической декомпозиции. Далее. Пытаемся реализовать ту самую функциональность, которая идет как функциональные требования. (Без всяких глобальных переменных, по крайней мере без мутабельных). В каких-то местах мы видим, что упираемся. Это происходит при надобности в какой-то точке вычислений обеспечить персистентность данных м/у вызовами. Т.е. сохранить состояние. Вот! Усек что произошло? Вместо заведомого "от балды" рисования семейства объектов-акторов, как участников "первого варианта дизайна" (который будет потом многократно перерефакторен), мы выходим на список объектов как бы автоматически, через мн-во состояний, требующих персистентности. И уже с готовыми "кубиками" наперевес, так что составить из них в нужном месте композицию получается совсем простым делом. Утрирую, понятно, но очень близко к происходящему.
Т.е. ты предлагаешь вставлять мутабельные объекты там где требуется персистентность состояний между вызовами. Остается вопрос где грань между требуется и не требуется. Ведь ФП предлагает средства по передаче состояний между вызовами без персистентности (рекурсия, монада state, зиппер). На самом деле вопрос о грани между требуется и не требуется ли персистентность — очень скользкий. Легко впасть в крайность, когда она требуется везде — получаем голый императив, не требуется нигде — чистое ФП, или местами — гибрид.
V>Вообще-то фокус был на порядок работ, чтобы минимизировать кол-во съеденных карандашей. По мне рефакторинг и есть перманентная грызня карандаша, только уже с помощью мышки и клавы.
Да, так и есть. Вместо витания в облаках, точится код во плоти. И не только перманентная грызня, но и персистентная. А значит требует больше ресурсов.
S>>Дык и проблема в том что чистое ФП технически сложно на языках имеющих парадигму менее чем гибридную по отношению к ФП. Так или иначе получается адская мешанина.
V>Ты поменьше функциональщиков слушай.
Наоборот, хотел бы послушать.
V>Я тут многократно предлагал взглянуть на объекты как на автоматы (а они и есть автоматы), и позаимствовать оттуда кой-чего. Чем преобразователь-автомат отличается от простой цифровой функции? Наличием памяти. Cтруктура автомата (Мура) такова:
согласен, объекты есть автоматы. V>п.п.1-2 абсолютно "чисты" с т.з. ФП, что как бэ намекает на уместность применения этого подхода для реализации объекта-автомата.
память автомата может быть не только внутри объекта. Её может предоставлять клиент автомата, потому автоматы могут быть абсолютно чистыми, впрочем вместе с клиентами (http://www.rsdn.ru/article/haskell/HaskellStateMachine.xml
).
V>Вернемся к нашему подходу. ... Т.е. отделив в явном виде ф-ии вычисления след. состояния от собственно шага обновления состояния, мы можем добиться уникального в плане надежности качества — устойчивости к исключениям. ... В итоге, мы отказываемся еще от одной полезной практики, под названием "let it fail".
Интересный момент, но не пойму, какое это имеет отношение к обсуждаемым материям.
V>Обрати внимание на изящное решение популярной проблемы читателей/писателей, получаемое вместе с транзакционностью, когда мы стадию вычисления следующего состояния отделили от операции по его обновлению.
да, изящно.
V>Почему же функциональщики так жужжат о вреде смешения парадигм? ... Бери цифровую электронику. Это почти ООП (КОП в чистом виде) — интерфейсы и их реализации. И никто не страдает, что на одной плате есть как "чистые" цифровые ф-ии, так и россыпь автоматов.
Дык в ФП автоматы сплошь и рядом. Те же функции можно рассматривать как автоматы. Ленивость — автомат. Никто не страдает что свиду чистые функции являются фактически автоматами.
S>>Я бы сказал что знаком с китом, а не владею.
V>Не скромничай. Создание делегата по нестатическому методу — это всегда замыкание, еще со времен первого дотнета. А ты наверняка делегатов насоздавал за свою практику уже немало.
конечно насоздавал. Но владение китом не приравнивается к использованию делегатов. Даже не рядом. Все равно что говорить о владении ООП человеком, написавшему Console.WriteLine("hello world") на том основании что строка есть объект
S>>В шарпе — да. Куда сложнее на C++ без 0x, с которым приходится иметь дело.
V>Дык, а boost:bind? А старые добрые std::bind1st, std::bind2nd? Та же фигня. А слоты и сигналы QT?
boost-а и QT нет в текущем проекте, а std::bind*** покрывает довольно мало сценариев.
S>>Мне довольно удобно. неудобно как раз видеть решение в ФП виде и адаптировать его к ООП.
V>Наверно, от образа мыслей зависит. По мне ФП хорошо, пока мы производим вычисления, и плохо, когда нам результат этого вычисления надо куда-то девать. Монада IO в Хаскеле как раз помечает те места, где "чистое ФП" умывает руки.
Да, но при совмещении техник (при отказе от матаппарата ФП) эти места становятся недостойными внимания.
S>>ООП ведь не запрещает анализ!
V>Ни одна методология не запрещает. Мое ИМХО о том, что ООП поощряет начинать сразу с квадратиков.
Да. Если в программе должно выстрелить ружье, то в ООП программе появляются риски возникновения квадратиков "ружье", "стрелковое оружие", "оружие", "оружие с курком", "оружие с магазином" и т.п. Причем процесс этот довольно занимательный
S>>Дело в том, что код становится плохочитаемым не сам по себе, а в процессе изменений. И тут все-таки нужен рефакторинг, желательно в тот момент, когда код модифицирован, т.к. он только что прочитан и детали свежи.
V>Это в конкретном месте детали свежи. А если имеем несколько накопленных TODO, то можно попытаться обозреть проблему чуть более со стороны. И часто бывает так, что удовлетворяя один из них, можно удовлетворить целую пачку. В общем, перед решением любой задачи, желательно как можно больше вводных/требований. Хотя, каждый случай уникальный, понятно, и универсальных советов тут нет. Совет "рефакторить сразу" так же далек от универсальности.
Мне кажется что это особенности именно ООП рефакторинга, т.к. один и тот же объект (а то и в разных состояниях) встречается в различных местах кода. Изменяя какой-то аспект поведения объекта, либо его члены, приходится думать, а как это повлияет на код в другом месте. Особенно заметно при нарушениях SRP. И действительно, рефакторить такие места нужно представляя все сценарии использования объекта, а не местячково.
Re[12]: Почему объектно-ориентированное программирование про
Здравствуйте, samius, Вы писали:
V>>У функции нет собственного поведения, т.е. функциональности, зависящей от состояния, вот и все отличие. S>Не совсем так. поведение функции может зависеть от состояния извне, переданного аргументом. Ключевое отличие — внутри или снаружи. Но и это отличие тает при упоминании о том что состояние передается неявно через this. Остается совсем незначительная деталь, отделяющая чистую функцию от метода объекта — функция не может менять внутреннюю память аргумента. (Уверен, ты все это знаешь. Я просто описываю ракурс, под которым я вижу немалую схожесть функции и объекта.) В таком ракурсе объект, не изменяющий свое внутреннее состояние, отлично воспринимается в виде функции и наоборот. Между делом в ООП нигде не сказано что объекты обязаны обладать изменяемым состоянием, хотя и многие ООП паттерны не перенесут иммутабельности.
Какие паттерны из ООП не перенесут иммутабельности ?
Re[11]: Почему объектно-ориентированное программирование про
Здравствуйте, Ikemefula, Вы писали:
I>Здравствуйте, samius, Вы писали:
S>>Я немного не об этом. Вот возьмем некий алгебраический тип и функцию, которая принимает его и возвращает новый экземпляр. Можно трактовать этот процесс по Кею следующим образом: экземпляру АТД отправляем сообщение (передаем его функции) и получаем результат сообщения (новый АТД). Естественно, что традиционному ООП это поперек горла. Но в рамках Кея ФП и ООПК(ООП по Кею) можно в каком-то роде совмещать. Это мое предположение, и я без понятия как к этому отнесся бы сам Кей.
I>Традиционному ООП это никак поперек горла быть не может
Оно фактически призывает воспользоваться OCP и заменить ПМ полиморфизмом, предусмотрев дальнейшее расширение иерархии и размазав логику работы метода по разным классам/файлам, а то и прикрутить какойнибудь TemplateMethod.
S>>В моей практике TODO имеют меньшие приоритеты чем issue в трэкере, потому плодятся как кролики. Стараюсь рефакторить сразу.
I>Любой код имеет свой цикл жизни. Рефакторинг удлинняет этот цикл жизни. Но сделать бесконечным просто не получится. Ну и издержки по вермени/деньгами никто не отменял. В конечном итоге становится проще выбросить хотя бы некоторые части и написать их заново.
Конечно и так бывает. Хоть это уже технически рефакторингом не называется, но все еще относится к обсуждаемым материям. Можно например назвать общим словом "улучшайзинг". А можно смотреть на рефакторинг чуть шире, чем того требует определение. Ведь целью рефакторинга не является сохранение функциональности само по себе. Иногда нужно и ломать, что бы на том месте строить что-то новое.
Re[13]: Почему объектно-ориентированное программирование про
Здравствуйте, Ikemefula, Вы писали:
I>Здравствуйте, samius, Вы писали:
S>>Между делом в ООП нигде не сказано что объекты обязаны обладать изменяемым состоянием, хотя и многие ООП паттерны не перенесут иммутабельности.
I>Какие паттерны из ООП не перенесут иммутабельности ?
например Iterator, Observer, State
Re[12]: Почему объектно-ориентированное программирование про
Здравствуйте, samius, Вы писали:
I>>Традиционному ООП это никак поперек горла быть не может S>Оно фактически призывает воспользоваться OCP и заменить ПМ полиморфизмом, предусмотрев дальнейшее расширение иерархии и размазав логику работы метода по разным классам/файлам, а то и прикрутить какойнибудь TemplateMethod.
При чем здесь замена ПМ полиморфизмом ?
Re[14]: Почему объектно-ориентированное программирование про
Здравствуйте, samius, Вы писали:
S>>>Между делом в ООП нигде не сказано что объекты обязаны обладать изменяемым состоянием, хотя и многие ООП паттерны не перенесут иммутабельности.
I>>Какие паттерны из ООП не перенесут иммутабельности ? S>например Iterator, Observer, State
Переносят
yield break на первые два а для State не обязательно хранить ссылку
Re[13]: Почему объектно-ориентированное программирование про
Здравствуйте, Ikemefula, Вы писали:
I>Здравствуйте, samius, Вы писали:
I>>>Традиционному ООП это никак поперек горла быть не может S>>Оно фактически призывает воспользоваться OCP и заменить ПМ полиморфизмом, предусмотрев дальнейшее расширение иерархии и размазав логику работы метода по разным классам/файлам, а то и прикрутить какойнибудь TemplateMethod.
I>При чем здесь замена ПМ полиморфизмом ?
притом что type test не кошерен по ООП
Re[30]: Почему объектно-ориентированное программирование про
Здравствуйте, Ikemefula, Вы писали:
I>>>Соответственно никакого разделения состояния быть не может — декомпозиция проведена, а состояние где было там и осталось.
V>>Все ясно. Что есть по твоему "состояние"?
I>Элементарно — персистед данные.
А ссылка на другой объект в это понятие входит?
I>Принципиально. Состояния может и не быть, а зависимость будет в любом случае.
Чем обеспечивается зависимость? Впрочем, это тот же вопрос, что и предыдущий. Мои наихудшие подозрения оправдались.
I>Вот посмотри внимательно ан мои примеры, я ажно дважды показал разбиение сложного решения на две части. И там и там разбиение по функциональному признаку.
Еще раз крупными буквами — не обязательно, коль декоратор после переработки объектов использует такую функциональность, которая после декомпозиции не нужна в исходном Doer. Давай ты уже сосредоточишься на этом моменте. Бо надоело.
I>>>Ога, сделать жосткую зависимость от другого класса
V>>Уточни, какая именно зависимость. Т.е. подставь сюда идентификаторы: X --> Y.
Хм, я же попросил, во избежание подобного копирования всего кода, конкретно указать зависимую пару (или пары). Ты не справился.
В общем, тебе стоит показать, что сия зависимость не идет в исходном коде по условию задачи. Ты же сам сказал, что присутствует некий дополнительный игрок — еще один класс, который мы не можем изменять. Будь добр, подкорректируй свой пример с учетом этого, и только потом покажи список лишних зависимостей, через простое перечисление, которые я ввел, в сравнении с твоим уточненным примером.
I>>>Опаньки, щас ты снова заговорил про связанность
V>>Знакомое слово услышал? Дык, а конкретные детали декомпозиции я из каких, по-твоему, соображений совершаю?
I>Ранее ты вещал про состояние
Невнимателен. Вещалось про наиболее значимую метрику, которая отражает степень связанности методов объекта с его собственным состоянием.
I>Уже давно было дадено это "локальное ТЗ".
Ладно, попахивает непрошибаемостью и незамутненностью сознания. Если ты не хочешь проработать собственный пример, с учетом собственных дополнений, давай договоримся прикрыть эту лавочку.
I>Адаптер это паттерн более древний, чем ООП
Черт. А фасад? А фабрика с одним методом тогда что? А почему в ФП не рассматривают эти приемы, как отдельные паттерны? Эх коллега, напряг бы что ли, кой чего... Может, в ФП не делают разницы от того, что наличие единственной ф-ии без описания ролей каждого из ее аргументов и истории её создания не позволит восстановить/распознать все происходящее за кулисами? Ведь по сигнатуре "SomeObj func(int arg)" никогда не скажешь, адаптер это, или фабрика.
V>>Дык, это у тебя зависимость от какого-то базового класса (упомянутого устно), и от явно заданного типа IDoer.
I>Враньё. Я говорил совсем друго. Про базовый клас ты выдумал. В очередной раз скипнул, ибо похоже ты уже сам поверил в свое вранье.
Вот надо поменьше говорить, побольше делать. В исходном примере можно было уже сто раз показать свой "особый случай", введя тот самый пресловутый некий класс, о котором так долго говорили большевики (С), и наличие которого для тебя является "элементарным и очевидным". Нам ты пока мест предлагаешь просто поверить тебе на слово. Не прокатит. Ближе к делу! Нарисуй еще раз.
V>>С состоянием и поведением! Иначе это не объект, а просто юзерский тип, описанный ср-вами ООП-языка.
I>Это в с++ тбе надо искать состояние.
Ваш сын еще и курит. А тигру в зоопарке мясо не докладывают.
Re[15]: Почему объектно-ориентированное программирование про
Здравствуйте, Ikemefula, Вы писали:
I>Здравствуйте, samius, Вы писали:
I>>>Какие паттерны из ООП не перенесут иммутабельности ? S>>например Iterator, Observer, State
I>Переносят
I>yield break на первые два
можно подробнее?
I> а для State не обязательно хранить ссылку
в смысле состояние? Да, необязательно хранить ее внутри объекта. Но это уже будет что-то вроде автоматов в хаскеле, к паттерну State не имеющих отношения совершенно.
Re[31]: Почему объектно-ориентированное программирование про
Здравствуйте, vdimas, Вы писали:
I>>Элементарно — персистед данные.
V>А ссылка на другой объект в это понятие входит?
Если персистед, то да. Если нет — то нет
I>>Принципиально. Состояния может и не быть, а зависимость будет в любом случае.
V>Чем обеспечивается зависимость? Впрочем, это тот же вопрос, что и предыдущий. Мои наихудшие подозрения оправдались.
Походу, код показать ты не в состоянии
V>Хм, я же попросил, во избежание подобного копирования всего кода, конкретно указать зависимую пару (или пары). Ты не справился.
Прочесть коммент болдом ты не в состоянии ? Надо было сразу сказать
V>В общем, тебе стоит показать, что сия зависимость не идет в исходном коде по условию задачи. Ты же сам сказал, что присутствует некий дополнительный игрок — еще один класс, который мы не можем изменять. Будь добр, подкорректируй свой пример с учетом этого, и только потом покажи список лишних зависимостей, через простое перечисление, которые я ввел, в сравнении с твоим уточненным примером.
Я показал всё что необходимо.
I>>Адаптер это паттерн более древний, чем ООП
V>Черт. А фасад? А фабрика с одним методом тогда что? А почему в ФП не рассматривают эти приемы, как отдельные паттерны?
ФП это другой уровень
I>>Враньё. Я говорил совсем друго. Про базовый клас ты выдумал. В очередной раз скипнул, ибо похоже ты уже сам поверил в свое вранье.
V>Вот надо поменьше говорить, побольше делать. В исходном примере можно было уже сто раз показать свой "особый случай", введя тот самый пресловутый некий класс, о котором так долго говорили большевики (С),
Ты сам о нем говоришь. А я показал все что необходимо.
>и наличие которого для тебя является "элементарным и очевидным". Нам ты пока мест предлагаешь просто поверить тебе на слово. Не прокатит. Ближе к делу! Нарисуй еще раз.
есть фреймворк для рендеринга изображения. в нем реализованы различные генераторы изображения. каждая такая рисовалка должена реализовать интерфейс IRender(=IDoer) с единственным иметодом void Render(Context ctx); кроме этого есть еще рисовалки реализованые в проекте.
необходимо расширить возможности этого фреймворка диагностикой, валидацией, отладкой и тд
задача 1 — замерить время выполнения некоторых реализаций IRender — любых, как своих так и встроеных. Почему нельзя замерить через профайлер — нужны данные по продакшну, а не по дебагу
задача 2 — параллельно с генерацией изображения записывать генерацию в текстовом виде для валидации, диагностики, отладки
задача 3 — некоторые генераторы косячат. надо подавить их артефакты без перепеисывания. например перед вызовом генератора установить некоторые значения в контексте, а по окончанию вернуть значения назад.
задача 4 — необходимо иметь возможность включать-выключать некоторые генераторы, например при рендеринге на бумагу или экран
задача 5 — необходимо иметь возможность делать отрисовку по требованию, т.е. вместо изображения генерируются команды отрисовки примитивов, который потом можно выполнить в другом фреймворке.
в моем решении ненужно модифицировать ни генераторы, не фреймворк, вообще ничего нужно только сделать один декоратор на каждую задачу.
при этом для задач 1,2,3 и 4 декоторатору вообще не надо ничего знать ни про базовый, ни про Сontext.
1 использует StopWatch и Logger
2 использует логгер
3 использует контекст
4 ничего вообще не использует — у тебя вроятно фантазия не позволит представить такое
и только 5й использует кое какие методы из базового класса и класса Context
покажи внятное, тестируемое решение. если не можешь, объясни внятно, чего тебе не хватает.
Re[14]: Почему объектно-ориентированное программирование про
Здравствуйте, samius, Вы писали:
S>>>Оно фактически призывает воспользоваться OCP и заменить ПМ полиморфизмом, предусмотрев дальнейшее расширение иерархии и размазав логику работы метода по разным классам/файлам, а то и прикрутить какойнибудь TemplateMethod.
I>>При чем здесь замена ПМ полиморфизмом ? S>притом что type test не кошерен по ООП
Это Страуструп так сказал ?
Re[16]: Почему объектно-ориентированное программирование про
Здравствуйте, samius, Вы писали:
I>>yield break на первые два S>можно подробнее?
yield return разумеется
I>> а для State не обязательно хранить ссылку S>в смысле состояние? Да, необязательно хранить ее внутри объекта. Но это уже будет что-то вроде автоматов в хаскеле, к паттерну State не имеющих отношения совершенно.
к тому паттерну что в Гоф, если трактовать исключительно буквально, отношения иметь не будет. А если посмотреть на назначение, обязанности и тд, получается тот же state
Re[32]: Почему объектно-ориентированное программирование про
I>1 Есть некоторые реализации IDoer. Их модифицировать нельзя, например за отсутствием исходного кода. I>2 Есть конкретная реализация IDoer. Её модифицировать можно. I>3 Есть AcceptDoer который модифицировать нельзя, например за отсутствием исходного кода.
Хе, когда ты вообще всё обложил обложил дополнтельными ограничениями, стоило ли требовать проведения объектной декомпозиции, которая, по идее, призвана улучшить дизайн? Тут никакими улучшениями не пахнет, тебе изворачиваться надо.
I>Задача — модифицировать поведение AcceptDoer для ВСЕХ IDoer.
I>Чем тебе поможет абстрагирование от AcceptDoer в этой задаче ?
Тем, что мы аспект может накладывать с противоположной стороны. Вернее, вообще с любой стороны, не утяжеляя дизайн некими "правилами", т.е. имея возможность делать необходимое прямо по-месту:
Заметь, оба раза я предполагаю явный вынос функциональности декоратора (по принципу SR). В отличие от твоей декомпозиции, мне не нужно вводить зависимость декоратора от IDoer, т.е. тот же декоратор можно использовать для других типов, например IDoer2.
Но это всё еще решение с некоторой завязкой на конкретные интерфейсы, да еще на те, которые мы менять не можем. Непорядок, будем избавляться от зависимостей:
public delegate void DoerAsFunc(); // Actionpublic delegate void AcceptorAsFunc(DoerAsFunc); // Action<Action>class DoerAdapter : IDoer {
DoerAsFunc _doerAsFunc;
public DoerAdapter(DoerAsFunc doerAsFunc) { _doerAsFunc = doerAsFunc; }
public Do() { doerAsFunc(); }
}
...
var acceptor = new DoerAcceptor(); // исходный аксептор
AcceptorAsFunc acceptorAsFunc = (doer)=> acceptor.AcceptDoer(new DoerAdapter(doer)); // точка входа до декорирования
Итого, мы вводим всего один адаптер от ФП к ООП — DoerAdapter (обратные "адаптеры" встроены в язык), а в остальном используем стандартные типы Action и Action<Action>, не вводя лишних сущностей в дизайн. Требуемый аспект Decorator накладываем, где удобно, либо как в первом снипете в этом посте, создавая еще одну точку входа AcceptDoer, либо как здесь: http://rsdn.ru/forum/philosophy/4170405.aspx
, связывая аспект с конкретным экземпляром DoerAsFunc.
В общем, философия такая: есть некие типы, над которыми мы не властны, т.е. которые могут мешать дизайну, создавая лишнюю связанность. Адаптируем по-месту с минимальными телодвижениями эти типы под уже имеющуюся инфраструктуру, и забываем в своем дизайне про существование этих особенных типов и про порождаемую ими связанность.
Чем больше типов из уже имеющейся инфраструктуры мы будем использовать (т.н. "стандартные протоколы"), тем меньше будет надобность рефакторинга по мере развития функциональности. Вернее, рефакторинг если будет, то "очень локальный", что и требовалось.
Re[18]: Почему объектно-ориентированное программирование про
Здравствуйте, Ikemefula, Вы писали:
I>Я скипнул порожний текст.
Зря, лучше было помедитировать над ним. Это одна из немногих полезных вещей в нашей длиной дискуссии.
I>Мне очень хочется посмотреть, как же ты зависимость от ThirdParty заменишь на заглушку.
Легко. Давай минимально-необходимый интерфейс этого ThirdParty.
Re[25]: Почему объектно-ориентированное программирование про
Здравствуйте, Ikemefula, Вы писали:
I>Вот это агрегирование базы ты похоже и называешь "разделение состояния"
Ну да, один из способов ООП-декомпозици — это выделение базы с переносом в нее части состояния (все-равно потом агрегируем обратно). Ключевое — один из.
Re[33]: Почему объектно-ориентированное программирование про
Здравствуйте, vdimas, Вы писали:
I>>1 Есть некоторые реализации IDoer. Их модифицировать нельзя, например за отсутствием исходного кода. I>>2 Есть конкретная реализация IDoer. Её модифицировать можно. I>>3 Есть AcceptDoer который модифицировать нельзя, например за отсутствием исходного кода.
V>Хе, когда ты вообще всё обложил обложил дополнтельными ограничениями, стоило ли требовать проведения объектной декомпозиции, которая, по идее, призвана улучшить дизайн? Тут никакими улучшениями не пахнет, тебе изворачиваться надо.
Это не я обложил ограничениями При этом я тебе показал эту самую декомпозицию в действии — извлек декоратор из имеющегося класса.
V>Тем, что мы аспект может накладывать с противоположной стороны. Вернее, вообще с любой стороны, не утяжеляя дизайн некими "правилами", т.е. имея возможность делать необходимое прямо по-месту:
V>... V>// где-то используем V>IDoer doer = GetDoer(); V>decoratedAcceptor(doer); V>[/c#]
Декорировать нужно doer, неужели ты еще не понял ? При чам каждый doer можно декорировать по разному.
V>Заметь, оба раза я предполагаю явный вынос функциональности декоратора (по принципу SR). В отличие от твоей декомпозиции, мне не нужно вводить зависимость декоратора от IDoer, т.е. тот же декоратор можно использовать для других типов, например IDoer2.
см выше.
вызов AcceptDoer он один единственный, от него не надо асбтрагироваться. А вот самих doer много и их функциональность мы и расширям. При этом поведение AcceptDoer меняется именно так как нам надо.
V>Итого, мы вводим всего один адаптер от ФП к ООП — DoerAdapter (обратные "адаптеры" встроены в язык), а в остальном используем стандартные типы Action
итого ты продекорировал совсем не то что надо
Re[19]: Почему объектно-ориентированное программирование про
Здравствуйте, vdimas, Вы писали:
V>Здравствуйте, Ikemefula, Вы писали:
I>>Я скипнул порожний текст.
V>Зря, лучше было помедитировать над ним. Это одна из немногих полезных вещей в нашей длиной дискуссии.
I>>Мне очень хочется посмотреть, как же ты зависимость от ThirdParty заменишь на заглушку.
V>Легко. Давай минимально-необходимый интерфейс этого ThirdParty.
Вообще то этот класс ты сам придумал. Ну да ладно — класс ниже. В нем один метд который делает запись в некоторую базу.
class ThirdParty
{
public void WriteToDatabase(string value);
}
Re[26]: Почему объектно-ориентированное программирование про
Здравствуйте, vdimas, Вы писали:
I>>Вот это агрегирование базы ты похоже и называешь "разделение состояния"
V>Ну да, один из способов ООП-декомпозици — это выделение базы с переносом в нее части состояния (все-равно потом агрегируем обратно). Ключевое — один из.
А ну как состояние остается там же где и было ? т.е. классы другие, обязанности другие, а состояние где было, там и осталось.
Re[15]: Почему объектно-ориентированное программирование про
Здравствуйте, Ikemefula, Вы писали:
I>Здравствуйте, samius, Вы писали:
I>>>yield break на первые два S>>можно подробнее?
I>yield return разумеется
и каким образом итератор с наблюдателем становятся иммутабельными через yield return?
I>>> а для State не обязательно хранить ссылку S>>в смысле состояние? Да, необязательно хранить ее внутри объекта. Но это уже будет что-то вроде автоматов в хаскеле, к паттерну State не имеющих отношения совершенно.
I>к тому паттерну что в Гоф, если трактовать исключительно буквально, отношения иметь не будет. А если посмотреть на назначение, обязанности и тд, получается тот же state
так можно и осла к грузовику приравнять
паттерн не определяется назначением и обязанностями. Структура и участники тоже входят в паттерн.
Re[16]: Почему объектно-ориентированное программирование про
Здравствуйте, samius, Вы писали:
I>>>>При чем здесь замена ПМ полиморфизмом ? S>>>притом что type test не кошерен по ООП
I>>Это Страуструп так сказал ?
S>не помню, кто это сказал
В большинстве случаев type test не нужен и использование его создаёт проблемы. PM — это как раз тот случай где type test это нормально.
Re[17]: Почему объектно-ориентированное программирование про
Здравствуйте, Ikemefula, Вы писали:
I>Здравствуйте, samius, Вы писали:
I>>>>>При чем здесь замена ПМ полиморфизмом ? S>>>>притом что type test не кошерен по ООП
I>>>Это Страуструп так сказал ?
S>>не помню, кто это сказал
I>В большинстве случаев type test не нужен и использование его создаёт проблемы. PM — это как раз тот случай где type test это нормально.
Для АТД и ПМ type test — это нормально. Для иерархии объектов, моделирующих АТД — это не алё.
Re[18]: Почему объектно-ориентированное программирование про
Здравствуйте, samius, Вы писали:
I>>yield return разумеется S>и каким образом итератор с наблюдателем становятся иммутабельными через yield return?
А где ты в них мутабельности углядел ?
I>>к тому паттерну что в Гоф, если трактовать исключительно буквально, отношения иметь не будет. А если посмотреть на назначение, обязанности и тд, получается тот же state S>так можно и осла к грузовику приравнять
В конце Гоф черным по белому написано, что паттерны ни в коем случае не надо рассматривать буквально.
S>паттерн не определяется назначением и обязанностями. Структура и участники тоже входят в паттерн.
структура, участники, обязанности, зависимости остаются на своих местах
Re[18]: Почему объектно-ориентированное программирование про
Здравствуйте, samius, Вы писали:
S>>>не помню, кто это сказал
I>>В большинстве случаев type test не нужен и использование его создаёт проблемы. PM — это как раз тот случай где type test это нормально. S>Для АТД и ПМ type test — это нормально. Для иерархии объектов, моделирующих АТД — это не алё.
Кто такое сказал ? Какие проблемы возникают ? Какие есть более толковые решения ? Или же вопрос чисто идеологический ?
Re[34]: Почему объектно-ориентированное программирование про
Здравствуйте, Ikemefula, Вы писали:
I>Декорировать нужно doer, неужели ты еще не понял ?
Это лишь твоё собственное видение решения, ИМХО довольно кривого, и подгон всего остального под своё решение. Я же сказал, давай задачу целиком. Декорирование по своей своей природе симметрично, и пока что ты не продемонстрировал, почему это надо делать непременно с какой-то одной из сторон. Тем более, что показал оба варианта, и после второго варианта явно напомнил про первый, предоставив свободу выбора.
Подумай, ты же сам сказал, что IDoer менять нельзя, т.е. это "чуждый" нам интерфейс. Это лишь значит, что нам желательно не основывать на нём дизайн, надо наоборот от него изолироваться в том же локальном месте, где этот интерфейс себя обнаруживает. А раз так, то решение декорирования с поддержкой интерфейса IDoer выглядит косяком дизайна. Если посмотрю на всё решение целиком, смогу сказать, насколько грубый косяк (это зависит от степени локальности происходящего). Т.е. пока это лишь очередное предположение, равнозначное остальным. И твоим в т.ч.
I>При чам каждый doer можно декорировать по разному.
Так ради бога, я показал оба варианта. Если связь декоратора с конкретной имплементацией IDoer слаба, то предпочтительней декорировать точку входа. Это банально эффективней в нагруженных сценариях, например, где объекты-наследники IDoer создаются по new тысячи раз в секунду.
V>>Итого, мы вводим всего один адаптер от ФП к ООП — DoerAdapter (обратные "адаптеры" встроены в язык), а в остальном используем стандартные типы Action
I>итого ты продекорировал совсем не то что надо
итого я ответил на вопрос:
Чем тебе поможет абстрагирование от AcceptDoer в этой задаче ?
Т.к. мысль ты не понял, пришлось показать.
В общем, притянутость твоего примера за уши была видна сразу. Пришлось вытаскивать подробности десяток постов, и до сих пор еще куча белых пятен. Немного раздражает, что частности своего решения ты пытаешься выдать за постановку задачи. Повторю, это не прокатит.
Re[35]: Почему объектно-ориентированное программирование про
Здравствуйте, vdimas, Вы писали:
V>Здравствуйте, Ikemefula, Вы писали:
I>>Декорировать нужно doer, неужели ты еще не понял ?
V>Это лишь твоё собственное видение решения, ИМХО довольно кривого, и подгон всего остального под своё решение. Я же сказал, давай задачу целиком.
Задача была дадена, если ты не заметил
V>Подумай, ты же сам сказал, что IDoer менять нельзя, т.е. это "чуждый" нам интерфейс. Это лишь значит, что нам желательно не основывать на нём дизайн, надо наоборот от него изолироваться в том же локальном месте, где этот интерфейс себя обнаруживает. А раз так, то решение декорирования с поддержкой интерфейса IDoer выглядит косяком дизайна.
Ну да, использование thirdparty — "косяк"
I>>При чам каждый doer можно декорировать по разному.
V>Так ради бога, я показал оба варианта. Если связь декоратора с конкретной имплементацией IDoer слаба, то предпочтительней декорировать точку входа. Это банально эффективней в нагруженных сценариях, например, где объекты-наследники IDoer создаются по new тысячи раз в секунду.
А что тебя пугает ? Пусть создаются. Это в с++ надо бояться инстанцирования.
V>итого я ответил на вопрос: V>Т.к. мысль ты не понял, пришлось показать.
Итого — ты спрыгнул на какую то свою задачу.
V>В общем, притянутость твоего примера за уши была видна сразу. Пришлось вытаскивать подробности десяток постов, и до сих пор еще куча белых пятен. Немного раздражает, что частности своего решения ты пытаешься выдать за постановку задачи. Повторю, это не прокатит.
Я тебе дал одну конкретную задачу. Которая вобщем то достаточно часто встрачается
Re[27]: Почему объектно-ориентированное программирование про
Здравствуйте, Ikemefula, Вы писали:
V>>Ну да, один из способов ООП-декомпозици — это выделение базы с переносом в нее части состояния (все-равно потом агрегируем обратно). Ключевое — один из.
I>А ну как состояние остается там же где и было ? т.е. классы другие, обязанности другие, а состояние где было, там и осталось.
Нет, состояние базы из наследника необходимо рассматривать как инкапсулированное в базе. Т.е. всё состояние базового класса надо рассматривать как одно новое поле теперь с совсем другим интерфейсом, а именно с публичным + защищенным интерфейсом базы. Как и в случае других способов композиции объектов, принцип SR никто не отменял.
Re[28]: Почему объектно-ориентированное программирование про
Здравствуйте, vdimas, Вы писали:
I>>А ну как состояние остается там же где и было ? т.е. классы другие, обязанности другие, а состояние где было, там и осталось.
V>Нет, состояние базы из наследника необходимо рассматривать как инкапсулированное в базе. Т.е. всё состояние базового класса надо рассматривать как одно новое поле теперь с совсем другим интерфейсом, а именно с публичным + защищенным интерфейсом базы. Как и в случае других способов композиции объектов, принцип SR никто не отменял.
Не отвлекайся на такие мелочи, жду ответа по двум сообщениям
V>В ФП-языках эти кубики выглядят как алгебраические типы или туплы, иногда именованные — структуры/кортежи. Все кишки наружу и АПИ к ним не нарисуешь, поэтому "чистое ФП" меня не торкает.
А таких "чисто сферических" ФЯ не существует. Во всех реальных ФЯ есть еще один кубик — модуль, который отлично прячет все кишки. Например в тех же ML образных модули даже позволяют разную инкапсуляцию для разных клиентов использующих данный модуль.
Re[19]: Почему объектно-ориентированное программирование про
Здравствуйте, Ikemefula, Вы писали:
I>Здравствуйте, samius, Вы писали:
I>>>yield return разумеется S>>и каким образом итератор с наблюдателем становятся иммутабельными через yield return?
I>А где ты в них мутабельности углядел ?
Хочется спросить навстречу, где ты в них мутабельности не углядел?
итератор сохраняет позицию, в наблюдателе subject сохраняет список наблюдателей.
I>>>к тому паттерну что в Гоф, если трактовать исключительно буквально, отношения иметь не будет. А если посмотреть на назначение, обязанности и тд, получается тот же state S>>так можно и осла к грузовику приравнять
I>В конце Гоф черным по белому написано, что паттерны ни в коем случае не надо рассматривать буквально.
S>>паттерн не определяется назначением и обязанностями. Структура и участники тоже входят в паттерн.
I>структура, участники, обязанности, зависимости остаются на своих местах
Тогда попрошу продемонстрировать, как объект меняет свое поведение без изменения состояния
Re[20]: Почему объектно-ориентированное программирование про
Здравствуйте, Ikemefula, Вы писали:
V>>Легко. Давай минимально-необходимый интерфейс этого ThirdParty.
I>Вообще то этот класс ты сам придумал.
Нет, это по твоим дополнительным вводным та самая объективная реальность, не доступная нам для изменений, на основе которой сделана ф-сть декоратора Pre/Post.
I>Ну да ладно — класс ниже. В нем один метд который делает запись в некоторую базу. I>
I>class ThirdParty
I>{
I> public void WriteToDatabase(string value);
I>}
I>
Этого маловато, коль речь о БД, потому как это запись в "космос". Лучше примерно так:
class ThirdParty
{
public void WriteToDatabase(string value);
public string ReadFromDatabase(string value);
}
Мне демонстрировать ручную заглушку для этого случая или и так всё понятно? Хотя, и для первого случая заглушка может быть полезна для того, например, чтобы проверить, что этот вызов-таки был произведен в нужном месте. Чтобы не вручную, можно юзать какой-нить mock framework:
class ThirdParty
{
public void WriteToDatabase(string value) {}
}
// Мок-фреймворки любят интерфейсы, хотя в ручных заглушках через подмену сборок можно как угодноinterface IDatabase
{
void WriteToDatabase(string value);
}
// Везде в проекте, где ожидается IDatabase пользуем Databaseclass Database : ThirdParty, IDatabase {}
// Пишем тест
[TestMethod]
public void DbTest()
{
MockRepository mocks = new MockRepository();
IDatabase db = mocks.StrictMock<IDatabase >();
Expect.Call(db.WriteToDatabase("expected value"));
mocks.ReplayAll();
// Изолированно тестируем некий прикладной класс
DbClient client = new DbClient();
client.Operate(db);
// проверяем сам факт вызова + правильность аргумента
mocks.VerifyAll();
}
Re[19]: Почему объектно-ориентированное программирование про
Здравствуйте, Ikemefula, Вы писали:
I>Здравствуйте, samius, Вы писали:
S>>>>не помню, кто это сказал
I>>>В большинстве случаев type test не нужен и использование его создаёт проблемы. PM — это как раз тот случай где type test это нормально. S>>Для АТД и ПМ type test — это нормально. Для иерархии объектов, моделирующих АТД — это не алё.
I>Кто такое сказал ? Какие проблемы возникают ? Какие есть более толковые решения ? Или же вопрос чисто идеологический ?
Почитай у Кириевски, ты любишь на него ссылаться.
Re[36]: Почему объектно-ориентированное программирование про
I>Я тебе дал одну конкретную задачу. Которая вобщем то достаточно часто встрачается
Вообще-то, твое решение часто встречается, а не задача. Ты продолжаешь путать уровни задач. Взяв за основу некое решение, ты выходишь на список новых задач, требуемых для его реализации. И приводишь тут этот список, вместо исходной задачи. Людям порой трудно объяснить, чтобы они не плясали от первого же попавшегося решения. Я уже предложил воспользоваться личкой, если неохота тут светить реальные куски кода.
Re[32]: Почему объектно-ориентированное программирование про
Здравствуйте, Ikemefula, Вы писали:
V>>Чем обеспечивается зависимость? Впрочем, это тот же вопрос, что и предыдущий. Мои наихудшие подозрения оправдались.
I>Я уже внятно ответил на этот вопрос в твоем же коде — http://rsdn.ru/forum/philosophy/4171506.1.aspx
Состояния может и не быть, а зависимость будет в любом случае.
Т.е. зависимость не постоянная, а наблюдается лишь в некоторых методах в виде поданных аргументов? Хе, такая зависимость режется проще всего, как раз через упомянутый тобой DI, или функциональный подход (одно и то же).
I>Что бы продолжить разговор про депенденси, ответь сначала вот на этот вопрос http://rsdn.ru/forum/philosophy/4171487.1.aspx
Походу тебе нечем заняться как форуме болтать. Иначе откуда такая незаинтересованность в ответах на собственные вопросы? Там по ссылке всё есть.
I>Прочесть коммент болдом ты не в состоянии ? Надо было сразу сказать
Ну ты нахал, однако:
>Вот есть твои методы PreDo() и PostDo(). Они требовали для своей работы каких-то внутренних полей первоначального класса Doer?
Разумеется не требовали и это элементарно.
>Если требовали, то тебе надо обеспечить доступ к этим полям в новом объекте PreAndPostDoerDecorator, ЧТД.
Во первых, не требовали. Во вторых, они могут пользоваться методами базового класса
I>Ты сам о нем говоришь. А я показал все что необходимо.
Из того, что ты показал не следует твое решение. Вообще.
I>есть фреймворк для рендеринга изображения. в нем реализованы различные генераторы изображения. каждая такая рисовалка должена реализовать интерфейс IRender(=IDoer) с единственным иметодом void Render(Context ctx); кроме этого есть еще рисовалки реализованые в проекте.
I>необходимо расширить возможности этого фреймворка диагностикой, валидацией, отладкой и тд
I>задача 1 — замерить время выполнения некоторых реализаций IRender — любых, как своих так и встроеных. Почему нельзя замерить через профайлер — нужны данные по продакшну, а не по дебагу I>задача 2 — параллельно с генерацией изображения записывать генерацию в текстовом виде для валидации, диагностики, отладки I>задача 3 — некоторые генераторы косячат. надо подавить их артефакты без перепеисывания. например перед вызовом генератора установить некоторые значения в контексте, а по окончанию вернуть значения назад. I>задача 4 — необходимо иметь возможность включать-выключать некоторые генераторы, например при рендеринге на бумагу или экран I>задача 5 — необходимо иметь возможность делать отрисовку по требованию, т.е. вместо изображения генерируются команды отрисовки примитивов, который потом можно выполнить в другом фреймворке.
I>в моем решении ненужно модифицировать ни генераторы, не фреймворк, вообще ничего нужно только сделать один декоратор на каждую задачу.
I>при этом для задач 1,2,3 и 4 декоторатору вообще не надо ничего знать ни про базовый, ни про Сontext.
I>1 использует StopWatch и Logger I>2 использует логгер I>3 использует контекст I>4 ничего вообще не использует — у тебя вроятно фантазия не позволит представить такое
Естественно не позволит, для включения генераторов надо иметь на них ссылку.
I>и только 5й использует кое какие методы из базового класса и класса Context
I>покажи внятное, тестируемое решение. если не можешь, объясни внятно, чего тебе не хватает.
Итого, создавай независимые аспекты, реализующие IRendererAspect, а затем порождай "матрешки" применённых аспектов произвольной вложенности, то бишь комбинируй как угодно аспекты через композицию RendererWithAspect.
Состояние конкретного экземпляра RendererWithAspect определяется конкретными значениями его 2-х приватных полей. Если придти к этому решению от некоего Renderer, в который внутри, помимо собственно рисования, находился отладочный код, то декомпозиция состояния здесь видна невооруженным взглядом. Сейчас Renderer должен только рисовать, а отладочная фигня лежит внутри IRenderAspect. Если некий составной рендерер использует другие рендереры, т.е. сам представляет из себя композицию, то его отладочный вариант аналогично строится на оборачивании каждого вложенного рендерера через RendererWithAspect.
Помимо показанного, комбинировать аспекты можно и явно:
Изоляция тестирования тут простая — отдельно тестируются аспекты на заглушечном renderer, отдельно тестируется каждый рендерер, через заглушечный Context, отдельно сам Context и отдельно RendererWithAspect с обоими заглушечными (хотя не факт, что его примитивный код требует тестирования).
Здравствуйте, samius, Вы писали:
S>Здравствуйте, Ikemefula, Вы писали:
I>>Здравствуйте, samius, Вы писали:
S>>>>>не помню, кто это сказал
I>>>>В большинстве случаев type test не нужен и использование его создаёт проблемы. PM — это как раз тот случай где type test это нормально. S>>>Для АТД и ПМ type test — это нормально. Для иерархии объектов, моделирующих АТД — это не алё.
I>>Кто такое сказал ? Какие проблемы возникают ? Какие есть более толковые решения ? Или же вопрос чисто идеологический ?
S>Почитай у Кириевски, ты любишь на него ссылаться.
А причем тут криевски?
PM по АлгТД это далеко не тоже самое что typetest в ООП.
Для объектов x is A будет верно для любого наследника A, а когда еще и множественное наследование (реализация множества интерфейсов) есть, то этот код будет работать медленно. Кстати именно поэтому классы атрибутов в .NET рекомендуют делать sealed, тогда поиск атрибутов определенного типа работает быстрее.
АлгТД не образуют иерархию, а предоставляют известное на момент компиляции количество вариантов. Поэтому для определения конкретного варианта можно использовать числовой идентификатор и код матчинга будет ужасно эффективным (выбор по таблице).
Re[21]: Почему объектно-ориентированное программирование про
Здравствуйте, gandjustas, Вы писали:
G>Здравствуйте, samius, Вы писали:
S>>Здравствуйте, Ikemefula, Вы писали:
I>>>Здравствуйте, samius, Вы писали:
S>>>>>>не помню, кто это сказал
I>>>>>В большинстве случаев type test не нужен и использование его создаёт проблемы. PM — это как раз тот случай где type test это нормально. S>>>>Для АТД и ПМ type test — это нормально. Для иерархии объектов, моделирующих АТД — это не алё.
I>>>Кто такое сказал ? Какие проблемы возникают ? Какие есть более толковые решения ? Или же вопрос чисто идеологический ?
S>>Почитай у Кириевски, ты любишь на него ссылаться.
G>А причем тут криевски? G>PM по АлгТД это далеко не тоже самое что typetest в ООП.
конечно не то же самое. Речь, видимо, лишь об идентификации конструктора АТД.
G>Для объектов x is A будет верно для любого наследника A, а когда еще и множественное наследование (реализация множества интерфейсов) есть, то этот код будет работать медленно. Кстати именно поэтому классы атрибутов в .NET рекомендуют делать sealed, тогда поиск атрибутов определенного типа работает быстрее.
Согласен. Но при моделировании АТД иерархией наследования, достаточно проверки на точное соответствие
o.GetType() == typeof(SomeADTConstructor)
т.к. иерархия будет двухэтажная (не считая System.Object, если речь о дотнете).
G>АлгТД не образуют иерархию, а предоставляют известное на момент компиляции количество вариантов. Поэтому для определения конкретного варианта можно использовать числовой идентификатор и код матчинга будет ужасно эффективным (выбор по таблице).
образует иерархию (иерархией принято называть дерево наследования вне зависимости от того, известно ли оно все во время компиляции). Да, будет эффективно выполняться. С другой стороны — числовой идентификатор ведет к куче рукописного кода (по идентификатору + метод на каждый вариант). И если код вариантов не генерируется, то это довольно печально.
Но мы говорим вообще об ООП, а не конкретно о ООП via C#. Например, в C++ рассчитывать на наличие RTTI не всегда можно, особенно разрабатывая библиотеки, которые будут использоваться фиг знает где. Да и бытует мнение среди C++-ников, что если потребовался RTTI, значит что-то делается не по ООП. Так что идентификаторы вариантов — практически единственный кошерный путь в С++. Это если речь только об идентификации варианта. Если же нужно сравнение двух АТД (одного типа АТД, но возможно разных вариантов), то оно выливается уже в Template Method, т.к. надо сравнить и идентификаторы вариантов, и вызывать специфичный для конкретных вариантов код проверки равенства.
Но зато в C++ все это можно повесить на препроцессор и шаблоны.
Re[33]: Почему объектно-ориентированное программирование про
Здравствуйте, vdimas, Вы писали:
V>Здравствуйте, Ikemefula, Вы писали:
V>>>Чем обеспечивается зависимость? Впрочем, это тот же вопрос, что и предыдущий. Мои наихудшие подозрения оправдались.
I>>Я уже внятно ответил на этот вопрос в твоем же коде — http://rsdn.ru/forum/philosophy/4171506.1.aspx
I>>Походу, код показать ты не в состоянии
V>Походу тебе нечем заняться как форуме болтать. Иначе откуда такая незаинтересованность в ответах на собственные вопросы? Там по ссылке всё есть.
По ссылке ничего нет — ты не в состоянии написать юнит-тест для своего же класса
V>Ну ты нахал, однако: V>
>>Вот есть твои методы PreDo() и PostDo(). Они требовали для своей работы каких-то внутренних полей первоначального класса Doer?
V>Разумеется не требовали и это элементарно.
Смотри внимательно — последняя фраза моя. В ней говорится что никаких внутренних полей для работы не требуется.
I>>1 использует StopWatch и Logger I>>2 использует логгер I>>3 использует контекст I>>4 ничего вообще не использует — у тебя вроятно фантазия не позволит представить такое
V>Естественно не позволит, для включения генераторов надо иметь на них ссылку.
Твое не позволит. А мое позволяет — см мой пример.
V>Обычная декомпозиция на основе SR. Например так: V>
V>
Задача 4 в принципе не решаема твоим кодом. т.е. для решения которое не покрывает все случаи ты нагородил всяких классов, аспектов и интерфейсов
V>Итого, создавай независимые аспекты, реализующие IRendererAspect, а затем порождай "матрешки" применённых аспектов произвольной вложенности, то бишь комбинируй как угодно аспекты через композицию RendererWithAspect.
см выше
показываю простое решение, которое работает, тестируется и покрывает все пять задач
В реальном коде декорирование вынесено в экстеншн метод, что означает не надо городить говноинтерфейсы для всех возможных аспектов
someThirPartyObject.AcceptRender(widget1.Suppress());
someThirPartyObject.AcceptRender(widget2.Measure());
someThirPartyObject.AcceptRender(widget3.Log());
someThirPartyObject.AcceptRender(widget4.FixAliasing());
someThirPartyObject.AcceptRender(widget5.Deferred());
...
// вот так "аспекты" комбинируются - и без всяких одноразовых говноинтерфейсов
someThirPartyObject.AcceptRender(widget10234.Deferred().FixAliasing().Measure().Log());
...
// а теперь тем же способом рендерим всю сцену
someThirPartyObject.Log().Measure().Render(new Context());
Вот как это сделано, без экстеншнов, они тривиальные
interface IRender
{
void Render(Context ctx);
}
// IRender реализует как мой код, так и ThirdParty, потому я не могу изменить поведение Render
// базовый для декотораторовabstract class RenderDecoratorBase : IRender
{
protected IRender _render;
RenderDecoratorBase(IRender render)
{
_render = render;
}
public abstract void Render(Context ctx);
}
задача 4 - маскировать рендеринг некоторых объектов
class SuppressRendrer : RenderDecoratorBase
{
SuppressRendrer(IRender render):base(render)
{
}
public void Render(Context ctx) { // empty method } // :-) - этот случай тебе фантазия и не подсказала :-)
}
// вот как используется этот декоратор - точно так же, как и все другие.
someThirPartyObject.AcceptRender( new SuppressRendrer(widgetThatIsToBeHidden) );
задача 2 - логировать рендеринг некоторых объектов
class LoggingRendrer : RenderDecoratorBase
{
LoggingRendrer(IRender render):base(render)
{
}
public void Render(Context ctx)
{
Log.Write("RenderBegin");
_render.Render(ctx);
Log.Write("RenderEnd");
} // :-)
}
someThirPartyObject.AcceptRender( new LoggingRendrer(widgetThatIsToBeLogged) );
V>Изоляция тестирования тут простая — отдельно тестируются аспекты на заглушечном renderer, отдельно тестируется каждый рендерер, через заглушечный Context, отдельно сам Context и отдельно RendererWithAspect с обоими заглушечными (хотя не факт, что его примитивный код требует тестирования).
V>Пример тут: http://rsdn.ru/forum/philosophy/4172198.aspx
Здравствуйте, samius, Вы писали:
I>>>>В большинстве случаев type test не нужен и использование его создаёт проблемы. PM — это как раз тот случай где type test это нормально. S>>>Для АТД и ПМ type test — это нормально. Для иерархии объектов, моделирующих АТД — это не алё.
I>>Кто такое сказал ? Какие проблемы возникают ? Какие есть более толковые решения ? Или же вопрос чисто идеологический ?
S>Почитай у Кириевски, ты любишь на него ссылаться.
Ты про визитор ?
Современные ООП языки не умеют PM, сделано это не ради идеологии, а из за сложности реализации синтаксиса.
Даже в функциональных язвках не хватет скобок и прочей дряни и приходится прибегать к [|||||]
Если не про визитор, то см. выше
Вообще понимать ООП как парадигму в корне неверно. Парадигмы есть разные, функциональная, императивная. ООП ложится и на ту, и на другую.
Так шта...
Re[20]: Почему объектно-ориентированное программирование про
Здравствуйте, samius, Вы писали:
I>>А где ты в них мутабельности углядел ? S>Хочется спросить навстречу, где ты в них мутабельности не углядел? S>итератор сохраняет позицию, в наблюдателе subject сохраняет список наблюдателей.
О ужас, это всего лишь конкретная реализация и оптимизация. Во внутрях реализации функциональных языков точно так же. Иммутабельность нужна для пользователя языка, а не для рантайма.
S>>>паттерн не определяется назначением и обязанностями. Структура и участники тоже входят в паттерн.
I>>структура, участники, обязанности, зависимости остаются на своих местах S>Тогда попрошу продемонстрировать, как объект меняет свое поведение без изменения состояния
_currentState.Method();
меняется на
СurrentState().Method();
Все. Больше никаких изменений не нужно, ну и currentState выкинуть.
Re[12]: Почему объектно-ориентированное программирование про
Здравствуйте, FR, Вы писали:
FR>А таких "чисто сферических" ФЯ не существует. Во всех реальных ФЯ есть еще один кубик — модуль, который отлично прячет все кишки. Например в тех же ML образных модули даже позволяют разную инкапсуляцию для разных клиентов использующих данный модуль.
Кишки вообще везде прячутся,только везде прячутся разные кишки. Собственно ориентированый и означает, какие именно кишки прячутся.
Re[21]: Почему объектно-ориентированное программирование про
Здравствуйте, Ikemefula, Вы писали:
I>Здравствуйте, samius, Вы писали:
S>>Тогда попрошу продемонстрировать, как объект меняет свое поведение без изменения состояния
I>_currentState.Method();
I>меняется на
I>СurrentState().Method();
I>Все. Больше никаких изменений не нужно, ну и currentState выкинуть.
Оригинальная трактовка неизменяемости
Re[22]: Почему объектно-ориентированное программирование про
Здравствуйте, samius, Вы писали:
I>>Ты про визитор ?
I>>Современные ООП языки не умеют PM, сделано это не ради идеологии, а из за сложности реализации синтаксиса. S>
S>OCaml — современный объектно-ориентированный язык
S>
Это в первую очередь функциональный, а уже потом — оо. Но раз тебе охота поцепляться к словам, валяй
S>Если ты про C++, VB и C#, то куда им ПМ, если в них нет даже тюплов и АТД S>Про сложность реализации синтаксиса — это ты тоже здорово махнул
Думаешь это я причиной тому, что C++, java, C# это языки с самым сложным синтаксисом ?
Re[23]: Почему объектно-ориентированное программирование про
Здравствуйте, vdimas, Вы писали:
V>ИМХО, не надо быть мега-спецом, чтобы понять описанные способы: V>Какой из 3-х способов вызывает трудности?
Никакой. Тебе просто хочется поиграть в какую то свою задачу.
Что бы распознать вызов PreDo и PostDo не нужен ни лишний класс, как у тебя, ни ушлые техники тестирования вроде подмены сборки.
V>Код наследника от "черного ящика" точно так же тестируется. Этот код надо лишь отделить от базы.
Что ж ты его не отделил ?
V>Показываю техники для всех 3-х вариантов. V>1. V>
V>class ThirdParty {
V> protected abstact int TemplateMethod();
V> protected void EntryPoint() {}
V>}
Ну и клоунада, выбрал удобный для себя интерфейс этого ThirdParty :))) Ну да бог с ним.
V>interface IThirdPartyCallback {
V> int TemplateMethod();
V>}
Ага, вводить лишний интерфейс чисто для тестирования :-)
V>interface IThirdPartyAPI {
V> void EntryPoint();
V>}
и еще один :)))
V>class ThirdPartyAdapter : ThirdParty, IThirdPartyAPI {
V> IThirdPartyCallback _callback;
V> public ThirdPartyAccess(IThirdPartyCallback callback) { _callback = callback; }
V> new public void EntryPoint() { base.EntryPoint(); }
V> protected override int TemplateMethod() { return _callback.TemplateMethod(); }
V>}
И родился небольшой монстрик, цель которого - обеспечить тестируемость ПРИМИТИВНОГО кода
V>public delegate IThirdPartyAPI ThirdPartyFactory(IThirdPartyCallback callback);
V>class InternalParty : IThirdPartyCallback {
V> IThirdPartyAPI _api;
V> public InternalParty(ThirdPartyFactory factory) { _api = factory(this); }
V> public void UsefulMethod() { _api.EntryPoint(); }
V> private int IThirdPartyCallback.TemplateMethod() { return 42; }
V>}
V>
V>Итого, InternalParty тестируется отдельно от ThirdParty, через заглушку, реализующую IThirdPartyAPI. В случае, когда наследование не требуется, вся развязка с целью тестопригодности делается одним интерфейсом или абстрактным классом.
А теперь вернемся к том, что было — ThirdParty это ThirdParty и менять его нельзя за неимением кода.
V>3. Самое что ни на есть решение "в лоб". Создаешь сборку, где в нужных неймспейсах пишешь тестового двойника ThirdParty под некоторые сценарий,
За такую "тестируемость" надо выпиливать из проекта вместе с кодом. Это решение для тех случаев, когда по другому ну никак не выкрутиться, когда другие тесты просто не работают.
V>Способ, с одной стороны, самый трудоемкий, с другой — самый гибкий и самый приближенный к происходящему.
Способ самый ушлый из всех доступных. нет ни наглядности, не простоты реализации, а эффект ровно тот же, как и в других случаях.
I>>итого, что надо сделать, что бы твой декоторатор был тестируемым ?
V>Пройтись по интернету насчет более подробной инфы по указанным способам. Потом поставить у себя технический эксперимент. Возможно — задать пару вопросов в тематических форумах. В итоге, подобрать для вашей инфраструктуры наиболее удобный способ из описанных, или их комбинацию.
Повеселил так повеселил Ты заметил, что у тебя заюзаны чуть не все возможности дотнета что бы задетектить вызов двух методов ?
Тоже неплохо — новое слово в поведенческом тестировании С твоего позволения я запощу ссылку в Тестирование, шоб люди просветились.
Re[23]: Почему объектно-ориентированное программирование про
Здравствуйте, vdimas, Вы писали:
I>>Все что надо сделать — добавить возможность инжектить ThirdParty прямо в декоторатор ровно тем же способом, который был показан чуть выше.
V>Ты уже заблудился. В приведенном тобой примере ты тестируешь PreAndPostDoerDecorator, т.е. вот этот код:
Конечно. Его и надо тестировать, а не ThirdParty. Это называется поведенческое тестирование Цель теста — гарантировать что декорация работает как положено, не вносит неустановленого поведения.
V>Ты напиши изолированный тест для PreAndPostDecorator, который, например, нетривиально пользует базовый ThirdPartyClass. Вот что представляет интерес для тестирования.
Точно такой же подход.
Re[24]: Почему объектно-ориентированное программирование про
Здравствуйте, Ikemefula, Вы писали:
V>>ИМХО, не надо быть мега-спецом, чтобы понять описанные способы: V>>Какой из 3-х способов вызывает трудности?
I>Никакой. Тебе просто хочется поиграть в какую то свою задачу.
Способ изолирования тестирования через заглушки живет вне "каких-то своих" задач.
I>Что бы распознать вызов PreDo и PostDo не нужен ни лишний класс, как у тебя, ни ушлые техники тестирования вроде подмены сборки.
Дык, ты упомянул всего один класс, и тот лишь адаптер, не содержащий целевого кода. Где еще 2 независимых теста для базы и наследника?
V>>Код наследника от "черного ящика" точно так же тестируется. Этот код надо лишь отделить от базы.
I>Что ж ты его не отделил ?
Проблемы с прочтением кода?
I>Ну и клоунада, выбрал удобный для себя интерфейс этого ThirdParty Ну да бог с ним.
Это не "удобный интерфейс", а те самые двааспекта, которые диктуют нам наследование. В ином случае мы бы наследование не рассматривали.
I>Ага, вводить лишний интерфейс чисто для тестирования
В этом и состоит один из способов. Характерно то, что будучи введен лишь для обеспечения тестопригодности, "лишний интерфейс" порой начинают использовать и для целевых прикладных вещей. Ведь происходящее — суть обеспечение изолированности, а оно бывает удобным не только для теста.
V>>interface IThirdPartyAPI { V>> void EntryPoint(); V>>}
I>и еще один
Угу. А всего два. Независимо от сложности базового класса.
I>И родился небольшой монстрик, цель которого — обеспечить тестируемость ПРИМИТИВНОГО кода
Протокол использования базы не факт, что примитивен. В отличие от твоего адаптера из трех строчек, на который ты умудрился написать тест. Мне бы и в голову не пришло. ЭТО примитивно.
I>А теперь вернемся к том, что было — ThirdParty это ThirdParty и менять его нельзя за неимением кода.
А где ты видел, что я его менял? Чукча писатель?
I>За такую "тестируемость" надо выпиливать из проекта вместе с кодом.
За непроходимость и предрассудки надо выпиливать.
I>Это решение для тех случаев, когда по другому ну никак не выкрутиться, когда другие тесты просто не работают.
Спасибо, что процитировал меня. Только пользуйся тегом [q] в другой раз.
V>>Способ, с одной стороны, самый трудоемкий, с другой — самый гибкий и самый приближенный к происходящему.
I>Способ самый ушлый из всех доступных. нет ни наглядности, не простоты реализации, а эффект ровно тот же, как и в других случаях.
Это ты занимаешься проектированием в голове. Уже советовал тебе стадию технического эксперимента.
Внутренности такого класса можно сделать на моках, в том же стиле, как ты написал тестовый код. Более того, это же наш собственный класс — добавь св-во для доступа к экземпляру моковского репозитория внутри, и задавай ожидания теста снаружи. Т.е. нам требуется те же самые тесты "упаковать" в ожидаемый клиентом тип-оболочку. Тем паче, что каждый отдельный тест в общем случае задевает не всё АПИ класса (оно может быть большим), а лишь его некое его подможество. Вот его-то и достаточно нарисовать.
Эффект был упомянут, можешь вернуться прочесть. Там, где развязка на интерфейсах заметно сказывается на производительности, у тебя и выбора-то другого нет, для целей тестирования.
I>Повеселил так повеселил Ты заметил, что у тебя заюзаны чуть не все возможности дотнета что бы задетектить вызов двух методов ?
Тяжелый ты товарищ, однако... Еще и крайне невнимателен.
Два однострочных метода наблюдаются у твоего адаптера. И да, ты такой весь довольный написал код тестирования этих двух однострочных методов. Ну поздравляю. Только я решал другую задачу — изолирование нашего прикладного кода от ненашего. Чтобы иметь возможность написать тест, который ты написать, увы, не можешь. Да плевать, что в некоей конкретной задаче "код простой, тестировать не надо". Я на простом примере показываю, как тебе выкручиваться в сложных. Произвольный наследник внутри своей реализации может дергать доступный ему базовый ThirdParty произвольное кол-во раз по сколь угодно сложному протоколу. Даже если у наследника всего один метод.
I>Тоже неплохо — новое слово в поведенческом тестировании
Это в первую очередь юнит-тестирование, с требованием изолированного тестирования всех участников. Слово "всех" — такое же ключевое, как "изолирование".
А потом уже это поведенческое или какое еще. Не всегда нужны поведенческие тесты, но изолированность — всегда. Иначе непонятно, кого тестируем.
В общем, аргументы у тебя неплохи: целевой прикладной код лучше не тестировать, а то вишь, два лишних интерфейса ради такой ерунды появилось, или, О ужас!, заглушку писать придется... Браво! Профанация кучи потраченного здесь времени. Как же народ раньше писал себе заглушки десятилетиями, до появления мок-фреймворков? Сейчас непокрываемых моками сценариев максимум пару-другую процентов наберется, но ты уже заранее отказываешься их тестировать. Повторное браво!
I>С твоего позволения я запощу ссылку в Тестирование, шоб люди просветились.
Ради бога.
Re[22]: Почему объектно-ориентированное программирование про
Здравствуйте, samius, Вы писали:
I>>_currentState.Method();
I>>меняется на
I>>СurrentState().Method();
I>>Все. Больше никаких изменений не нужно, ну и currentState выкинуть.
S>Оригинальная трактовка неизменяемости
Здесь нет ничего оригинального. Просто не нужно ГоФ понимать буквально.
Re[23]: Почему объектно-ориентированное программирование про
Здравствуйте, Ikemefula, Вы писали:
I>Здравствуйте, samius, Вы писали:
I>>>_currentState.Method();
I>>>меняется на
I>>>СurrentState().Method();
I>>>Все. Больше никаких изменений не нужно, ну и currentState выкинуть.
S>>Оригинальная трактовка неизменяемости
I>Здесь нет ничего оригинального. Просто не нужно ГоФ понимать буквально.
Гоф тут не причем. Если объект изменил внешнее поведение, значит он не может считаться неизменяемым, вне зависимости от того, хранится ли состояние в нем самом, или еще где.
Re[25]: Почему объектно-ориентированное программирование про
Здравствуйте, vdimas, Вы писали:
I>>Никакой. Тебе просто хочется поиграть в какую то свою задачу.
V>Способ изолирования тестирования через заглушки живет вне "каких-то своих" задач.
А выбирается исходя из конкретной задачи. Что бы задетектить вызов двух методов не надо городить ни интерфейсы, ни подменять сборки.
I>>Что бы распознать вызов PreDo и PostDo не нужен ни лишний класс, как у тебя, ни ушлые техники тестирования вроде подмены сборки.
V>Дык, ты упомянул всего один класс, и тот лишь адаптер, не содержащий целевого кода. Где еще 2 независимых теста для базы и наследника?
Я тебе показал весь необходимый код для моего и твоего случаев.
I>>Ну и клоунада, выбрал удобный для себя интерфейс этого ThirdParty Ну да бог с ним.
V>Это не "удобный интерфейс", а те самые два
Если ты плохо понимаешь, то напомню, что интерфейс ThirdParty ты спросил у меня. Вот им и надо было пользваться.
А ты поступил с ThirdParty как со своим собственным кодом
I>>Ага, вводить лишний интерфейс чисто для тестирования
V>В этом и состоит один из способов. Характерно то, что будучи введен лишь для обеспечения тестопригодности, "лишний интерфейс" порой начинают использовать и для целевых прикладных вещей. Ведь происходящее — суть обеспечение изолированности, а оно бывает удобным не только для теста.
1 you aint gonna need it
2 keep it simple, stupid !
протестировать можно без доп. классов, без подмены сборок, без доп. интерфейсов
V>Угу. А всего два. Независимо от сложности базового класса.
Это на два больше чем необходимо
V>Протокол использования базы не факт, что примитивен. В отличие от твоего адаптера из трех строчек, на который ты умудрился написать тест. Мне бы и в голову не пришло. ЭТО примитивно.
При чем здесь база ? Ты все хочешь на какую то свою задачу спрыгнуть.
V>А где ты видел, что я его менял? Чукча писатель?
Видел.Вот твой код:
class ThirdParty {
protected abstact int TemplateMethod();
protected void EntryPoint() {}
}
class ThirdParty
{
public void WriteToDatabase(string value);
}
Судя по всему у тебя или очень короткая память, или ты просто сознательно врёшь
I>>За такую "тестируемость" надо выпиливать из проекта вместе с кодом. V>За непроходимость и предрассудки надо выпиливать.
V>Два однострочных метода наблюдаются у твоего адаптера. И да, ты такой весь довольный написал код тестирования этих двух однострочных методов. Ну поздравляю.
Это был пример. Не все декотораторы такие примитивные.
>Только я решал другую задачу — изолирование нашего прикладного кода от ненашего.
Я решил эту же задачу и вероятно тебе это крайне сложно понять
Re[24]: Почему объектно-ориентированное программирование про
Здравствуйте, samius, Вы писали:
I>>Здесь нет ничего оригинального. Просто не нужно ГоФ понимать буквально.
S>Гоф тут не причем. Если объект изменил внешнее поведение, значит он не может считаться неизменяемым, вне зависимости от того, хранится ли состояние в нем самом, или еще где.
Внешнее поведение это конкретный протокол/контракт. Класс реализует протокол/контракт — реализует. Изменения в протоколе есть — нет. Нарушения контракта есть — нет. Стало быть внешнее не менялось.
Т.е. State меняет _внутреннее_ поведение как раз за счет иммутабельности.
Re[25]: Почему объектно-ориентированное программирование про
Здравствуйте, Ikemefula, Вы писали:
I>Здравствуйте, samius, Вы писали:
S>>Гоф тут не причем. Если объект изменил внешнее поведение, значит он не может считаться неизменяемым, вне зависимости от того, хранится ли состояние в нем самом, или еще где.
I>Внешнее поведение это конкретный протокол/контракт. Класс реализует протокол/контракт — реализует. Изменения в протоколе есть — нет. Нарушения контракта есть — нет. Стало быть внешнее не менялось.
То есть ты прописал изменение поведения в контракт и объявил иммутабельность? браво!
I>Т.е. State меняет _внутреннее_ поведение как раз за счет иммутабельности.
Я не понимаю, о чем ты
Re[26]: Почему объектно-ориентированное программирование про
Здравствуйте, samius, Вы писали:
I>>Внешнее поведение это конкретный протокол/контракт. Класс реализует протокол/контракт — реализует. Изменения в протоколе есть — нет. Нарушения контракта есть — нет. Стало быть внешнее не менялось.
S>То есть ты прописал изменение поведения в контракт и объявил иммутабельность? браво!
Не валяй дурака, ладно ?
Конкретный State это только часть всего поведения, которое описывается протоколом
Поясняю — протоколы описываются без вникания в детали того, как ты будешь реализовывать. Хоть State, хоть Strategy, хоть Template Method, хоть Decorator — абсолютно фиолетово, протокол во всех случаях остаётся ровно один и тот же.
Т.е. конкретный state реализует не весь протокол, а только ЧАСТЬ его.
Хотя я не уверен, возможно ты считаешь, что правила вроде Connect->Send->Disconnect это "изменение поведения в контракт"
I>>Т.е. State меняет _внутреннее_ поведение как раз за счет иммутабельности.
S>Я не понимаю, о чем ты
Ты похоже вообще не понимаешь, что такое протокол.
Re[27]: Почему объектно-ориентированное программирование про
Здравствуйте, Ikemefula, Вы писали:
I>Здравствуйте, samius, Вы писали:
S>>То есть ты прописал изменение поведения в контракт и объявил иммутабельность? браво!
I>Не валяй дурака, ладно ?
I>Конкретный State это только часть всего поведения, которое описывается протоколом
I>Поясняю — протоколы описываются без вникания в детали того, как ты будешь реализовывать. Хоть State, хоть Strategy, хоть Template Method, хоть Decorator — абсолютно фиолетово, протокол во всех случаях остаётся ровно один и тот же.
I>Т.е. конкретный state реализует не весь протокол, а только ЧАСТЬ его.
I>Хотя я не уверен, возможно ты считаешь, что правила вроде Connect->Send->Disconnect это "изменение поведения в контракт"
Походу ты переключился с иммутабельности на контракты.
I>>>Т.е. State меняет _внутреннее_ поведение как раз за счет иммутабельности.
S>>Я не понимаю, о чем ты
I>Ты похоже вообще не понимаешь, что такое протокол.
Походу ты не понимаешь какое отношение у иммутабельности к протоколу, раз переключился на протоколы и контракты.
Объясняю: неизменность состояния с внешней точки зрения (иммутабельность) может быть частью контракта, но неизменность контракта не есть неизменность состояния.
Re[28]: Почему объектно-ориентированное программирование про
Здравствуйте, samius, Вы писали:
I>>Ты похоже вообще не понимаешь, что такое протокол. S>Походу ты не понимаешь какое отношение у иммутабельности к протоколу, раз переключился на протоколы и контракты.
S>Объясняю: неизменность состояния с внешней точки зрения (иммутабельность) может быть частью контракта, но неизменность контракта не есть неизменность состояния.
Здравствуйте, Ikemefula, Вы писали:
I>Здравствуйте, samius, Вы писали:
I>>>Ты похоже вообще не понимаешь, что такое протокол. S>>Походу ты не понимаешь какое отношение у иммутабельности к протоколу, раз переключился на протоколы и контракты.
S>>Объясняю: неизменность состояния с внешней точки зрения (иммутабельность) может быть частью контракта, но неизменность контракта не есть неизменность состояния.
I>Смотри, простой протокол
I>[] -> connect I>connect -> send I>connect -> disconnect I>send -> send I>send -> disconnect I>disconnect -> []
I>Тебе кажется, что это я вношу в такой протокол состояние ? Очнись и пой.
Мне кажется что ты хочешь этот протокол реализовать иммутабельным паттерном State. Пой ты. Это твоя песня.
Re[26]: Почему объектно-ориентированное программирование про
V>>Это не "удобный интерфейс", а те самые два
I>Если ты плохо понимаешь, то напомню, что интерфейс ThirdParty ты спросил у меня. Вот им и надо было пользваться.
Какой бы интерфейс ThirdParty ты не дал, каждый его метод попадает или под первый случай, или под второй. Я же сразу попытался обратить твое внимание, видя твоё, прямо скажем, непонимание вопроса, нафига вообще применяют наследование. И даже ссылки дал. Пойдись по ним предварительно.
I>2 keep it simple, stupid !
Отличный принцип, особенно в свете показанного тобой рядом настоящей задачи и, прямо скажем, спорного решения.
I>протестировать можно без доп. классов, без подмены сборок, без доп. интерфейсов
Ты пока не показал как. Ты лишь написал тест который НЕ НУЖЕН, опустив 2 НУЖНЫХ теста.
V>>Протокол использования базы не факт, что примитивен. В отличие от твоего адаптера из трех строчек, на который ты умудрился написать тест. Мне бы и в голову не пришло. ЭТО примитивно.
I>При чем здесь база ? Ты все хочешь на какую то свою задачу спрыгнуть.
Понимаешь, колега. Я же тебя за коллегу считаю. Если ты с самого начала поставил условие базового класса, то оно должно было быть не от балды, правильно? Есть совсем немного сценариев, где нужно наследование, и эти сценарии я покрыл. Сейчас же ты пытаешься сказать, что ничего этого не надо было. Ну дык, дорогой, тогда в твоем случае наследование выглядит банальным косяком дизайна. Определись.
V>>А где ты видел, что я его менял? Чукча писатель?
I>Видел.Вот твой код:
I>
I>class ThirdParty
I>{
I> public void WriteToDatabase(string value);
I>}
I>
Я так и думал. Двойка за внимательность.
1. protected void SomeMethod() покрывает случай public void SomeMethod()
2. Если нам от класса нужен только публичный интерфейс, то, боюсь, убедить коллег в необходимости наследования от него не удастся. Поэтому, дабы не смешить читателей, были обыграны подробности, однозначно требующие наследования. Т.е. мы взяли такой интерфейс базового класса, который явно был разработан под последующее наследование.
I>Судя по всему у тебя или очень короткая память, или ты просто сознательно врёшь
Нормально с памятью. Я уже говорил, что ты легкомысленнен и невнимателен. По ссылкам стоит ходить и аргументы оппонентов пытаться понять.
V>>Два однострочных метода наблюдаются у твоего адаптера. И да, ты такой весь довольный написал код тестирования этих двух однострочных методов. Ну поздравляю.
I>Это был пример. Не все декотораторы такие примитивные.
Хм... Я уже не знаю, как достучаться... Ты до сих пор не понял собственный код? Тебе его кто-то другой написал и забыл объяснить, что-ли?
Ты протестировал вот это PreAndPostDoerDecorator. А сие не сам декоратор, а адаптер для оных. Никак? Прочти еще раз, потом взгляни на свой
Чтобы протестировать PreAndPostDecorator, необходимо убедиться, что его методы PreDo/PostDo правильно обслуживают протокол базового класса, если есть желание пройтись поведенческим тестом. Либо проверять сайд-эффекты/возвращаемые значения, коль речь идет о функциональных тестах. Понимаешь, ты же не можешь в общем случае гарантировать, что там дергают только виртуальные методы, то бишь имеется возможность использования мок-фреймворков — поэтому остается либо развязка через интерфейсы, либо заглушка в чистом виде, т.е. подмена "боевого" кода на тестовый.
Единственно, что там верно сказано, после того как ты раскрыл детали, это вот это:
Очевидно, решение не самое лучшее, т.к. PreAndPostDecorator вообще не нужен.
Неудивительно, надуманность твоего примера была видна невооруженным взглядом. Да еще не соответствует приведенной в конце концов задаче.
В том посте, где ты раскрыл задачу, я ближе к вечеру пройдусь детально. Бо там надо вернуться к началу, собрать историю возникновения примера и разобрать твое решение. А так же показать где там разделение состояния (и есть ли там состояние вне временного на стеке , плюс не забыть вопросы тестируемости). А это не 5 минут, боюсь 0,5..1 час времени придется угробить.
>>Только я решал другую задачу — изолирование нашего прикладного кода от ненашего.
I>Я решил эту же задачу и вероятно тебе это крайне сложно понять
Пока что тем твои тестом можно подтереться, потому как тестирования собственно PreAndPostDecorator не происходит. Кому и что тут сложно понять, уже очевидно.
Re[27]: Почему объектно-ориентированное программирование про
Здравствуйте, vdimas, Вы писали:
I>>Если ты плохо понимаешь, то напомню, что интерфейс ThirdParty ты спросил у меня. Вот им и надо было пользваться.
V>Какой бы интерфейс ThirdParty ты не дал, каждый его метод попадает или под первый случай, или под второй. Я же сразу попытался обратить твое внимание, видя твоё, прямо скажем, непонимание вопроса, нафига вообще применяют наследование.
Неясно, для чего вообще было притягивать наследование
I>>2 keep it simple, stupid !
V>Отличный принцип, особенно в свете показанного тобой рядом настоящей задачи и, прямо скажем, спорного решения.
Мое решение проще твоего
I>>протестировать можно без доп. классов, без подмены сборок, без доп. интерфейсов
V>Ты пока не показал как. Ты лишь написал тест который НЕ НУЖЕН, опустив 2 НУЖНЫХ теста.
Я показал пример, как писать тестопригодный код и как писать тесты для него.
I>>При чем здесь база ? Ты все хочешь на какую то свою задачу спрыгнуть.
V>Понимаешь, колега. Я же тебя за коллегу считаю. Если ты с самого начала поставил условие базового класса, то оно должно было быть не от балды, правильно?
Не было там условия базового класса, ты похоже в свои выдумки сам поверил
V>2. Если нам от класса нужен только публичный интерфейс, то, боюсь, убедить коллег в необходимости наследования от него не удастся. Поэтому, дабы не смешить читателей, были обыграны подробности, однозначно требующие наследования. Т.е. мы взяли такой интерфейс базового класса, который явно был разработан под последующее наследование.
Я так и думал — ты сознательно изменил условие
I>>Это был пример. Не все декотораторы такие примитивные.
V>Хм... Я уже не знаю, как достучаться... Ты до сих пор не понял собственный код? Тебе его кто-то другой написал и забыл объяснить, что-ли? V>Ты протестировал вот это PreAndPostDoerDecorator. А сие не сам декоратор, а адаптер для оных. Никак?
Хочешь сказать, что ты адаптер назвал декоторатором ? Но вообще говоря, это декоторатор.
V>Чтобы протестировать PreAndPostDecorator, необходимо убедиться, что его методы PreDo/PostDo правильно обслуживают протокол базового класса, если есть желание пройтись поведенческим тестом. Либо проверять сайд-эффекты/возвращаемые значения, коль речь идет о функциональных тестах. Понимаешь, ты же не можешь в общем случае гарантировать, что там дергают только виртуальные методы,
Проверять надо только ключевые методы. Все подряд проверять не нужно, т.к. это в принципе невозможно Если некто вызывает невиртуальный метод с какой то целью, на этапе написания тестов неясно, легальный это вызов или нет.
V>
V>Очевидно, решение не самое лучшее, т.к. PreAndPostDecorator вообще не нужен.
V>Неудивительно, надуманность твоего примера была видна невооруженным взглядом. Да еще не соответствует приведенной в конце концов задаче.
Это твое решение избыточное
V>В том посте, где ты раскрыл задачу, я ближе к вечеру пройдусь детально. Бо там надо вернуться к началу, собрать историю возникновения примера и разобрать твое решение.
Попробуй, посмотри хороший букварь по тестированию предварительно
V>Пока что тем твои тестом можно подтереться, потому как тестирования собственно PreAndPostDecorator не происходит. Кому и что тут сложно понять, уже очевидно.
Конечно. Его и не надо тестировать, ибо класс этот вобще не нужен ни для продакшна ни для тестирования.
Re[30]: Почему объектно-ориентированное программирование про
Здравствуйте, samius, Вы писали:
I>>Тебе кажется, что это я вношу в такой протокол состояние ? Очнись и пой.
S>Мне кажется что ты хочешь этот протокол реализовать иммутабельным паттерном State. Пой ты. Это твоя песня.
Сначала ты ляпнул нечто вроде "ООП паттерны не перенесут иммутабельности.".
Если бы ты сказал, что в языке где нет мутабельных переменных, State нереализуем, то это совсем другой расклад, но получится в духе КО Ибо не будет полноты по Черчу.
Потом ты задним числом решил приписать мне неизвестно что, вот например "реализовать иммутабельным паттерном State"
СurrentState().Method();
Вроде и ежу понятно, что речь идет о разделении обязанностей. Если задача требует изменения состояния, то это особенность _задачи_, а не паттерна, что я тебе и показал на примере протокола. Иммутабельность это способ сведения к минимуму сайт-эффектов. Никто не говорит про абсолютную иммутабельность. Вон в Эрланге её тож нет, хотя там нет мутабельных переменных.
Итого, какие у тебя проблемы возникают с кодом выше ? Если есть что сказать без капитанских банальностей, валяй.
Re[31]: Почему объектно-ориентированное программирование про
Здравствуйте, Ikemefula, Вы писали:
I>Здравствуйте, samius, Вы писали:
I>>>Тебе кажется, что это я вношу в такой протокол состояние ? Очнись и пой.
S>>Мне кажется что ты хочешь этот протокол реализовать иммутабельным паттерном State. Пой ты. Это твоя песня.
I>Сначала ты ляпнул нечто вроде "ООП паттерны не перенесут иммутабельности.".
Да, ляпнул. И привел тебе примеры.
I>Если бы ты сказал, что в языке где нет мутабельных переменных, State нереализуем, то это совсем другой расклад, но получится в духе КО Ибо не будет полноты по Черчу.
Полнота не требует реализуемости ООП паттернов. Она про функции
I>Потом ты задним числом решил приписать мне неизвестно что, вот например "реализовать иммутабельным паттерном State"
I>
I>СurrentState().Method();
I>
I>Вроде и ежу понятно, что речь идет о разделении обязанностей. Если задача требует изменения состояния, то это особенность _задачи_, а не паттерна, что я тебе и показал на примере протокола.
Варьировать состояние объекта — назначение паттерна State. На задачи и протоколы ты перешел. Я говорил о паттернах.
Ты же пытаешься мне втюхать альтернативное решение задачи, которую призван решать обсуждаемый паттерн.
I>Иммутабельность это способ сведения к минимуму сайт-эффектов. Никто не говорит про абсолютную иммутабельность. Вон в Эрланге её тож нет, хотя там нет мутабельных переменных.
иммутабельность это характеристика объекта.
I>Итого, какие у тебя проблемы возникают с кодом выше ? Если есть что сказать без капитанских банальностей, валяй.
Я не вижу объект, чье состояние изменяется согласно назначению паттерна State.
Re[32]: Почему объектно-ориентированное программирование про
I>>Сначала ты ляпнул нечто вроде "ООП паттерны не перенесут иммутабельности.". S>Да, ляпнул. И привел тебе примеры.
I>>Если бы ты сказал, что в языке где нет мутабельных переменных, State нереализуем, то это совсем другой расклад, но получится в духе КО Ибо не будет полноты по Черчу. S>Полнота не требует реализуемости ООП паттернов. Она про функции
С полнотой я погорячился. Но вообще говоря это и есть твоя позиция — "в языке где нет мутабельных переменных, State нереализуем,", правильно ?
Re[33]: Почему объектно-ориентированное программирование про
Здравствуйте, Ikemefula, Вы писали:
I>Здравствуйте, samius, Вы писали:
I>>>Сначала ты ляпнул нечто вроде "ООП паттерны не перенесут иммутабельности.". S>>Да, ляпнул. И привел тебе примеры.
I>>>Если бы ты сказал, что в языке где нет мутабельных переменных, State нереализуем, то это совсем другой расклад, но получится в духе КО Ибо не будет полноты по Черчу. S>>Полнота не требует реализуемости ООП паттернов. Она про функции
I>С полнотой я погорячился. Но вообще говоря это и есть твоя позиция — "в языке где нет мутабельных переменных, State нереализуем,", правильно ?
Нет, это не есть моя позиция. И я ничего не утверждал о мутабельных переменных.
В таком ракурсе объект, не изменяющий свое внутреннее состояние, отлично воспринимается в виде функции и наоборот. Между делом в ООП нигде не сказано что объекты обязаны обладать изменяемым состоянием, хотя и многие ООП паттерны не перенесут иммутабельности.
Я писал об иммутабельности объекта.
Re[34]: Почему объектно-ориентированное программирование про
Здравствуйте, samius, Вы писали:
I>>С полнотой я погорячился. Но вообще говоря это и есть твоя позиция — "в языке где нет мутабельных переменных, State нереализуем,", правильно ? S>Нет, это не есть моя позиция. И я ничего не утверждал о мутабельных переменных. S>
S>В таком ракурсе объект, не изменяющий свое внутреннее состояние, отлично воспринимается в виде функции и наоборот. Между делом в ООП нигде не сказано что объекты обязаны обладать изменяемым состоянием, хотя и многие ООП паттерны не перенесут иммутабельности.
S>Я писал об иммутабельности объекта.
Приведи хороший пример "объект, не изменяющий свое внутреннее состояние" ?
Re[35]: Почему объектно-ориентированное программирование про
Здравствуйте, Ikemefula, Вы писали:
I>Здравствуйте, samius, Вы писали:
S>>Я писал об иммутабельности объекта.
I>Приведи хороший пример "объект, не изменяющий свое внутреннее состояние" ?
System.String
Re[36]: Почему объектно-ориентированное программирование про
Здравствуйте, Ikemefula, Вы писали:
I>Здравствуйте, samius, Вы писали:
I>>>Приведи хороший пример "объект, не изменяющий свое внутреннее состояние" ?
S>>System.String
I>Он не меняет внешнее состояние. Внутреннее может меняться как угодно.
Пусть так, с внутренним я погорячился. Впрочем к иммутабельности относится внешнее состояние, или наблюдаемое состояние через внешний интерфейс.
Re[38]: Почему объектно-ориентированное программирование про
Здравствуйте, samius, Вы писали:
S>>>System.String
I>>Он не меняет внешнее состояние. Внутреннее может меняться как угодно. S>Пусть так, с внутренним я погорячился. Впрочем к иммутабельности относится внешнее состояние, или наблюдаемое состояние через внешний интерфейс.
Итого — проблема была чисто терминологическая. Смотри у меня !
Re[39]: Почему объектно-ориентированное программирование про
Здравствуйте, Ikemefula, Вы писали:
I>Здравствуйте, samius, Вы писали:
S>>>>System.String
I>>>Он не меняет внешнее состояние. Внутреннее может меняться как угодно. S>>Пусть так, с внутренним я погорячился. Впрочем к иммутабельности относится внешнее состояние, или наблюдаемое состояние через внешний интерфейс.
I> Итого — проблема была чисто терминологическая. Смотри у меня !
Т.е. ты согласен с тем, что иммутабельность как неизменность наблюдаемого через внешний интерфейс состояния объекта ломает паттерны ООП Itarator, State, Observer?
Re[40]: Почему объектно-ориентированное программирование про
Здравствуйте, samius, Вы писали:
S>Здравствуйте, Ikemefula, Вы писали:
I>>Здравствуйте, samius, Вы писали:
S>>>>>System.String
I>>>>Он не меняет внешнее состояние. Внутреннее может меняться как угодно. S>>>Пусть так, с внутренним я погорячился. Впрочем к иммутабельности относится внешнее состояние, или наблюдаемое состояние через внешний интерфейс.
I>> Итого — проблема была чисто терминологическая. Смотри у меня !
S>Т.е. ты согласен с тем, что иммутабельность как неизменность наблюдаемого через внешний интерфейс состояния объекта ломает паттерны ООП Itarator, State, Observer?
Очевидно — нет. И я привел тебе хороший пример. Внешнее состояние от внутренней реализации вообще никак не зависит. Это и с итератором и со стейтом и обсервером.
Здравствуйте, Ikemefula, Вы писали:
I>Здравствуйте, samius, Вы писали:
S>>Т.е. ты согласен с тем, что иммутабельность как неизменность наблюдаемого через внешний интерфейс состояния объекта ломает паттерны ООП Itarator, State, Observer?
I>Очевидно — нет. И я привел тебе хороший пример. Внешнее состояние от внутренней реализации вообще никак не зависит. Это и с итератором и со стейтом и обсервером.
I>Смотри: I>
Здравствуйте, samius, Вы писали:
I>>Где ты здесь видишь изменяемое внешнее состояние ?
S>Здесь я предполагаю IO, о какой неизменяемости ты говоришь по отношению к IO?
А если бы там были методы A, B, С ?
Выходит, тебе таки нужны подробности внутренней реализации ? При чем тогда наблюдаемое внешнее состояние ?
Выходит, снова получается очередное капитанское утверждение
Re[43]: Почему объектно-ориентированное программирование про
Здравствуйте, Ikemefula, Вы писали:
I>Здравствуйте, samius, Вы писали:
I>>>Где ты здесь видишь изменяемое внешнее состояние ?
S>>Здесь я предполагаю IO, о какой неизменяемости ты говоришь по отношению к IO?
I>А если бы там были методы A, B, С ?
Тогда было бы неясно, ради чего там State
I>Выходит, тебе таки нужны подробности внутренней реализации ? При чем тогда наблюдаемое внешнее состояние?
Мне нужны подробности контракта. Притом что в зависимости от наличия вызова Connect, метод Send даст тот либо иной результат при некотором предполагаемом контракте. Если нигде ничего не изменится от вызова Send, то нафиг он нужен? Если ничего не меняется от вызова Connect, то зачем он?
I>Выходит, снова получается очередное капитанское утверждение
Выходит ты провоцируешь капитанские утвреждения капитанскими примерами.
Re[44]: Почему объектно-ориентированное программирование про
Здравствуйте, samius, Вы писали:
I>>А если бы там были методы A, B, С ? S>Тогда было бы неясно, ради чего там State
А ты всегда смотришь, каким образом класс реализует свой внешний интерфейс ?
I>>Выходит, тебе таки нужны подробности внутренней реализации ? При чем тогда наблюдаемое внешнее состояние? S>Мне нужны подробности контракта. Притом что в зависимости от наличия вызова Connect, метод Send даст тот либо иной результат при некотором предполагаемом контракте. Если нигде ничего не изменится от вызова Send, то нафиг он нужен? Если ничего не меняется от вызова Connect, то зачем он?
Вот именно, нафиг он нужен. Вот это и есть иммутабельность как в классе System.String.
I>>Выходит, снова получается очередное капитанское утверждение S>Выходит ты провоцируешь капитанские утвреждения капитанскими примерами.
Выходит, что ты изначально ляпнул, не подумав. Изменяемое внешнее состояние придумываю не я, а это требует протокол. Потому иммутабельность тут помешать ну никак не может, только в ущерб задаче.
Re[45]: Почему объектно-ориентированное программирование про
Здравствуйте, Ikemefula, Вы писали:
I>Выходит, что ты изначально ляпнул, не подумав. Изменяемое внешнее состояние придумываю не я, а это требует протокол. Потому иммутабельность тут помешать ну никак не может, только в ущерб задаче.
Выходит ты встрял не подумав. Я сказал что иммутабельность противоречит паттернам ООП, ты же мне начал доказывать что?
Вот это было к чему?
CurrentState().Method()?
Где иммутабельные Iterator/Observer?
Re[46]: Почему объектно-ориентированное программирование про
Здравствуйте, Ikemefula, Вы писали:
I>Здравствуйте, samius, Вы писали:
S>>CurrentState().Method()?
???
S>>Где иммутабельные Iterator/Observer?
I>yield return
Ты знаешь что стоит за этой конструкцией?
Re[48]: Почему объектно-ориентированное программирование про
Здравствуйте, Ikemefula, Вы писали:
I>Здравствуйте, samius, Вы писали:
S>>>>Где иммутабельные Iterator/Observer?
I>>>yield return S>>Ты знаешь что стоит за этой конструкцией?
I>Конечно.
Тогда согласно какой логике ты решение на IEnumerator приводишь в качестве иммутабельного?
Re[50]: Почему объектно-ориентированное программирование про
Здравствуйте, samius, Вы писали:
I>>Конечно. S>Тогда согласно какой логике ты решение на IEnumerator приводишь в качестве иммутабельного?
Согласно обычной формальной логике.
Честно говоря я не понимаю, что ты хочешь сказать
Раз уж ты высказался что де три паттерна не перенесут иммутабельности, будь добр показать это на примере, как именно они не перенесут эту иммутабельность.
Без этого разговаривать смысла нет, ибо похоже под твои невнятные формулировки подходит почти все что угодно вместе со всем оставшимся
Re[51]: Почему объектно-ориентированное программирование про
Здравствуйте, Ikemefula, Вы писали:
I>Здравствуйте, samius, Вы писали:
I>>>Конечно. S>>Тогда согласно какой логике ты решение на IEnumerator приводишь в качестве иммутабельного?
I>Согласно обычной формальной логике.
Это дает мне повод думать что ты IEnumerator считаешь неизменяемым.
I>Честно говоря я не понимаю, что ты хочешь сказать
I>Раз уж ты высказался что де три паттерна не перенесут иммутабельности, будь добр показать это на примере, как именно они не перенесут эту иммутабельность.
Я не буду добр, потому как не понимаю твою "обычную формальную логику"
I>Без этого разговаривать смысла нет, ибо похоже под твои невнятные формулировки подходит почти все что угодно вместе со всем оставшимся
Мне показалось что это ты любитель вольной трактовки терминов и формулировок. Тому примеры — полнота по Чёрчу, трактовка иммутабельности, и даже паттернов.
Согласен, смысла нет.
Re[52]: Почему объектно-ориентированное программирование про
Здравствуйте, samius, Вы писали:
I>>Раз уж ты высказался что де три паттерна не перенесут иммутабельности, будь добр показать это на примере, как именно они не перенесут эту иммутабельность. S>Я не буду добр, потому как не понимаю твою "обычную формальную логику"
Одако, своё высказывание ты не в состоянии пояснить Вот так всегда — попросишь уточнить, как тут же находится какое то оправдание.
Re[53]: Почему объектно-ориентированное программирование про
Здравствуйте, Ikemefula, Вы писали:
I>Здравствуйте, samius, Вы писали:
I>>>Раз уж ты высказался что де три паттерна не перенесут иммутабельности, будь добр показать это на примере, как именно они не перенесут эту иммутабельность. S>>Я не буду добр, потому как не понимаю твою "обычную формальную логику"
I>Одако, своё высказывание ты не в состоянии пояснить Вот так всегда — попросишь уточнить, как тут же находится какое то оправдание.
Я тебе поясню так: если ты считаешь IEnumerator иммутабельным, то для тебя и State и Iterator и Observer будут иммутабельными, как и многое другое. Разубеждать тебя не собираюсь.
Re[54]: Почему объектно-ориентированное программирование про
Здравствуйте, samius, Вы писали:
I>>Одако, своё высказывание ты не в состоянии пояснить Вот так всегда — попросишь уточнить, как тут же находится какое то оправдание.
S>Я тебе поясню так: если ты считаешь IEnumerator иммутабельным, то для тебя и State и Iterator и Observer будут иммутабельными, как и многое другое. Разубеждать тебя не собираюсь.
Тут одно из двух — или мы говорим про разные вещи, или у тебя обострение капитанской очевидности.
Поскольку свою точку зрения ты отказываешься пояснить, смысла продолжать нету
Re[55]: Почему объектно-ориентированное программирование про
Здравствуйте, Ikemefula, Вы писали:
I>Здравствуйте, samius, Вы писали:
I>>>Одако, своё высказывание ты не в состоянии пояснить Вот так всегда — попросишь уточнить, как тут же находится какое то оправдание.
S>>Я тебе поясню так: если ты считаешь IEnumerator иммутабельным, то для тебя и State и Iterator и Observer будут иммутабельными, как и многое другое. Разубеждать тебя не собираюсь.
I>Тут одно из двух — или мы говорим про разные вещи, или у тебя обострение капитанской очевидности.
Очень похоже на то что про разные вещи. Я говорю об иммутабельности, а ты о протоколах
I>Поскольку свою точку зрения ты отказываешься пояснить, смысла продолжать нету
Я пытался, но ты все время подразумеваешь что-то свое и пытаешься опровергнуть.
Вот ответь, контракт IEnumerator подразумевает иммутабельность?
Re[56]: Почему объектно-ориентированное программирование про
Здравствуйте, samius, Вы писали:
I>>Поскольку свою точку зрения ты отказываешься пояснить, смысла продолжать нету S>Я пытался, но ты все время подразумеваешь что-то свое и пытаешься опровергнуть.
Дай ка ссылку, где ты пояснил напримерах свое высказывание ?
S>Вот ответь, контракт IEnumerator подразумевает иммутабельность?
Нет, в эти игры мы играть не будем. Сперва дай внятную, проверяемую трактовку своего высказывания, а потом продолжим.
Не способен приводить примеры — просто не отвечай, не переживай, не ты первый
Re[58]: Почему объектно-ориентированное программирование про
Здравствуйте, samius, Вы писали:
I>>Дай ка ссылку, где ты пояснил напримерах свое высказывание ? S> S>Пытался пояснить и пытался пояснить на примерах — это разные вещи, не мухлюй
Я не заметил что бы ты пытался подвести. А вот выпендрёжа разного сорта было более чем достаточно. Может это по твоему "подвести" — я не в курсе
I>>Нет, в эти игры мы играть не будем. Сперва дай внятную, проверяемую трактовку своего высказывания, а потом продолжим. S>Какого именно высказывания? Мне все больше кажется, что ты начал спорить с тем, чего не понял. Ну да я тут не причем.
Ну да, ты чисто д'артаньян, выдал нечто в духе КО и после этого "ни при чем"
I>>Не способен приводить примеры — просто не отвечай, не переживай, не ты первый
S>Потом я начал выяснять, не считаешь ли ты IEnumerator иммутабельным. А ты отказываешься играть в эти игры.
Ну это как бы просто — ты делаешь странные заявления, никак не поясняя свои высказывания, да еще хочешь что бы тебе все по полочкам раскладывал.
Внятно сформулируй, если есть чего сформулировать, и поясни, желательно на примере, потом продолжим, ибо я хочу убедиться что вся эта беседа имела хоть какой то смысл.
Re[59]: Почему объектно-ориентированное программирование про
Здравствуйте, Ikemefula, Вы писали:
I>Здравствуйте, samius, Вы писали:
I>Ну это как бы просто — ты делаешь странные заявления, никак не поясняя свои высказывания, да еще хочешь что бы тебе все по полочкам раскладывал.
I>Внятно сформулируй, если есть чего сформулировать, и поясни, желательно на примере, потом продолжим, ибо я хочу убедиться что вся эта беседа имела хоть какой то смысл.
Все что я формулировал было достаточно внятно для моего собеседника, во всяком случае от него претензий не последовало. Ты походу что-то не понял и кинулся доказывать что я не прав. Я тебе что-то должен после этого?
Re[9]: Почему объектно-ориентированное программирование пров
S>Возьмём тот же проект. Он обладает идентичностью и состоянием. Можем ли мы построить класс, описывающий объект "проект"?
конечно, можно. как минимум можно в виде набора классов
S>Очень сомнительно. "Поведение" проекта не является прямой реакцией на происходящие с ним события; окажется, что детали того, как проект меняет своё состояние не являются для него "внутренне присущими". Ровно наоборот: ограничения на эволюцию состояний проекта определяются внешними по отношению к нему бизнес-правилами. Попытка инкапсулировать бизнес-правила внутрь класса "проект" обречена на провал.
и кто сказал, что класс должен описывать лишь внутреннее состояние объекта? и не должен описывать поведение набора объектов?
есть даже набор паттернов, которые описывают именно поведение набора объектов
S>Кроме того, на разных стадиях жизненного цикла поведение проекта настолько отличается, что мы затруднимся построить единый класс для описания этого поведения. С точки зрения ООП проект выглядит так, как будто его класс меняется радикальным образом. А в ООП связь класса с объектом является священной и неизменной.
но это лишь main-stream языки утверждают, что класс у объекта должен быть статичным
S>Конечно же, паттерны для разрешения этого (и других) противоречия существуют и хорошо известны. Но их применение неизбежно приводит к тому, что мы получаем катастрофически далёкое от оригинальной модели описание. S>В том же управлении проектами вместо "проекта" появятся какие-то абстрактные "issue", "transition", "attribute", "requirement" и мы быстро перейдём к программированию собственно прикладной логики на основе совсем другого "языка", в котором нет никакого ООП.
как это без ООП, если issue, transition, attrubute и requirement — это есть всамделишные объекты?
Re[10]: Почему объектно-ориентированное программирование про
Здравствуйте, DarkGray, Вы писали: DG>конечно, можно. как минимум можно в виде набора классов И чему в "реальной модели" будут соответствовать эти классы из "набора"?
В реальности объектная модель, якобы построенная на основе той модели, которая описывает предмет автоматизации, стремительно разъезжается.
DG>и кто сказал, что класс должен описывать лишь внутреннее состояние объекта? и не должен описывать поведение набора объектов?
Не понял про описание поведения набора объектов в классе. С точки зрения классического ООП, класс описывает поведение своих объектов.
DG>есть даже набор паттернов, которые описывают именно поведение набора объектов
Я про них написал ниже — не забегайте вперёд.
DG>но это лишь main-stream языки утверждают, что класс у объекта должен быть статичным
Ок, покажите мне немейнстрим-ООП, в котором работает смена класса объекта на лету.
DG>как это без ООП, если issue, transition, attrubute и requirement — это есть всамделишные объекты?
Какие же они всамделишные? Их не было в той модели, которая задокументирована на входе. Это в чистом виде артефакт изготовления. Уже из них строится реальная программа для решения конечной задачи, а не из классов, методов и прочих свойств и интерфейсов.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[11]: Почему объектно-ориентированное программирование про
DG>>конечно, можно. как минимум можно в виде набора классов S> И чему в "реальной модели" будут соответствовать эти классы из "набора"? S>В реальности объектная модель, якобы построенная на основе той модели, которая описывает предмет автоматизации, стремительно разъезжается.
той или иной грани проекта.
только чисто из языка у проекта есть 4 смысла
1) (план) design [], (technical) plan
2) (рд.; черновой вариант) draft (attr)
3) (замысел) scheme, plan, project
4) (предприятие, инициатива) project
DG>>и кто сказал, что класс должен описывать лишь внутреннее состояние объекта? и не должен описывать поведение набора объектов? S>Не понял про описание поведения набора объектов в классе. С точки зрения классического ООП, класс описывает поведение своих объектов.
спорно.
например, operator + , в общем случае, описывает поведение не только своего объекта, но при этом operator + является частью класса и частью ООП.
DG>>но это лишь main-stream языки утверждают, что класс у объекта должен быть статичным S>Ок, покажите мне немейнстрим-ООП, в котором работает смена класса объекта на лету.
Objects in Python can change their class by setting the __class__ attribute
DG>>как это без ООП, если issue, transition, attrubute и requirement — это есть всамделишные объекты? S>Какие же они всамделишные? Их не было в той модели, которая задокументирована на входе. Это в чистом виде артефакт изготовления. Уже из них строится реальная программа для решения конечной задачи, а не из классов, методов и прочих свойств и интерфейсов.
и чему это противоречит?
цемента, арматуры, а тем более лесов и крана тоже нет при постановке задачи построить дом, но при строительстве всё это появляется
при переходе от постановки к реализации прошел этап детализации, и появились более атомарные сущности (объекты).
что в этом такого странного? и в чем противоречие с ООП?
Re[11]: Почему объектно-ориентированное программирование про
чтобы не быть голословными лучше опираться на какую-нибудь задачу.
давай постановку задачи про проекты, которая по твоему плохо описывается при помощи ООП.
Re[12]: Почему объектно-ориентированное программирование про
Здравствуйте, DarkGray, Вы писали:
DG>чтобы не быть голословными лучше опираться на какую-нибудь задачу. DG>давай постановку задачи про проекты, которая по твоему плохо описывается при помощи ООП.
Посмотрите на MS Project. Прикиньте, с какими сущностями имеет дело пользователь. Ну там — ресурсы, задачи, расписания. Задача там, в сущности, ровно одна — выполнить leveling.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[12]: Почему объектно-ориентированное программирование про
Здравствуйте, DarkGray, Вы писали: DG>той или иной грани проекта. DG>только чисто из языка у проекта есть 4 смысла DG>1) (план) design [], (technical) plan DG>2) (рд.; черновой вариант) draft (attr) DG>3) (замысел) scheme, plan, project DG>4) (предприятие, инициатива) project
Никакой грани того проекта, в терминах которго мыслит пользователь эти объекты соответствовать не будут.
Упрощённый пример на ту же тему — детям всегда рассказывают про прямоугольники и квадраты при иллюстрации ООП. А в жизни там ровно один тип данных — Polyline, никакого красивого наследования и полиморфизма.
DG>спорно. DG>например, operator + , в общем случае, описывает поведение не только своего объекта, но при этом operator + является частью класса и частью ООП.
Догадываюсь, что вы имеете в виду, но всё же покажите код этого оператора, чтобы показать, как он влияет на поведение чужих объектов. Желательно ещё чтобы это всё-таки были объекты, а не экземпляры АТД с value-семантикой.
DG>Objects in Python can change their class by setting the __class__ attribute
Спасибо, не знал. Буду иметь в виду.
DG>и чему это противоречит?
Это противоречит утверждению о том, что в ООП классы используются для воспроизведения каких-то компонентов исходной модели.
DG>цемента, арматуры, а тем более лесов и крана тоже нет при постановке задачи построить дом, но при строительстве всё это появляется
При этом никто не утверждает, что арматура хорошо моделирует представления жильца о будущем доме. Тем более леса и кран.
DG>при переходе от постановки к реализации прошел этап детализации, и появились более атомарные сущности (объекты).
Они не более атомарные. Они просто другие. Вообще другие.
DG>что в этом такого странного? и в чем противоречие с ООП?
Противоречие не с ООП. Противоречие — с идиотским предположением о том, что ООП предлагает лепить классы с сущностей модели. Если у вас встанет задача смоделировать управление стройкой, то в вашем коде не будет никаких TКран, ТБульдозер, ТКаменщик или ТЦементМарки400.
Ничего из того, во что можно ткнуть пальцем на стройке, не проникнет в реальную модель вашей программы. Зато будет дохрена всяких штук типа TEditingSession, TChange, TMainWindow и прочего, что моделирует устройство исключительно самой программы. Никто в здравом уме не будет наследовать TПрораба от ТБригадира. Будет (в лучшем случае!) класс TEmployee. А то и его не будет — прекрасно обойдёмся тупо DataSet/DataRow, потому что никакого полиморфизма поведения у работников на стройке не предусмотрено.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[13]: Почему объектно-ориентированное программирование про
DG>>чтобы не быть голословными лучше опираться на какую-нибудь задачу. DG>>давай постановку задачи про проекты, которая по твоему плохо описывается при помощи ООП. S>Посмотрите на MS Project. Прикиньте, с какими сущностями имеет дело пользователь. Ну там — ресурсы, задачи, расписания. Задача там, в сущности, ровно одна — выполнить leveling.
не знаю, что такое leveling.
но знаю, что ms project можно считать редактором проекта, в смысле, плана
т.е. ты предлагаешь поговорить о задаче редактировании проекта?
Re[14]: Почему объектно-ориентированное программирование про
Здравствуйте, DarkGray, Вы писали: S>>Посмотрите на MS Project. Прикиньте, с какими сущностями имеет дело пользователь. Ну там — ресурсы, задачи, расписания. Задача там, в сущности, ровно одна — выполнить leveling.
DG>не знаю, что такое leveling.
Назначение задач ресурсам и срокам так, чтобы удовлетворить зависимости и ограничения. DG>но знаю, что ms project можно считать редактором проекта, в смысле, плана
DG>т.е. ты предлагаешь поговорить о задаче редактировании проекта?
Да, например.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[20]: Почему объектно-ориентированное программирование про
I>>А где ты в них мутабельности углядел ? S>Хочется спросить навстречу, где ты в них мутабельности не углядел? S>итератор сохраняет позицию, в наблюдателе subject сохраняет список наблюдателей.
Это потому, что имеющаяся реализация yield return реализует стандартный IEnumerable<T>. Её можно было бы "починить", если бы результат GetEnumerator реализовывал бы ICloneable<IEnumerator<T>>.
А окончательно её можно было бы починить, если бы в IEnumerator<T> MoveNext возвращал не void, а IEnumerator<T>.
Тогда бы за хранение состояния отвечал бы клиентский код, вместо $iterator.MoveNext было бы $iterator=$iterator.MoveNext.
S>Тогда попрошу продемонстрировать, как объект меняет свое поведение без изменения состояния
Классика жанра — результатом вызова модифицирующих методов является новый объект.
См. напр. System.String.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[54]: Почему объектно-ориентированное программирование про
Здравствуйте, samius, Вы писали:
S>Я тебе поясню так: если ты считаешь IEnumerator иммутабельным, то для тебя и State и Iterator и Observer будут иммутабельными, как и многое другое. Разубеждать тебя не собираюсь.
Ну, вот в нашем любимом дотнете обзёрвер таки реализован на иммутабельных делегатах.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[21]: Почему объектно-ориентированное программирование про
Здравствуйте, Sinclair, Вы писали:
S>Здравствуйте, samius, Вы писали:
I>>>А где ты в них мутабельности углядел ? S>>Хочется спросить навстречу, где ты в них мутабельности не углядел? S>>итератор сохраняет позицию, в наблюдателе subject сохраняет список наблюдателей. S>Это потому, что имеющаяся реализация yield return реализует стандартный IEnumerable<T>. Её можно было бы "починить", если бы результат GetEnumerator реализовывал бы ICloneable<IEnumerator<T>>. S>А окончательно её можно было бы починить, если бы в IEnumerator<T> MoveNext возвращал не void, а IEnumerator<T>. S>Тогда бы за хранение состояния отвечал бы клиентский код, вместо $iterator.MoveNext было бы $iterator=$iterator.MoveNext.
Задача перебора будет решена, но это уже не паттерн Iterator
S>>Тогда попрошу продемонстрировать, как объект меняет свое поведение без изменения состояния S>Классика жанра — результатом вызова модифицирующих методов является новый объект. S>См. напр. System.String.
Но при этом исходный объект свое наблюдаемое состояние не меняет. Классика жанра основана именно на этом.
Re[55]: Почему объектно-ориентированное программирование про
Здравствуйте, Sinclair, Вы писали:
S>Здравствуйте, samius, Вы писали:
S>>Я тебе поясню так: если ты считаешь IEnumerator иммутабельным, то для тебя и State и Iterator и Observer будут иммутабельными, как и многое другое. Разубеждать тебя не собираюсь. S>Ну, вот в нашем любимом дотнете обзёрвер таки реализован на иммутабельных делегатах.
Да, но при этом наблюдаемый объект не может быть иммутабельным.
Я не утверждаю что задачу паттерна наблюдатель нельзя решить в иммутабельном стиле. Я утверждаю что это будет не ООП паттерн наблюдатель.
Re[22]: Почему объектно-ориентированное программирование про
Здравствуйте, samius, Вы писали:
S>Здравствуйте, Sinclair, Вы писали:
S>>Это потому, что имеющаяся реализация yield return реализует стандартный IEnumerable<T>. Её можно было бы "починить", если бы результат GetEnumerator реализовывал бы ICloneable<IEnumerator<T>>. S>>А окончательно её можно было бы починить, если бы в IEnumerator<T> MoveNext возвращал не void, а IEnumerator<T>. S>>Тогда бы за хранение состояния отвечал бы клиентский код, вместо $iterator.MoveNext было бы $iterator=$iterator.MoveNext. S>Задача перебора будет решена, но это уже не паттерн Iterator
Это собственно будет намного ближе к монаде State чем к паттерну Iterator. И это очень и очень далекие вещи, хоть и могут решать схожие задачи.
Re[23]: Почему объектно-ориентированное программирование про
Здравствуйте, Sinclair, Вы писали:
S>Здравствуйте, samius, Вы писали:
S>>>Тогда бы за хранение состояния отвечал бы клиентский код, вместо $iterator.MoveNext было бы $iterator=$iterator.MoveNext. S>>Задача перебора будет решена, но это уже не паттерн Iterator S>В узком смысле — да. В широком смысле — паттерн по-прежнему имеет смысл.
Поспешил я. Иммутабельности ведь нет (см выделенное), хоть перебрать иммутабельно все-таки можно через рекурсию, либо свертку.
И все-таки. Итератором в широком смысле этот подход назвать можно. И даже нужно, наряду с другими подходами, перечисленными в The Essence of the Iterator Pattern.
Но итератором по GoF это не является, а именно этот конкретный паттерн я подразумевал изначально.
S>>>Классика жанра — результатом вызова модифицирующих методов является новый объект. S>>>См. напр. System.String. S>>Но при этом исходный объект свое наблюдаемое состояние не меняет. Классика жанра основана именно на этом. S>В принципе, да. С другой стороны, философия классики в том, что объект имеет право реагировать на сообщения с учётом своего состояния, и в том что другого способа узнать состояние объекта нет.
Согласен, но с уточнением что не своего, а вообще любого состояния. Неизменяемым считается тот объект, который реагирует идентично на все сообщения на протяжении всего своего существования, не зависимо от side-effectoв, фаз луны, и прочего вроде наличия слушателя на другом конце TCP.
S>Вопрос, является ли неизменяемое состояние вообще состоянием или нет — весьма философский. Ну, то есть мы могли бы с тем же успехом считать объект вместе со встроенным состоянием объектом отдельного "класса" — ведь именно класс диктует поведение объекта. Итератор, показывающий на последний элемент списка, всегда вернёт null из MoveNext.
Полагаю что речь исключительно об итераторе, который возвращает новый итератор при MoveNext, явно ничего не изменяя.
Тогда тут два аспекта:
1) — что вернет итератор, показывающий на последний элемент списка после того как к списку добавят элемент?
Если что-то отличное от null — исключение, или "очередной итератор", то говорить об иммутабельности такого итератора нельзя однозначно.
2) — я уверен в том что в языках с номинальной системой типов иммутабельными объектами считаются объекты тех типов, чьи экземпляры все иммутабельны. Т.е. не должно быть такого что new A(immutable: true) является иммутабельным, а new A() не является. Значит итератор не будет иммутабельным, если он имеет техническую возможность ссылаться на мутабельный контейнер.
S>Есть ещё один щекотливый момент: что считать идентичностью в этом случае. S>Два объекта в одинаковом состоянии неразличимы — нет способа "изменить" только один из них. Считать ли два состояния одного и того же объекта идентичными или нет?
Состояния — да. Будут ли идентичны сами объекты — вопрос интереснее.
Если ссылаться на руководство для implementers Object.Equals, то нарушается пункт
Successive calls to x.Equals(y) return the same value as long as the objects referenced by x and y are not modified.
Изменение по крайней мере одного объекта можно считать side effect-ом, потому при сравнении его с третьим объектом, который не изменил свое состояние вместе с первыми двумя, нарушится условие.
Можно усугубить: пусть нет способа изменить лишь один объект из всех (а не только из двух). Типичный паттерн Monostate. Считать ли все возможные состояния идентичными? Допускаю.
А причем тут вообще идентичность?
Re[24]: Почему объектно-ориентированное программирование про
Здравствуйте, samius, Вы писали: S>1) — что вернет итератор, показывающий на последний элемент списка после того как к списку добавят элемент? S>Если что-то отличное от null — исключение, или "очередной итератор", то говорить об иммутабельности такого итератора нельзя однозначно.
S>2) — я уверен в том что в языках с номинальной системой типов иммутабельными объектами считаются объекты тех типов, чьи экземпляры все иммутабельны. Т.е. не должно быть такого что new A(immutable: true) является иммутабельным, а new A() не является. Значит итератор не будет иммутабельным, если он имеет техническую возможность ссылаться на мутабельный контейнер.
Конечно же иммутабельность итератора подразумевает и иммутабельность итерируемого. В связи с этим п.1 не проблема.
S>Состояния — да. Будут ли идентичны сами объекты — вопрос интереснее.
Вот тут как раз непонятно, как отделить "состояния" от "самих объектов".
То есть вот у нас есть
S>Successive calls to x.Equals(y) return the same value as long as the objects referenced by x and y are not modified. S>
Непонятно, что имеется в виду. Все объекты — иммутабельны; поэтому никаких нарушений нет.
S>А причем тут вообще идентичность?
Ну так это же основа ООП. Если у нас нет идентичности (т.е. identity, которая, имхо, на самом деле идентифицируемость) то это вообще не ООП а непонятно что.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[25]: Почему объектно-ориентированное программирование про
Здравствуйте, Sinclair, Вы писали:
S>Здравствуйте, samius, Вы писали:
S>>Состояния — да. Будут ли идентичны сами объекты — вопрос интереснее. S>Вот тут как раз непонятно, как отделить "состояния" от "самих объектов".
Еще раз перечитал вопрос — признаюсь, я его походу не понял. И сейчас нет ясности.
S>То есть вот у нас есть S>
S>Кто из них считается эквивалентным?
Эквивалентным по какому признаку?
Ссылочно — наверняка нет (не исключено обратное)
Эквивалентно по набору реакций на сообщения — можно определить такую эквивалентность, но боюсь, ее придется определять рекурсивно через итераторы, возвращаемые Next()-ом в том числе.
Эквивалентно по контейнеру и позиции в нем — наверное iterator1 и iterator2 будут эквивалентны.
Я не очень понимаю, к чему вопрос.
S>>Если ссылаться на руководство для implementers Object.Equals, то нарушается пункт S>>
S>>Successive calls to x.Equals(y) return the same value as long as the objects referenced by x and y are not modified. S>>S>Непонятно, что имеется в виду. Все объекты — иммутабельны; поэтому никаких нарушений нет.
"нет способа изменить только один из них" — предполагает способ изменить сразу оба. Разве нет? Я исходил из этого.
S>>А причем тут вообще идентичность? S>Ну так это же основа ООП.
Сомневаюсь
Один из основных инструментов ООП — возможно. Но не основа.
S>Если у нас нет идентичности (т.е. identity, которая, имхо, на самом деле идентифицируемость) то это вообще не ООП а непонятно что.
Откуда это следует?
Re[27]: Почему объектно-ориентированное программирование про
Здравствуйте, Sinclair, Вы писали:
S>Здравствуйте, samius, Вы писали: S>>Эквивалентным по какому признаку? S>>Я не очень понимаю, к чему вопрос. S>Вы понимаете, что значит identity в ООП? Это гарантированный способ идентифицировать конкретный объект.
Я понимаю что значит идентичность, но не понимаю, к чему речь о ней.
S>Кроме того, очень важным моментом является то, что идентичность всегда сохраняется. То есть если мы получили ссылку r1 на объект о1, а через произвольное "время" мы получили ссылку r2 на тот же объект, то r1 == r2. Независимо от того, изменилось ли состояние o1 или нет.
Речь о ссылочной идентичности? Верно?
S>Если у нас нет такого свойства, то это однозначно не ООП.
Отлично. Вернемся к этому
с итераторами, возвращающими новый экземпляр итератора на MoveNext в точности то же самое, пока итераторы возвращаются не по значению. А смысла использовать структурную эквивалентность для итераторов я не вижу.
вернемся к
Два объекта в одинаковом состоянии неразличимы — нет способа "изменить" только один из них. Считать ли два состояния одного и того же объекта идентичными или нет?
Я до сих пор не понимаю ни суть вопроса, ни к чему он задан. И о какой идентичности все же идет речь? О ссылочной или структурной?
S>>Сомневаюсь S>>Один из основных инструментов ООП — возможно. Но не основа. S>>>Если у нас нет идентичности (т.е. identity, которая, имхо, на самом деле идентифицируемость) то это вообще не ООП а непонятно что. S>>Откуда это следует? S>Из определения. В ООП программа представляется набором объектов, обладающих S>- идентичностью, т.е. возможностью послать сообщение конкретному объекту S>- поведением, т.е. возможностью реагировать на сообщения некоторым образом S>- состоянием, т.е. возможностью варьировать своё поведение в зависимости от истории принятых сообщений.
Понятно. Ссылочная идентичность никуда не делась. Потому не понимаю, к чему было следующее:
Ну так это же основа ООП. Если у нас нет идентичности (т.е. identity, которая, имхо, на самом деле идентифицируемость) то это вообще не ООП а непонятно что.
Re[28]: Почему объектно-ориентированное программирование про
Здравствуйте, samius, Вы писали:
S>Речь о ссылочной идентичности? Верно?
Речь об идентичности. Которая в случае традиционной реализации соответствует ссылочной эквивалентности.
S>
S>Какие из них идентичны? Если никто из них, то это однозначно не ООП?
1. Не очень понял, что такое "штатные итераторы дотнета" в применении к данному примеру. Штатные итераторы не умеют так, как написано в строчке 2.
2. Если iterator1 не эквивалентен iterator2, то это нифига не ООП — мы не можем отличить разные состояния одного и того же объекта от разных объектов.
3. Если iterator1 эквивалентен iterator3, то это нифига не ООП — различные объекты невозможно отличить друг от друга.
S>Однако, если речь о ссылочной (shallow) идентичности, то она присутствует: S>
Данный пример никак не раскрывает вопроса наличия либо отсутствия ООП. Он будет работать с любыми ATD.
S>с итераторами, возвращающими новый экземпляр итератора на MoveNext в точности то же самое, пока итераторы возвращаются не по значению.
Не понял вот этой фразы. Можно мне её как-то развернуть? Будет ли способ установить идентичность iterator2 и iterator1?
S>Я до сих пор не понимаю ни суть вопроса, ни к чему он задан. И о какой идентичности все же идет речь? О ссылочной или структурной?
Вы, похоже, считаете термины "идентичность" и "эквивалентность" взаимозаменяемыми.
На самом деле они практически противоположны — прочитайте определение.
S>Понятно. Ссылочная идентичность никуда не делась.
Термина "ссылочная идентичность" не существует. S>
S>Ну так это же основа ООП. Если у нас нет идентичности (т.е. identity, которая, имхо, на самом деле идентифицируемость) то это вообще не ООП а непонятно что.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[29]: Почему объектно-ориентированное программирование про
Здравствуйте, Sinclair, Вы писали:
S>Здравствуйте, samius, Вы писали:
S>>Речь о ссылочной идентичности? Верно? S>Речь об идентичности. Которая в случае традиционной реализации соответствует ссылочной эквивалентности.
Окей. Но я решительно не понимаю, куда пропадает ссылочная эквивалентность в обсуждаемых примерах.
S>>Какие из них идентичны? Если никто из них, то это однозначно не ООП? S>1. Не очень понял, что такое "штатные итераторы дотнета" в применении к данному примеру. Штатные итераторы не умеют так, как написано в строчке 2.
Да, не умеют. Можно не рассматривать 2-ую строчку применительно к штатным итераторам. Ссылочная эквивалентность iterator1 и iterator3 сохраняется и с нештатными итераторами. Т.е. может эквивалентны ссылочно, а может и нет. Обычно нет.
S>2. Если iterator1 не эквивалентен iterator2, то это нифига не ООП — мы не можем отличить разные состояния одного и того же объекта от разных объектов.
Вообще говоря не понимаю, почему iteratro1 должен быть эквивалентен итератору2. А так же не понимаю, о каких различных состояниях одного и того же объекта речь в контексте иммутабельных объектов... Во всяком случае внешнего проявления изменения состояний быть не должно, а значит и на идентичность они не могут повлиять по определению иммутабельного объекта.
S>3. Если iterator1 эквивалентен iterator3, то это нифига не ООП — различные объекты невозможно отличить друг от друга.
Откуда следует что они различные?
И какие предполагаются отличия иммутабельных итераторов от штатных в этом аспекте? Если реализация возвращает каждый раз отличные объекты, почему они вдруг станут эквивалентными (ссылочно я полагаю)?
S>Данный пример никак не раскрывает вопроса наличия либо отсутствия ООП. Он будет работать с любыми ATD.
ок, опустим его
S>>с итераторами, возвращающими новый экземпляр итератора на MoveNext в точности то же самое, пока итераторы возвращаются не по значению. S>Не понял вот этой фразы. Можно мне её как-то развернуть? Будет ли способ установить идентичность iterator2 и iterator1?
Вот это надо узнать у автора идеи, или у того, кто ее здесь представил. Честно говоря, кроме $iterator=$iterator.MoveNext я о ней ничего не знаю. Могу предположить что в конце последовательности MoveNext будет возвращать this.
Если речь о традиционной реализации, то iterator1 и iterator2 могут быть ссылочно эквивалентны. А могут и не быть. Что это дает в вопросе наличия либо отсутствия ООП?
И что подразумевается под установкой идентичности iterator2 и iterator1? Убедиться что это разные объекты? Или что они одинаковые?
А сказать я хотел лишь то, что не вижу каких-то принципиальных отличий штатных итераторов от итераторов, возвращающих итератор на MoveNext в плане идентичности, кроме того факта, что последние возвращают новый итератор (возможно и нет в случае конца последовательности, т.к. я не знаю, что именно служит признаком конца последовательности, может и null).
S>>Я до сих пор не понимаю ни суть вопроса, ни к чему он задан. И о какой идентичности все же идет речь? О ссылочной или структурной? S>Вы, похоже, считаете термины "идентичность" и "эквивалентность" взаимозаменяемыми. S>На самом деле они практически противоположны — прочитайте определение.
Прочитал. Теперь я не понимаю следующее: Если в традиционной реализации идентичность соответствует ссылочной эквивалентности, то куда пропадает ссылочная эквивалентность при изменении модели итератора? Тот же вопрос вначале поста.
И главное я не понимаю того, как изменение модели итератора влияет на наличие ООП, притом что реализация традиционная, ссылочная эквивалентность а значит и идентичность присутствуют. Может я еще не понимаю о традиционной реализации чего именно идет речь?
Re[30]: Почему объектно-ориентированное программирование про
Здравствуйте, samius, Вы писали:
S>Да, не умеют. Можно не рассматривать 2-ую строчку применительно к штатным итераторам. Ссылочная эквивалентность iterator1 и iterator3 сохраняется и с нештатными итераторами. Т.е. может эквивалентны ссылочно, а может и нет. Обычно нет.
S>>2. Если iterator1 не эквивалентен iterator2, то это нифига не ООП — мы не можем отличить разные состояния одного и того же объекта от разных объектов. S>Вообще говоря не понимаю, почему iteratro1 должен быть эквивалентен итератору2.
Потому что в "обычном" ООП iterator2 — это тот же самый итератор1 после обработки сообщения moveNext. Переход к immutable, получается, теряет это свойство. Мы не можем взять, к примеру, внешний словарь, сохранить в нём некое значение для нашего итератора, и через время T получить это значение, скормив ему iterator2. S>А так же не понимаю, о каких различных состояниях одного и того же объекта речь в контексте иммутабельных объектов... Во всяком случае внешнего проявления изменения состояний быть не должно, а значит и на идентичность они не могут повлиять по определению иммутабельного объекта.
Ну как это не понимаете. Если мы хотим эмулировать ООП, то вместо монолитного объекта, который меняет своё состояние "на месте", мы имеем цепочку состояний. Что мы будем иметь вместо identity?
S>Откуда следует что они различные?
Ну, они могут быть и одинаковыми. Вопрос, собственно, в том — могут ли они быть различными?
S>И какие предполагаются отличия иммутабельных итераторов от штатных в этом аспекте? Если реализация возвращает каждый раз отличные объекты, почему они вдруг станут эквивалентными (ссылочно я полагаю)?
Я говорю не про реализацию. Предположим, она корректно реализует все требования. Какие именно требования вы предъявите, чтобы модель оставалась ООПшной?
S>>Не понял вот этой фразы. Можно мне её как-то развернуть? Будет ли способ установить идентичность iterator2 и iterator1? S>Вот это надо узнать у автора идеи, или у того, кто ее здесь представил. Честно говоря, кроме $iterator=$iterator.MoveNext я о ней ничего не знаю. Могу предположить что в конце последовательности MoveNext будет возвращать this.
Если this — иммутабелен, то смысла его возвращать нету. MoveNext никуда не сдвинется.
S>Если речь о традиционной реализации, то iterator1 и iterator2 могут быть ссылочно эквивалентны. А могут и не быть. Что это дает в вопросе наличия либо отсутствия ООП?
Это даёт наличие либо отсутствие ООП.
S>И что подразумевается под установкой идентичности iterator2 и iterator1? Убедиться что это разные объекты? Или что они одинаковые?
Убедиться, что они одинаковые, отличающиеся от всех других итераторов.
S>Прочитал. Теперь я не понимаю следующее: Если в традиционной реализации идентичность соответствует ссылочной эквивалентности, то куда пропадает ссылочная эквивалентность при изменении модели итератора? Тот же вопрос вначале поста.
Как куда? Раньше мы могли сохранять ссылку на итератор, меняя его состояние. Теперь мы вынуждены всё время её обновлять, следя за "состоянием". Вот вам и пропадание ссылочной эквивалентности. Я же привёл пример с iterator1/iterator2. В традиционной реализации мы можем написать вот так:
var iterator2 = iterator1;
iterator2.MoveNext();
Console.WriteLine(iterator2 == iterator1); // true
S>И главное я не понимаю того, как изменение модели итератора влияет на наличие ООП, притом что реализация традиционная, ссылочная эквивалентность а значит и идентичность присутствуют. Может я еще не понимаю о традиционной реализации чего именно идет речь?
Традиционная реализация — мутабельная.
Попытка реализовать итератор иммутабельным, судя по всему, не соответствует математике ООП.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[31]: Почему объектно-ориентированное программирование про
Здравствуйте, Sinclair, Вы писали:
S>>А так же не понимаю, о каких различных состояниях одного и того же объекта речь в контексте иммутабельных объектов... Во всяком случае внешнего проявления изменения состояний быть не должно, а значит и на идентичность они не могут повлиять по определению иммутабельного объекта. S>Ну как это не понимаете. Если мы хотим эмулировать ООП, то вместо монолитного объекта, который меняет своё состояние "на месте", мы имеем цепочку состояний. Что мы будем иметь вместо identity?
Эээ... Собственно, конкретное состояние в какой-то момент времени. Какие проблемы-то?
Sapienti sat!
Re[33]: Почему объектно-ориентированное программирование про
Здравствуйте, Sinclair, Вы писали:
C>>Эээ... Собственно, конкретное состояние в какой-то момент времени. Какие проблемы-то? S>Проблемы лично у меня с тем, что identity получается утеряна. В классическом ООП можно абстрагироваться от состояния объекта, и отличать его от всех других.
Почему?? Скажем, два разных объекта в функциональщине будут двумя разными объектами.
S>К примеру, можно иметь некий dictionary, в котором лежат строки, индексированные thread. S>В любой момент можно пойти в этот dictionary, имея ссылку на текущее состояние потока, и получить нужную строку.
А где здесь identity?
S>В immutable реализации это невозможно: строку складывали со "старым" потоком, ищем с "новым". S>Придётся вносить какой-нибудь threadID, который будет сохраняться при смене состояния потока. S>А это и есть "ручная идентичность" в противовес "встроенной".
Нет. Это пример однозначно не на идентичность, а на ссылочную прозрачность.
В случае с функциональностью ты ОБЯЗАН передать состояние всё состояние, которое используется. В императивном подходе ты можешь использовать глобальные контексты.
Sapienti sat!
Re[31]: Почему объектно-ориентированное программирование про
Здравствуйте, Sinclair, Вы писали:
S>Здравствуйте, samius, Вы писали:
S>>Вообще говоря не понимаю, почему iteratro1 должен быть эквивалентен итератору2. S>Потому что в "обычном" ООП iterator2 — это тот же самый итератор1 после обработки сообщения moveNext. Переход к immutable, получается, теряет это свойство.
Естественно. S>Мы не можем взять, к примеру, внешний словарь, сохранить в нём некое значение для нашего итератора, и через время T получить это значение, скормив ему iterator2.
Это верно. Но причем здесь ООП? Iterator2 это не тот же итератор Iterator1. Изменился способ итерирования по коллекции. Один итератор — одна позиция последовательности. Все равно что складывать в словарь позицию в массиве int *iter1, а потом после iter1++ пытаться что-то найти в словаре.
S>>А так же не понимаю, о каких различных состояниях одного и того же объекта речь в контексте иммутабельных объектов... Во всяком случае внешнего проявления изменения состояний быть не должно, а значит и на идентичность они не могут повлиять по определению иммутабельного объекта. S>Ну как это не понимаете. Если мы хотим эмулировать ООП, то вместо монолитного объекта, который меняет своё состояние "на месте", мы имеем цепочку состояний. Что мы будем иметь вместо identity?
Ничего не надо делать вместо. Итератор это не один и тот же объект и все тут.
Но что-то мне кажется что итератор это сложная тема для нахождения взаимопонимания в вопросе наличия ООП. Предлагаю переключиться на аналогичную ситуацию с String/StringBuilder и посмотреть на операции
sb.Append("foo");
s += "foo";
Для меня здесь нет различий между в аспекте наличия ООП. Отличны только способы взаимодействия с объектами. Один получая сообщение меняет свое состояние, второй — возвращает новое значение.
S>>И какие предполагаются отличия иммутабельных итераторов от штатных в этом аспекте? Если реализация возвращает каждый раз отличные объекты, почему они вдруг станут эквивалентными (ссылочно я полагаю)? S>Я говорю не про реализацию. Предположим, она корректно реализует все требования. Какие именно требования вы предъявите, чтобы модель оставалась ООПшной?
Она для меня ООП-шная насквозь, потому как я не считаю цепочку итераторов одним и тем же объектом, либо эмуляцией одного и того же объекта.
S>>Вот это надо узнать у автора идеи, или у того, кто ее здесь представил. Честно говоря, кроме $iterator=$iterator.MoveNext я о ней ничего не знаю. Могу предположить что в конце последовательности MoveNext будет возвращать this. S>Если this — иммутабелен, то смысла его возвращать нету. MoveNext никуда не сдвинется.
Ну почему же? Для конца коллекции вполне можно возвращать this что бы клиент сравнивая ссылки с предыдущим итератором убедился что сдвига не произошло. Я не говорю что так должно быть, это просто один из предпологаемых сценариев.
S>>Если речь о традиционной реализации, то iterator1 и iterator2 могут быть ссылочно эквивалентны. А могут и не быть. Что это дает в вопросе наличия либо отсутствия ООП? S>Это даёт наличие либо отсутствие ООП.
Честно говоря, походу меня перемкнуло когда я отвечал на предыдущий пост. В случае традиционной реализации iterator2 не может быть получен как результат MoveNext. Может я хотел что-то другое сказать/спросить, уже не помню.
S>>И что подразумевается под установкой идентичности iterator2 и iterator1? Убедиться что это разные объекты? Или что они одинаковые? S>Убедиться, что они одинаковые, отличающиеся от всех других итераторов.
2 и 1 одинаковые? Может и можно убедиться что они одинаковые в случае если на конце коллекции MoveNext возвращает this. Но в общем случае они не будут одинаковыми и будут отличаться от всех других (тем что ссылки на них не будут равны).
S>>Если в традиционной реализации идентичность соответствует ссылочной эквивалентности, то куда пропадает ссылочная эквивалентность при изменении модели итератора? Тот же вопрос вначале поста. S>Как куда? Раньше мы могли сохранять ссылку на итератор, меняя его состояние. Теперь мы вынуждены всё время её обновлять, следя за "состоянием". Вот вам и пропадание ссылочной эквивалентности. Я же привёл пример с iterator1/iterator2. В традиционной реализации мы можем написать вот так: S>
Да, можем. А в иммутабельной не можем на том основании что итератор вернется другой. Но ссылочная эквивалентность осталась:
var iterator2 = iterator1;
var iterator3 = iterator2.MoveNext();
Console.WriteLine(iterator2 == iterator1); // true
S>>И главное я не понимаю того, как изменение модели итератора влияет на наличие ООП, притом что реализация традиционная, ссылочная эквивалентность а значит и идентичность присутствуют. Может я еще не понимаю о традиционной реализации чего именно идет речь? S>Традиционная реализация — мутабельная. А, речь об реализации итератора. S>Попытка реализовать итератор иммутабельным, судя по всему, не соответствует математике ООП.
Я считаю что математика ООП не должна ожидать ссылочной эквивалентности от _разных_ объектов.
Re[34]: Почему объектно-ориентированное программирование про
Здравствуйте, Cyberax, Вы писали:
C>Здравствуйте, Sinclair, Вы писали:
C>>>Эээ... Собственно, конкретное состояние в какой-то момент времени. Какие проблемы-то? S>>Проблемы лично у меня с тем, что identity получается утеряна. В классическом ООП можно абстрагироваться от состояния объекта, и отличать его от всех других. C>Почему?? Скажем, два разных объекта в функциональщине будут двумя разными объектами.
Тут возникает философский вопрос — что значит "разные" объекты?
И сложность не только в том, чтобы различать разные объекты, но и чтобы уметь понять, что две ссылки показывают на один и тот же объект.
S>>К примеру, можно иметь некий dictionary, в котором лежат строки, индексированные thread. S>>В любой момент можно пойти в этот dictionary, имея ссылку на текущее состояние потока, и получить нужную строку. C>А где здесь identity?
Везде. Identity в данном случае — это способ отличить "этот" объект от всех других объектов.
Возможность обратиться в dictionary напрямую связана с сохранением identity. Операции над объектами в ООП сохраняют идентичность. В ФП — не сохраняют.
C>Нет. Это пример однозначно не на идентичность, а на ссылочную прозрачность. Referential transparency приводится в вики как антипод identity. В связи с этим, имхо, трудно придумать пример на одно так, чтобы он не был и примером на другое
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[32]: Почему объектно-ориентированное программирование про
Здравствуйте, samius, Вы писали:
S>Это верно. Но причем здесь ООП? Iterator2 это не тот же итератор Iterator1. Изменился способ итерирования по коллекции. Один итератор — одна позиция последовательности. Все равно что складывать в словарь позицию в массиве int *iter1, а потом после iter1++ пытаться что-то найти в словаре.
Очень хорошо. Я надеюсь, вы понимаете, что (int *) — это не ООП?
Итератор, определённый таким образом, ведёт себя не как объект, а как value-type.
S>Но что-то мне кажется что итератор это сложная тема для нахождения взаимопонимания в вопросе наличия ООП. Предлагаю переключиться на аналогичную ситуацию с String/StringBuilder и посмотреть на операции S>
S>sb.Append("foo");
S>s += "foo";
S>
S>Для меня здесь нет различий между в аспекте наличия ООП. Отличны только способы взаимодействия с объектами. Один получая сообщение меняет свое состояние, второй — возвращает новое значение.
Как бы вам так объяснить. Вы имеете полное право игнорировать общепринятые определения ООП, подразумевая под ним что-то своё. Но, во-первых, хотелось бы тогда увидеть ваше определение — каким критериям должна удовлетворять архитектура, чтобы считаться объектной или объектно-ориентированной? А во-вторых, не очень понятно желание отказаться от общепринятых терминов.
S>>Если this — иммутабелен, то смысла его возвращать нету. MoveNext никуда не сдвинется. S>Ну почему же? Для конца коллекции вполне можно возвращать this что бы клиент сравнивая ссылки с предыдущим итератором убедился что сдвига не произошло. Я не говорю что так должно быть, это просто один из предпологаемых сценариев.
Это, конечно, интересно. А в другие места коллекций итераторы у вас указывать могут? Зачем тогда фокусироваться на одном частном случае?
S>>Убедиться, что они одинаковые, отличающиеся от всех других итераторов. S>2 и 1 одинаковые? Может и можно убедиться что они одинаковые в случае если на конце коллекции MoveNext возвращает this. Но в общем случае они не будут одинаковыми и будут отличаться от всех других (тем что ссылки на них не будут равны).
В случае ООП итератор это объект. Объект в ООП всегда обладает идентичностью. Это означает, что есть способ установить эквивалентность iterator1 до MoveNext и его же после MoveNext.
S>Да, можем. А в иммутабельной не можем на том основании что итератор вернется другой. Но ссылочная эквивалентность осталась: S>
Эта эквивалентность не является ссылочной. Если мы поменяем семантику операций присваивания и сравнения на почленное копирование/сравнение, то поведение этого фрагмента программы не изменится.
S>Я считаю что математика ООП не должна ожидать ссылочной эквивалентности от _разных_ объектов.
Математика ООП ожидает наличия identity у объекта. Ссылочная эквивалентность — это способ реализации identity в традиционной реализации ООП — там, где объекты живут в "памяти", и можно идентифицировать объект по его "положению" в этой памяти.
В менее традиционных реализациях ООП, где, скажем, нет способа манипулировать "адресом" объекта, применяют OID — Object Identifier.
По итогам дискуссии получается, что у immutable "объектов" identity нет, то есть это не объекты с точки зрения ООП.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[33]: Почему объектно-ориентированное программирование про
Здравствуйте, Sinclair, Вы писали:
S>Здравствуйте, samius, Вы писали:
S>Очень хорошо. Я надеюсь, вы понимаете, что (int *) — это не ООП?
(int *) — это не ООП S>Итератор, определённый таким образом, ведёт себя не как объект, а как value-type.
однако я не понимаю почему нельзя считать ООП $iterator = $iterator.MoveNext(). Куда делась идентичность объекта после вызова MoveNext()?
S>>
S>>sb.Append("foo");
S>>s += "foo";
S>>
S>>Для меня здесь нет различий между в аспекте наличия ООП. Отличны только способы взаимодействия с объектами. Один получая сообщение меняет свое состояние, второй — возвращает новое значение. S>Как бы вам так объяснить. Вы имеете полное право игнорировать общепринятые определения ООП, подразумевая под ним что-то своё. Но, во-первых, хотелось бы тогда увидеть ваше определение — каким критериям должна удовлетворять архитектура, чтобы считаться объектной или объектно-ориентированной? А во-вторых, не очень понятно желание отказаться от общепринятых терминов.
Что бы убедить меня в том что я от чего-то хочу отказаться, нужно показать как нарушается идентичность иммутабельного объекта после операций над ним. Например на строке. Что она такого теряет после += "foo"?
Или может строка это не объект? Тогда что отличает объект от необъекта? Ниужели наличие изменяемого состояния?
S>Это, конечно, интересно. А в другие места коллекций итераторы у вас указывать могут? Зачем тогда фокусироваться на одном частном случае?
Я не хотел на этом фокусироваться, просто ответил о том что iterator2 может быть идентичен iterator1.
S>В случае ООП итератор это объект. Объект в ООП всегда обладает идентичностью. Это означает, что есть способ установить эквивалентность iterator1 до MoveNext и его же после MoveNext.
То же самое и с иммутабельными итераторами. После MoveNext ничего с итератором не случается. Он остается самим собой и эквивалентен себе до MoveNext ссылочно и даже структурно (в контрасте с традиционным итератором).
S>>
S>Эта эквивалентность не является ссылочной. Если мы поменяем семантику операций присваивания и сравнения на почленное копирование/сравнение, то поведение этого фрагмента программы не изменится.
И я не вижу в этом проблему. Если объект от необъекта отличает необходимость изменять члены после каждой операции, то это плохой критерий.
S>Математика ООП ожидает наличия identity у объекта. Ссылочная эквивалентность — это способ реализации identity в традиционной реализации ООП — там, где объекты живут в "памяти", и можно идентифицировать объект по его "положению" в этой памяти.
Предлагаю оставаться в рамках традиционной реализации ООП, там где объект можно идентифицировать по его "положению".
S>По итогам дискуссии получается, что у immutable "объектов" identity нет, то есть это не объекты с точки зрения ООП.
Можно все-таки в коде увидеть признак отсутствия identity у immutable "объектов"? Примеры выше как-то это не показывают. В частности сравнение традиционных и иммутабельных итераторов (с вариациями строки с MoveNext) ведут себя одинаково если не копировать и не сравнивать их почленно.
Re[35]: Почему объектно-ориентированное программирование про
Здравствуйте, Sinclair, Вы писали:
S>>>Проблемы лично у меня с тем, что identity получается утеряна. В классическом ООП можно абстрагироваться от состояния объекта, и отличать его от всех других. C>>Почему?? Скажем, два разных объекта в функциональщине будут двумя разными объектами. S>Тут возникает философский вопрос — что значит "разные" объекты? S>И сложность не только в том, чтобы различать разные объекты, но и чтобы уметь понять, что две ссылки показывают на один и тот же объект.
Собственно, это вопрос совсем к императивности и функциональности не относятся ровно никак.
S>>>В любой момент можно пойти в этот dictionary, имея ссылку на текущее состояние потока, и получить нужную строку. C>>А где здесь identity? S>Везде. Identity в данном случае — это способ отличить "этот" объект от всех других объектов.
Так и что? В функциональщине просто мутаций нет, всё остальное такое же. Точно так же, нужно уметь отличать один объект от другого.
S>Возможность обратиться в dictionary напрямую связана с сохранением identity. Операции над объектами в ООП сохраняют идентичность. В ФП — не сохраняют.
Сохраняют. Если мне передадут DictionaryA и DictionaryB — они могут быть разными. Если бы у них не было идентичности, то их можно было бы заменять один на другой, что очевидно не так.
Sapienti sat!
Re[22]: Почему объектно-ориентированное программирование про
Здравствуйте, samius, Вы писали:
S>>Это потому, что имеющаяся реализация yield return реализует стандартный IEnumerable<T>. Её можно было бы "починить", если бы результат GetEnumerator реализовывал бы ICloneable<IEnumerator<T>>. S>>А окончательно её можно было бы починить, если бы в IEnumerator<T> MoveNext возвращал не void, а IEnumerator<T>. S>>Тогда бы за хранение состояния отвечал бы клиентский код, вместо $iterator.MoveNext было бы $iterator=$iterator.MoveNext. S>Задача перебора будет решена, но это уже не паттерн Iterator
Итератор может быть "внешнием" и "внутренним", это по ГоФ. Если внутренним, то соответственно сколько угодно можешь делать его иммутабельным. Если внешним, то структура _нисколько_ не меняется если методы будут не void а будут возвращать новый итератор.
Re[33]: Почему объектно-ориентированное программирование про
Здравствуйте, Sinclair, Вы писали:
S>В менее традиционных реализациях ООП, где, скажем, нет способа манипулировать "адресом" объекта, применяют OID — Object Identifier.
S>По итогам дискуссии получается, что у immutable "объектов" identity нет, то есть это не объекты с точки зрения ООП.
Реально, поскольку объекты иммутабельные, нет разницы кому посылать сообщение, следовательно можно считать любые строки "abc" одним и тем же объектом.
Re[31]: Почему объектно-ориентированное программирование про
Здравствуйте, Sinclair, Вы писали:
S>>И главное я не понимаю того, как изменение модели итератора влияет на наличие ООП, притом что реализация традиционная, ссылочная эквивалентность а значит и идентичность присутствуют. Может я еще не понимаю о традиционной реализации чего именно идет речь? S>Традиционная реализация — мутабельная. S>Попытка реализовать итератор иммутабельным, судя по всему, не соответствует математике ООП.
ООП не требует что бы некоторая модель решения состояла из одного конкретного объекта.
Re[15]: Почему объектно-ориентированное программирование про
Здравствуйте, Sinclair, Вы писали:
S>Вы вообще реальные программы когда-нибудь писали? К чему эти абстрактные рассуждения про атомы и арматуру? Программа является моделью решаемой задачи не в большей степени, чем токарный станок является моделью вытачиваемого изделия.
Токарный станок работает по шаблону, т.е. по некоторой модели будущего изделия.
Re[34]: Почему объектно-ориентированное программирование про
Здравствуйте, samius, Вы писали:
S>Здравствуйте, Sinclair, Вы писали:
S>>Здравствуйте, samius, Вы писали:
S>>Очень хорошо. Я надеюсь, вы понимаете, что (int *) — это не ООП? S>(int *) — это не ООП S>>Итератор, определённый таким образом, ведёт себя не как объект, а как value-type. S>однако я не понимаю почему нельзя считать ООП $iterator = $iterator.MoveNext(). Куда делась идентичность объекта после вызова MoveNext()?
Как куда? Исчезла. $iterator стал совсем другим.
S>Что бы убедить меня в том что я от чего-то хочу отказаться, нужно показать как нарушается идентичность иммутабельного объекта после операций над ним. Например на строке. Что она такого теряет после += "foo"?
Она теряет идентичность.
S>Или может строка это не объект? Тогда что отличает объект от необъекта? Ниужели наличие изменяемого состояния?
Конечно же не объект. Строка имеет семантику value-типа.
S>>В случае ООП итератор это объект. Объект в ООП всегда обладает идентичностью. Это означает, что есть способ установить эквивалентность iterator1 до MoveNext и его же после MoveNext. S>То же самое и с иммутабельными итераторами. После MoveNext ничего с итератором не случается. Он остается самим собой и эквивалентен себе до MoveNext ссылочно и даже структурно (в контрасте с традиционным итератором).
S>И я не вижу в этом проблему. Если объект от необъекта отличает необходимость изменять члены после каждой операции, то это плохой критерий.
Зачем выворачивать наизнанку мои высказывания. Я говорю про возможность выполнять операции, сохраняя identity, даже если они изменяют состояние. А вовсе не про необходимость изменять состояние после каждой операции.
S>Предлагаю оставаться в рамках традиционной реализации ООП, там где объект можно идентифицировать по его "положению".
Ок.
S>Можно все-таки в коде увидеть признак отсутствия identity у immutable "объектов"? Примеры выше как-то это не показывают. В частности сравнение традиционных и иммутабельных итераторов (с вариациями строки с MoveNext) ведут себя одинаково если не копировать и не сравнивать их почленно.
Я же привёл вам примеры. Никаких почленных сравнений не надо.
Вот вам пример со строками, который показывает разницу между объектами и value-типами:
var sb = new StringBuilder("Hello");
var s = "Hello";
var d = new Dictionary<object, string>;
d[sb] = "Ok";
d[s] = "Ok";
sb += "!";
s+= "!";
System.Console.WriteLine(d[sb]);
System.Console.WriteLine(d[s]); // имеем нарушение идентичности
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[16]: Почему объектно-ориентированное программирование про
V>Токарный станок работает по шаблону, т.е. по некоторой модели будущего изделия.
Я ждал этого комментария Конечно же, вы считаете шаблон основной частью станка. То есть хорошей технологией производства токарных станков будет та, которая упрощает создание шаблонов. Вопросы устройства самого станка, безусловно, вторичны.
Если вас не устраивает токарный станок — возьмите сверлильный. Модели отверстия он не содержит.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[32]: Почему объектно-ориентированное программирование про
Здравствуйте, Ikemefula, Вы писали:
I>ООП не требует что бы некоторая модель решения состояла из одного конкретного объекта.
Зато ООП однозначно требует, чтобы объекты обладали идентичностью, которая ведёт себя вполне определённым образом.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[33]: Почему объектно-ориентированное программирование про
Здравствуйте, Sinclair, Вы писали:
I>>ООП не требует что бы некоторая модель решения состояла из одного конкретного объекта. S>Зато ООП однозначно требует, чтобы объекты обладали идентичностью, которая ведёт себя вполне определённым образом.
Т.е. ты хочешь сказать, что семантика value-type не вписывается в OOP ? Почему ?
Re[35]: Почему объектно-ориентированное программирование про
Здравствуйте, Sinclair, Вы писали:
S>Здравствуйте, samius, Вы писали:
S>>однако я не понимаю почему нельзя считать ООП $iterator = $iterator.MoveNext(). Куда делась идентичность объекта после вызова MoveNext()? S>Как куда? Исчезла. $iterator стал совсем другим.
извиняюсь, если покажется передергиванием, но по такой логике все что x = x.Clone() — не является ООП?
S>>Что бы убедить меня в том что я от чего-то хочу отказаться, нужно показать как нарушается идентичность иммутабельного объекта после операций над ним. Например на строке. Что она такого теряет после += "foo"? S>Она теряет идентичность.
Идентичность по вашему это свойство объекта или переменной?
S>>Или может строка это не объект? Тогда что отличает объект от необъекта? Ниужели наличие изменяемого состояния? S>Конечно же не объект. Строка имеет семантику value-типа.
Это мешает ей быть объектом?
S>>И я не вижу в этом проблему. Если объект от необъекта отличает необходимость изменять члены после каждой операции, то это плохой критерий. S>Зачем выворачивать наизнанку мои высказывания.
Приношу извинения S>Я говорю про возможность выполнять операции, сохраняя identity, даже если они изменяют состояние. А вовсе не про необходимость изменять состояние после каждой операции.
Я пытаюсь понять, что же по вашему отличает иммутабельные объекты от мутабельных в плане idintity. И возможно перегибаю. Здесь опять — в чем проявляется сохранение identity, особенно в тех случаях когда они не изменяют состояние?
S>Я же привёл вам примеры. Никаких почленных сравнений не надо. S>Вот вам пример со строками, который показывает разницу между объектами и value-типами:
отлично. Добавлю пару штрихов.
S>var sb = new StringBuilder("Hello");
S>var s = "Hello";
var s1 = s;
S>var d = new Dictionary<object, string>;
S>d[sb] = "Ok";
S>d[s] = "Ok";
S>sb += "!";
sb = sb.Clone(); // у него нет такого метода, но мог бы быть.
S>s+= "!";
S>System.Console.WriteLine(d[sb]);
System.Console.WriteLine(d[sb]); // а в модифицированном мной примере тут проблема
S>System.Console.WriteLine(d[s]); // имеем нарушение идентичностиSystem.Console.WriteLine(d[s1]); // по-моему все впорядке с идентичностью объекта по ссылке s1
In object-oriented and functional programming, an immutable object is an object whose state cannot be modified after it is created. This is in contrast to a mutable object, which can be modified after it is created.
Там считают что иммутабельный объект это прежде всего объект, правда с некой спецификой, которая не мешает ему быть объектом. Я придерживаюсь этой точки зрения.
Re[34]: Почему объектно-ориентированное программирование про
I>Т.е. ты хочешь сказать, что семантика value-type не вписывается в OOP ? Почему ?
Потому, что value-type не ведут себя как объекты. У них нет идентичности: все объекты с равным "значением" эквивалентны. Объект — это чёрный ящик, о его внутреннем состоянии мы можем судить только по его поведению. Value-тип — это практически чистое состояние.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[36]: Почему объектно-ориентированное программирование про
Здравствуйте, samius, Вы писали:
S>>Как куда? Исчезла. $iterator стал совсем другим. S>извиняюсь, если покажется передергиванием, но по такой логике все что x = x.Clone() — не является ООП?
Нет. Только то, где мы хотим сохранить идентичность, но не можем.
Вы всё время зачем-то выворачиваете мои утверждения.
S>Идентичность по вашему это свойство объекта или переменной?
Объекта.
S>>Конечно же не объект. Строка имеет семантику value-типа. S>Это мешает ей быть объектом?
Имхо, да. Вы поймите — не всё, что можно запрограммировать на ОО-языке является реализацией корректной объектной модели. На C# можно, к примеру, сделать чисто статический класс. С точки зрения ООП его не может быть.
S>Я пытаюсь понять, что же по вашему отличает иммутабельные объекты от мутабельных в плане idintity. И возможно перегибаю. Здесь опять — в чем проявляется сохранение identity, особенно в тех случаях когда они не изменяют состояние?
Я привёл примеры. Что именно вам в них непонятно?
S>отлично. Добавлю пару штрихов. S>
S>>var sb = new StringBuilder("Hello");
S>>var s = "Hello";
S>var s1 = s;
S>>var d = new Dictionary<object, string>;
S>>d[sb] = "Ok";
S>>d[s] = "Ok";
S>>sb += "!";
S>sb = sb.Clone(); // у него нет такого метода, но мог бы быть.
S>>s+= "!";
S>>System.Console.WriteLine(d[sb]);
S>System.Console.WriteLine(d[sb]); // а в модифицированном мной примере тут проблема
S>>System.Console.WriteLine(d[s]); // имеем нарушение идентичности
S>System.Console.WriteLine(d[s1]); // по-моему все впорядке с идентичностью объекта по ссылке s1
Ну и что? Что именно вы хотите продемонстрировать? То, что клонированный объект имеет другую идентити? Ну так это как раз пример на демонстрацию того, что такое идентичность. Показываю ещё раз, в другом разрезе:
[c#]
var sb = new StringBuilder("Hello");
var s = "Hello";
var d = new Dictionary<object, string>;
d[sb] = "Ok";
d[s] = "Ok";
var s2 = "Hello"; // у строки нет .Clone, но если бы был, то результат был бы таким жеvar sb2 = new StringBuilder("Hello"); // у StringBuiler нет .Clone, но если бы был, то результат был бы таким же
System.Console.WriteLine(d[sb2]); // несмотря на совпадение содержимого, различить настоящие объекты всегда можно
System.Console.WriteLine(d[s2]); // а вот value-типы с равным значением неразличимы
S>Вот еще подкину ссылку на Immutable Object S>
S>In object-oriented and functional programming, an immutable object is an object whose state cannot be modified after it is created. This is in contrast to a mutable object, which can be modified after it is created.
S>Там считают что иммутабельный объект это прежде всего объект, правда с некой спецификой, которая не мешает ему быть объектом. Я придерживаюсь этой точки зрения.
Интересная точка зрения. В статье приведен скорее некоторый паттерн, чем строгая математика. Это тоже имеет право на жизнь; но скорее мы говорим о некотором "расширенном" ООП, в котором есть черты ещё чего-то.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[37]: Почему объектно-ориентированное программирование про
Здравствуйте, Sinclair, Вы писали:
S>Здравствуйте, samius, Вы писали:
S>>>Как куда? Исчезла. $iterator стал совсем другим. S>>извиняюсь, если покажется передергиванием, но по такой логике все что x = x.Clone() — не является ООП? S>Нет. Только то, где мы хотим сохранить идентичность, но не можем. S>Вы всё время зачем-то выворачиваете мои утверждения.
Я их усугубляю, пытаясь понять момент потери идентичности. Если это нервирует — могу прекратить.
S>>Идентичность по вашему это свойство объекта или переменной? S>Объекта.
Но разве присвоение ссылки что-то делает с объектом? Буч ссылки называет синонимами. И пишет о путанице, которая возникает при работе с синонимами.
S>>>Конечно же не объект. Строка имеет семантику value-типа. S>>Это мешает ей быть объектом? S>Имхо, да.
Буч, например, не отделяет объекты которые копируются по значению. Возможно из-за того что в C++ семантику копирования можно контроллировать.
S>Вы поймите — не всё, что можно запрограммировать на ОО-языке является реализацией корректной объектной модели. На C# можно, к примеру, сделать чисто статический класс. С точки зрения ООП его не может быть.
Я понимаю. Но в корне не согласен с тем что иммутабельный объект противоречит ООП своим существованием.
S>>Я пытаюсь понять, что же по вашему отличает иммутабельные объекты от мутабельных в плане idintity. И возможно перегибаю. Здесь опять — в чем проявляется сохранение identity, особенно в тех случаях когда они не изменяют состояние? S>Я привёл примеры. Что именно вам в них непонятно?
Мне непонятно в каком месте происходит "потеря" идентичности объекта. Все эти примеры манипулируют ссылками на объекты, хотя должны демонстрировать "потерю" идентичности объекта. По определению идентичность — это такое свойство объекта, которое отличает его от остальных. После присваиваний ссылок объект остается вместе с тем свойством, которое его от остальных отличает.
Вот что пишет Буч про идентичность:
Уникальная идентичность (но не обязательно имя) каждого объекта сохраняется на все время его существования, даже если его внутреннее состояние изменилось.
S>>отлично. Добавлю пару штрихов. S>>
S>>sb = sb.Clone(); // у него нет такого метода, но мог бы быть.
S>> S>Ну и что? Что именно вы хотите продемонстрировать? То, что клонированный объект имеет другую идентити? Ну так это как раз пример на демонстрацию того, что такое идентичность.
Нет, я пытался продемонстрировать что нормальный объект (мутабельный) точно так же "теряет" идентичность, как и иммутабельный (с ваших слов). На самом деле верно то что у другого объекта другая идентичность. А у старого — своя, и с ней ничего не случилось. Как и со строками. Единственное что отличает sb от строки в этом примере — то что у строки структурная эквивалентность (ничего общего с идентичностью не имеющая).
Так и иммутабельные объекты — они могут иметь структурную эквивалентность, а могут и нет. Способ по которому производится поиск в словаре завязан именно на эквивалентность объектов.
S>Показываю ещё раз, в другом разрезе: S>
S>var sb = new StringBuilder("Hello");
S>var s = "Hello";
S>var d = new Dictionary<object, string>;
S>d[sb] = "Ok";
S>d[s] = "Ok";
S>var s2 = "Hello"; // у строки нет .Clone, но если бы был, то результат был бы таким же
S>var sb2 = new StringBuilder("Hello"); // у StringBuiler нет .Clone, но если бы был, то результат был бы таким же
S>System.Console.WriteLine(d[sb2]); // несмотря на совпадение содержимого, различить настоящие объекты всегда можно
S>System.Console.WriteLine(d[s2]); // а вот value-типы с равным значением неразличимы
S>
И этот пример на эквивалентность. Его запросто заставить работать по-другому, если создать словарь с компарером, работающем на ReferenceEquals.
S>>Там считают что иммутабельный объект это прежде всего объект, правда с некой спецификой, которая не мешает ему быть объектом. Я придерживаюсь этой точки зрения. S>Интересная точка зрения. В статье приведен скорее некоторый паттерн, чем строгая математика. Это тоже имеет право на жизнь; но скорее мы говорим о некотором "расширенном" ООП, в котором есть черты ещё чего-то.
По-моему проще согласиться с тем что идентичность — неотъемлемая характеристика объекта, невзирая на возможность изменять его состояние (фактическое или наблюдаемое).
Вообще говоря — любой объект можно считать иммутабельным в некоторой фазе работы программы. иммутабельные от мутабельных отличаются лишь тем, что для них эта фаза длится всё время жизни. А это не исключено и для мутабельных объектов, т.е. мутабельный объект может все время существования сохранять свое наблюдаемое состояние. Было бы странно если бы такое отличие как длина фазы иммутабельности влияло бы на идентичность объекта и как следствие на "истинную объектность".
Re[39]: Почему объектно-ориентированное программирование про
Здравствуйте, Sinclair, Вы писали:
S>Здравствуйте, samius, Вы писали:
S>Ну пока что я не могу получить изоморфизм между поведением модели, построенной из "настоящих" объектов, и из иммутабельных объектов.
А я наоборот не могу обнаружить значительных отличий.
S>>По определению идентичность — это такое свойство объекта, которое отличает его от остальных. После присваиваний ссылок объект остается вместе с тем свойством, которое его от остальных отличает. S>Это понятно. Но у нас нет средства взаимодействовать с объектом без использования ссылок.
Хорошо, зафиксируем дискуссию вокруг ссылочных объектов и забудем об объектах-значениях S>Поэтому все особенности поведения идентичности выявляются через манипуляции со ссылками. S>Идентичность означает возможность однозначно и корректно ответить на вопрос "ссылаются ли эти две ссылки на один и тот же объект".
Верно. Однозначный способ ответить на этот вопрос в дотнете — ReferenceEquals. Все что делают методы Equals, компареры и прочее, все что используют словари — все это отвечает на вопрос об эквивалентности в том или ином смысле и имеет отношение к идентичности только в том случае, если речь идет о ссылочной эквивалентности.
S>>Нет, я пытался продемонстрировать что нормальный объект (мутабельный) точно так же "теряет" идентичность, как и иммутабельный (с ваших слов). На самом деле верно то что у другого объекта другая идентичность. S>У вас не получилось. Объект идентичность не потерял.
Естественно не потерял. S>>Так и иммутабельные объекты — они могут иметь структурную эквивалентность, а могут и нет. Способ по которому производится поиск в словаре завязан именно на эквивалентность объектов. S>Конечно. Просто для value-типов ссылочная эквивалентность не имеет смысла. А для настоящих объектов — имеет, поскольку для них ссылка и есть их identity.
О value-типах тут в смысле о типах, чьи экземпляры передаются по значению? Или о таких как System.String? S>>И этот пример на эквивалентность. Его запросто заставить работать по-другому, если создать словарь с компарером, работающем на ReferenceEquals. S>Можно. Но это не имеет физического смысла.
Это имеет лишь тот смысл, что бы показать что пример работает с эквивалентностью а не идентичностью.
S>>По-моему проще согласиться с тем что идентичность — неотъемлемая характеристика объекта, невзирая на возможность изменять его состояние (фактическое или наблюдаемое). S>С этим никто не спорит. Вопрос только в том, имеет ли идентичность смысл для иммутабельных объектов.
А почему нет? Иммутабельные объекты — это такие объекты, которые не проявляют изменение состояний внешне. Но это не значит что у них нет изменяемого состояния внутри. Возьмем например System.Lazy<T>. Если забыть о его свойстве IsValueCreated, то этот объект можно считать иммутабельным. Такие объекты отличимы один от другого и смысл их отличать есть. Разница от использования того или другого объекта с внешне одинаковым состоянием налицо, ибо может проявляться во времени вычисления значения, либо даже в сайд-эффектах. Но тему о сайдэффектах при работе иммутабельных объектах я не хотел бы развивать, т.к. к чистым концепциям она не имеет отношения.
S>>Вообще говоря — любой объект можно считать иммутабельным в некоторой фазе работы программы... S>Это какая-то гуманитарщина. Поймите, иммутабельность — это не случайно обнаруженное поведение программы. Это набор некоторых гарантий. Нельзя быть "немножко беременной", или "частично мужчиной".
Как раз в случае иммутабельности можно быть "немножко беременной". Здесь в главе 3 "Круги ада" приведена классификация вариантов изменяемого состояния. Часть из них можно отнести к иммутабельности безоговорочно. Другие случаи (не все конечно) — условно.
Возьмем например случай "Двухфазный цикл жизни": объект во второй фазе несет тот же самый набор гарантий, что и иммутабельный. Но вот странно, получается что в первой фазе он "нормальный", а потом "не объект"....
"Монотонное изменяемое состояние" — типичный иммутабельный объект. Что отличает его от "нормального" объекта? То что он меняет свое состояние лишь однажды?
S>Гарантированная иммутабельность позволяет нам делать некоторые полезные преобразования программы, т.к. обеспечивает сохранение полезных инвариантов. S>Казуальная иммутабельность — всего лишь досадная помеха: она ограничивает возможности наших действий, но не даёт выигрыша.
Перечень полезных инвариантов выбирается программистом. Например, хочу я реализовать классический функциональный иммутабельный список на COM с распространенными операциями. Казалось бы, IUnknown противоречит иммутабельности. Но я могу считать такие списки "немножко" иммутабельными не обращая внимания на AddRef/Release. Это мне не помешает применять такие объекты для полезных преобразований. Будет ли у них identity?
Re[17]: Почему объектно-ориентированное программирование про
Здравствуйте, Sinclair, Вы писали:
V>>Токарный станок работает по шаблону, т.е. по некоторой модели будущего изделия. S>Я ждал этого комментария Конечно же, вы считаете шаблон основной частью станка.
Точнее говоря, шаблон — это не модель целиком, а параметр модели (ее проекция). Сама модель результата — это фигура вращения, и устройство станка полностью соответствует этой модели.
Является ли шаблон основной частью станка? Вопрос странный, и это еще мягко сказано.
S>То есть хорошей технологией производства токарных станков будет та, которая упрощает создание шаблонов.
Создания или применения?
S>Вопросы устройства самого станка, безусловно, вторичны.
Золотые слова. Важна лишь степень подходящести инструмента под задачу.
S>Если вас не устраивает токарный станок — возьмите сверлильный. Модели отверстия он не содержит.
Конечно же содержит параметрическую модель результата, так же как и токарный.
Определяется диаметром сверла.
Re[40]: Почему объектно-ориентированное программирование про
Здравствуйте, samius, Вы писали: S>А я наоборот не могу обнаружить значительных отличий.
Мы смотрим с разных точек зрения.
S>Верно. Однозначный способ ответить на этот вопрос в дотнете — ReferenceEquals. Все что делают методы Equals, компареры и прочее, все что используют словари — все это отвечает на вопрос об эквивалентности в том или ином смысле и имеет отношение к идентичности только в том случае, если речь идет о ссылочной эквивалентности.
Ещё раз: ReferenceEquals — это некая низкоуровневая операция. Уместность её применения в качестве основы для identity зависит от "прикладного" смысла окружающего её контекста.
К примеру, я могу забоксить экземпляр структурного типа, и начать манипулировать ссылками на него в ReferenceEquals. Технически ничто не мешает мне это делать; однако физического смысла в этом нет — оттого, что я получил два экземпляра int 5 в хипе, целые числа не стали обладать идентичностью. И с идентичностью этих двух забоксенных экземпляров я не могу сделать ничего полезного.
S>О value-типах тут в смысле о типах, чьи экземпляры передаются по значению? Или о таких как System.String?
С точки зрения теории, разницы между ними нет. Есть value-семантика, она гарантирует некоторое определённое поведение объектов.
S>Это имеет лишь тот смысл, что бы показать что пример работает с эквивалентностью а не идентичностью.
Пример показывает, что вводить идентичность для типов с value-семантикой не имеет физического смысла.
S>А почему нет? Иммутабельные объекты — это такие объекты, которые не проявляют изменение состояний внешне. Но это не значит что у них нет изменяемого состояния внутри. Возьмем например System.Lazy<T>. Если забыть о его свойстве IsValueCreated, то этот объект можно считать иммутабельным. Такие объекты отличимы один от другого и смысл их отличать есть. Разница от использования того или другого объекта с внешне одинаковым состоянием налицо, ибо может проявляться во времени вычисления значения, либо даже в сайд-эффектах. Но тему о сайдэффектах при работе иммутабельных объектах я не хотел бы развивать, т.к. к чистым концепциям она не имеет отношения.
Да, давайте без сайд-эффектов. Весь смысл оптимизации в программировании — в том, чтобы разделить "полезный" эффект и "побочные" эффекты, а затем заниматься преобразованиями программы, которые сохраняют "полезный" эффект, варьируя "побочные".
S>Как раз в случае иммутабельности можно быть "немножко беременной". Здесь в главе 3 "Круги ада" приведена классификация вариантов изменяемого состояния. Часть из них можно отнести к иммутабельности безоговорочно. Другие случаи (не все конечно) — условно. S>Возьмем например случай "Двухфазный цикл жизни": объект во второй фазе несет тот же самый набор гарантий, что и иммутабельный. Но вот странно, получается что в первой фазе он "нормальный", а потом "не объект"....
А какие преимущества мы можем из этого извлечь? Ну, кроме облегчения отладки?
Для настоящих immutable объектов мы можем проводить трансформации алгоритма автоматически. S>"Монотонное изменяемое состояние" — типичный иммутабельный объект. Что отличает его от "нормального" объекта? То что он меняет свое состояние лишь однажды?
Это не совсем изменяемое состояние. Объект своё состояние никак не меняет, это, фактически, SSA-форма (single static assignment).
S>Перечень полезных инвариантов выбирается программистом. Например, хочу я реализовать классический функциональный иммутабельный список на COM с распространенными операциями. Казалось бы, IUnknown противоречит иммутабельности. Но я могу считать такие списки "немножко" иммутабельными не обращая внимания на AddRef/Release. Это мне не помешает применять такие объекты для полезных преобразований. Будет ли у них identity?
В узком смысле — будет. Ведь сама идея AddRef/Release подсказывает, что у нас есть ссылки. В широком — .
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[18]: Почему объектно-ориентированное программирование про
Здравствуйте, vdimas, Вы писали:
V>Точнее говоря, шаблон — это не модель целиком, а параметр модели (ее проекция). Сама модель результата — это фигура вращения, и устройство станка полностью соответствует этой модели.
Вы вообще видели токарный станок? В нём самом нет никакой модели изделия. Различные компоненты токарного станка (коих, надо сказать, довольно много) взаимодействуют сложным образом для того, чтобы решить задачу. Можно, конечно, заниматься умственным самоудовлетворениям, придумывая "параметрические модели изделия".
V>Создания или применения?
Создания, создания. Ведь ООП вы предлагаете позиционировать как способ упрощения создания моделей задачи, а вовсе не применения.
V>Золотые слова. Важна лишь степень подходящести инструмента под задачу.
Под решение. То же изделие можно получить, к примеру, методом литья. Токарный станок вряд ли будет подходящим инструментом для такого решения, хотя задача и не изменилась.
V>Конечно же содержит параметрическую модель результата, так же как и токарный. V>Определяется диаметром сверла.
Ага. А отвёртка, надо полагать, содержит достаточно полную модель шурупа, молоток — гвоздя, ложка — блинного теста. Вам самому не смешно?
То, что некоторые параметры инструмента связаны с некоторыми параметрами решаемой задачи, простите, никак не тянет на моделирование. Выключатель не пытается моделировать лампочку, хотя их параметры, конечно же, должны быть согласованы.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[19]: Почему объектно-ориентированное программирование про
Здравствуйте, Sinclair, Вы писали:
V>>Точнее говоря, шаблон — это не модель целиком, а параметр модели (ее проекция). Сама модель результата — это фигура вращения, и устройство станка полностью соответствует этой модели. S>Вы вообще видели токарный станок?
Вопрос, надо полагать, риторический?
S>В нём самом нет никакой модели изделия.
Да есть. На токарном станке не выточишь кубик. Про фигуру вращения уже напомнил.
Можно предположить, что модели нету, если шаблон не установлен, и токарь работает "ручками". В этом случае у него модель есть в спеке изделия, подробности которой он ручками переносит на соотв. положение резака.
S>Различные компоненты токарного станка (коих, надо сказать, довольно много) взаимодействуют сложным образом для того, чтобы решить задачу. Можно, конечно, заниматься умственным самоудовлетворениям, придумывая "параметрические модели изделия".
Шаблон изделия — это и есть параметр конечного результата.
V>>Создания или применения? S>Создания, создания. Ведь ООП вы предлагаете позиционировать как способ упрощения создания моделей задачи, а вовсе не применения.
Ты изначально выразился насчет шаблона. Или же перефразируй исходную фразу, а то разговор переходит в русло слепого с глухим.
Да, ООП есть способ упрощения создания таких моделей, где подразумевается поведение, зависимое от состояния. Например, складская программа моделирует поведение кладовщика, где текущие остатки склада — его инкапсулированное состояние.
V>>Золотые слова. Важна лишь степень подходящести инструмента под задачу. S>Под решение.
Логично, именно поэтому есть несколько парадигм программирования.
S>То же изделие можно получить, к примеру, методом литья. Токарный станок вряд ли будет подходящим инструментом для такого решения, хотя задача и не изменилась.
Тонкость твоего примера в том, что для отлития фигур вращения таки используют токарный станок... для создания прототипа. А последующее литье — это суть копирование прототипа.
V>>Конечно же содержит параметрическую модель результата, так же как и токарный. V>>Определяется диаметром сверла. S>Ага. А отвёртка, надо полагать, содержит достаточно полную модель шурупа, молоток — гвоздя, ложка — блинного теста. Вам самому не смешно?
Отвертка на самом деле один из участников (акторов/объектов) в общей модели закручивания шурупа по его резьбе. Считай, что отвертка — некий адаптер к интерфейсу шурупа для передачи момента вращения. Ведь есть же и автоматические шуруповерты под тот же интерфейс. Почему ты решил, что один участник модели должен быть моделью другого участника? Участники модели взаимодействуют по некоторым интерфейсам.
S>То, что некоторые параметры инструмента связаны с некоторыми параметрами решаемой задачи, простите, никак не тянет на моделирование.
Ты как-то странно вообще рассматриваешь моделирование. Возьми некий сборный мост, например. Сначала выводится его модель, потом она расчитывается, причем расчитывается взаимодействие и заклепок, и балок и силы тяжести и прочих получаемых векторов приложения силы. Процесс разрушения моста под собственным весом тоже можно промоделировать. Насколько я понимаю, торговля идет относительно того, применять для этого ООП или нет? Ну дык, почему нет? В чистом ФП при численном интегрировании мы бы получали иммутабельные "сшапшоты" динамического процесса, в ООП мы эти же наборы чисел храним явным образом в тех же самых ячейках памяти, что и на предыдущем шаге, вот и все отличие. Как было показано уже не раз, для очень большого класса задач это эффективней на порядок/другой на современных архитекрурах. Обсуждали уже поточные архитектуры, где чистое ФП могло быть достаточно эффективным, их время еще не пришло из-за особых требований к ассоциативной памяти. Т.е. сейчас мы имеем, что имеем. Получается, что мы не просто делаем модель, но идем на некий компромисс, учитывая вычислительную модель современных компьютеров.
S>Выключатель не пытается моделировать лампочку, хотя их параметры, конечно же, должны быть согласованы.
Да что за бардак у тебя в голове? Выключатель — это часть цепи. Осуществляет замыкание/размыкание в этой модели и имеет вполне определенные состояния. Заметь, лампочка и источник напряжения не имеют состояния, они являются чистыми ф-иями (если не учитывать нагрев спирали), но выключатель — имеет. Соотв, для модели такой цепи нужен один регистр памяти и пара ф-ий.
Все становится интересней, если в цепи есть активные элементы: емкости и индуктивности. Во временной области они имеют вполне четкое мнгновенное состояние, т.е. при моделировании работы такой цепи путем численного интегрирования нам опять же удобно где-то хранить текущие мгновенные значения токов и напряжений. В операторной области, что характерно, активные элементы представлены опять же чистыми ф-ями. Но это же совсем другая модель, не имеющая состояния, а имеющая только однократно устанавливаемые параметры. И для этой другой модели вполне удобно использовать то же ФП.
Я вообще предмета спора не понимаю. Если нам удобно обслуживаемую компьютером целевую автоматизацию чего-либо представить в виде модели, участники которой имеют состояние, то самое удобное на сегодня — это ООП. Если удается построить модель, не требующую состояния — можно брать другие парадигмы. Более того, уже раз 1000 замечал, что даже в моделях, имеющих элементы с состояниями, полно бывает "чистых" ф-ий. И даже в самих алгоритмах вычисления следующего состояния объектов крайне удобно использовать именно чистые ф-ии для обеспечения транзакционности. Вот здесь прошелся подробнее: http://rsdn.ru/forum/philosophy/4171151.1.aspx
, начиная от фразы "Ты поменьше функциональщиков слушай".
По мне ООП еще удобнее тем, что требует больше разметки в исходном коде, а это важная часть самодокументации, показывающей отношение элементов программы к описываемой модели. Мы размечаем регистры памяти, даем им имена, даже описываем "мета-регистры" — свойства. Вместо безымянных туплов используем "маленькие" объекты с хорошей внутренней инкапсуляцией, и содержащих обычно встроенные ср-ва валидации своего состояния и безопасности, с т.з. этого состояния, совершаемых над ними операций. Даже простой факт группировкиэтих регистров памяти и операций по ним в некую логическую единицу дает для читабельности кода больше, чем многие экраны комментариев. Это всё теоретически обосновано? Нет конечно, ведь слишком велика свобода действий. Это лишь удобные практики, и грех ими не пользоваться.
В этой же ветке я по большей части выступал за то, чтобы в ООП тащить и другие практики, например из ФП и вспомнить "хорошо забытое старое" — процедурный подход. А он фактически уже забывается, как я вижу по коду более молодых коллег. Я наблюдаю, что "догматический" подход к ООП так же вреден, как и принципиальный отказ от него, ибо такой подход требует лишней трудоемкости по постоянной переделке решения в ходе лишь по причине реализации функциональных требований. ИМХО, абсурдная ситуация.
Re[41]: Почему объектно-ориентированное программирование про
Здравствуйте, Sinclair, Вы писали:
S>Ещё раз: ReferenceEquals — это некая низкоуровневая операция. Уместность её применения в качестве основы для identity зависит от "прикладного" смысла окружающего её контекста. S>К примеру, я могу забоксить экземпляр структурного типа, и начать манипулировать ссылками на него в ReferenceEquals. Технически ничто не мешает мне это делать; однако физического смысла в этом нет — оттого, что я получил два экземпляра int 5 в хипе, целые числа не стали обладать идентичностью. И с идентичностью этих двух забоксенных экземпляров я не могу сделать ничего полезного.
Это ничего не доказывает.
S>>О value-типах тут в смысле о типах, чьи экземпляры передаются по значению? Или о таких как System.String? S>С точки зрения теории, разницы между ними нет. Есть value-семантика, она гарантирует некоторое определённое поведение объектов.
value-семантика гарантирует копирование при присваивании и передаче в качестве аргумента. То что она имеет одинаковое поведение со ссылками на иммутабельные объекты, не делает их неразличаемыми.
S>>Это имеет лишь тот смысл, что бы показать что пример работает с эквивалентностью а не идентичностью. S>Пример показывает, что вводить идентичность для типов с value-семантикой не имеет физического смысла.
Что значит вводить? Она есть. Пользоваться ей мало смысла — возможно.
А вообще, в ООП паттернах у объектов есть куча ролей, где идентичность не имеет физического смысла. Это делает их не объектами?
S>>Как раз в случае иммутабельности можно быть "немножко беременной". Здесь в главе 3 "Круги ада" приведена классификация вариантов изменяемого состояния. Часть из них можно отнести к иммутабельности безоговорочно. Другие случаи (не все конечно) — условно. S>>Возьмем например случай "Двухфазный цикл жизни": объект во второй фазе несет тот же самый набор гарантий, что и иммутабельный. Но вот странно, получается что в первой фазе он "нормальный", а потом "не объект".... S>А какие преимущества мы можем из этого извлечь? Ну, кроме облегчения отладки? S>Для настоящих immutable объектов мы можем проводить трансформации алгоритма автоматически.
В неизменяемой фазе — все те же, что и для неизменяемых объектов. В изменяемой фазе — может иметь место императивное построение/конфигурация обеъкта. S>>"Монотонное изменяемое состояние" — типичный иммутабельный объект. Что отличает его от "нормального" объекта? То что он меняет свое состояние лишь однажды? S>Это не совсем изменяемое состояние. Объект своё состояние никак не меняет, это, фактически, SSA-форма (single static assignment).
Никакого отношения к SSA, имхо. Типичный Lazy<T>.
S>>Перечень полезных инвариантов выбирается программистом. Например, хочу я реализовать классический функциональный иммутабельный список на COM с распространенными операциями. Казалось бы, IUnknown противоречит иммутабельности. Но я могу считать такие списки "немножко" иммутабельными не обращая внимания на AddRef/Release. Это мне не помешает применять такие объекты для полезных преобразований. Будет ли у них identity? S>В узком смысле — будет. Ведь сама идея AddRef/Release подсказывает, что у нас есть ссылки. В широком — .
Предлагаю закругляться. Сам я не вижу смысл судить об "объектности" объекта по наличию физического смысла идентичности этого объекта. Жаль, если мне не удалось склонить к своему мнению, или хотя бы посеять сомнения в ценности деления на объекты и необъекты по смыслу идентичности. В любом случае спасибо за дискуссию.
Re[37]: Почему объектно-ориентированное программирование про
Здравствуйте, Sinclair, Вы писали:
S>Имхо, да. Вы поймите — не всё, что можно запрограммировать на ОО-языке является реализацией корректной объектной модели. На C# можно, к примеру, сделать чисто статический класс. С точки зрения ООП его не может быть.
Может. Это аналог объекта-синглтона. Разве что чуть упростили интерфейс к нему.
Re[20]: Почему объектно-ориентированное программирование про
Здравствуйте, vdimas, Вы писали:
V>Вопрос, надо полагать, риторический?
Ага. V>Да есть. На токарном станке не выточишь кубик. Про фигуру вращения уже напомнил.
Не стоит все ограничения принимать за модель. V>Можно предположить, что модели нету, если шаблон не установлен, и токарь работает "ручками". В этом случае у него модель есть в спеке изделия, подробности которой он ручками переносит на соотв. положение резака.
Совершенно верно. В спеке (т.е. в чертеже) модель есть. В инструменте — нету.
V>Ты изначально выразился насчет шаблона. Или же перефразируй исходную фразу, а то разговор переходит в русло слепого с глухим.
Я изначально выразился насчёт токарного станка.
V>Да, ООП есть способ упрощения создания таких моделей, где подразумевается поведение, зависимое от состояния. Например, складская программа моделирует поведение кладовщика, где текущие остатки склада — его инкапсулированное состояние.
Что характерно, для складских программ чистое ООП почему-то плохо применимо. Туда идеально подходит реляционная алгебра — поскольку инкапсулированное состояние мало кого интересует. Интересует как раз наоборот — возможность получать различные проекции одного и того же состояния.
Предлагаю поверить мне на слово — я занимался моделированием склада при помощи ООП на профессиональной основе. Ну там, объект Склад, объект Партия, объект ЕдиницаИзмерения.
Результат вкратце: ООП сосёт. Преимуществ никаких, недостатков и ограничений — масса.
Поэтому в реальной складской программе, написанной на ОО-языке, объекты моделируют исключительно компоненты решения — всякие SqlStatement, DBConnection, и прочее. V>Логично, именно поэтому есть несколько парадигм программирования.
Ну, в общем смысле да. Но я подчеркну — то, что от складской программы требуется давать остатки по партиям/видам товара/складам/поставщикам не означает неприменимости для неё ООП. В конце концов, 99% современных складских программ написаны таки на ОО-языках, и кода за пределами классов там совсем мало. Просто ООП в них применяется не для моделирования задачи или какого-то там "реального мира", а для моделирования решения этой задачи.
V>Тонкость твоего примера в том, что для отлития фигур вращения таки используют токарный станок... для создания прототипа. А последующее литье — это суть копирование прототипа.
Прототип может быть получен чем угодно. В том числе и трёхмерным принтером. Тонкость моего примера в том, что сначала выбирают некоторый путь решения. А потом вот это вот абстрактное решение воплощают в некоторой конкретной парадигме. К примеру, я могу реализовать умножение матриц в виде семейства stateless функций, которые оперируют над immutable данными. А могу — в виде набора stateful объектов, которые обмениваются сообщениями. Уместность того или иного подхода зависит исключительно от того, каким должно получиться полное решение. А вовсе не от задачи. Возможно, в данной задаче вообще можно обойтись без умножения матриц.
V>Отвертка на самом деле один из участников (акторов/объектов) в общей модели закручивания шурупа по его резьбе. Считай, что отвертка — некий адаптер к интерфейсу шурупа для передачи момента вращения. Ведь есть же и автоматические шуруповерты под тот же интерфейс. Почему ты решил, что один участник модели должен быть моделью другого участника?
Это не я решил — это решили те, кто убеждает в том, что основная роль ООП — в моделировании задачи.
Программа точно так же — всего лишь один из участников в общей модели чего-то там. Например, отслеживания отгрузок по складу. Физический склад — другой участник этой модели. И совершенно непонятно, почему один участник должен содержать в себе модель другого.
V>Ты как-то странно вообще рассматриваешь моделирование. Возьми некий сборный мост, например. Сначала выводится его модель, потом она расчитывается, причем расчитывается взаимодействие и заклепок, и балок и силы тяжести и прочих получаемых векторов приложения силы. Процесс разрушения моста под собственным весом тоже можно промоделировать. Насколько я понимаю, торговля идет относительно того, применять для этого ООП или нет?
Торговля идёт относительно того, насколько часто приходится моделировать в программистской деятельности. О применимости ООП для этого торговля идёт уже во вторую очередь.
V>Ну дык, почему нет? В чистом ФП при численном интегрировании мы бы получали иммутабельные "сшапшоты" динамического процесса, в ООП мы эти же наборы чисел храним явным образом в тех же самых ячейках памяти, что и на предыдущем шаге, вот и все отличие.
Ну как же — вы очень упрощаете ООП. Какие ещё ячейки памяти? ООП расположено на значительно более высоком уровне абстракции. Вполне возможно, что ФП-компилятор решит повторно использовать те же ячейки памяти, поскольку иммутабельность — это свойство исходной программы, а не ячейки памяти.
В принципе, я могу поверить, хотя и с оговорками, в то, что для моделирования моста удобно будет применять ООП-шные объекты, которые соответствуют его деталям.
А вот для моделирования работы датчика скорости потока на эффекте Холла вы какие объекты собираетесь описывать? Вода, МагнитноеПоле, Датчик?
S>>Выключатель не пытается моделировать лампочку, хотя их параметры, конечно же, должны быть согласованы.
V>Да что за бардак у тебя в голове?
У меня нет никакого бардака. V>Выключатель — это часть цепи. Осуществляет замыкание/размыкание в этой модели и имеет вполне определенные состояния. Заметь, лампочка и источник напряжения не имеют состояния, они являются чистыми ф-иями (если не учитывать нагрев спирали), но выключатель — имеет. Соотв, для модели такой цепи нужен один регистр памяти и пара ф-ий.
Нам не нужна модель цепи. Выключатель прекрасно работает безо всякой модели. Это была аналогия.
Вот у нас стоит задача управления освещением в комнате. С этим справляется выключатель. В нём, очевидно, модели лампочки нет. Можете на досуге разобрать выключатель и поискать там модель лампочки.
Далее, переходим к более сложной задаче — управление яркостью света. Появляется диммер. Он устроен сложнее, чем выключатель, но модели лампочки в нём по-прежнему нет.
Теперь сделаем управление яркостью света с обратной связью — чтобы ночью свет автоматически включался, а днём выключался. В цепи появятся фотоэлементы, и прочая электроника. Способов решить эту задачу существенно больше, но и в них никакой модели лампочки и окружающей среды по прежнему нет. Есть модель некоего устройства "управляющий элемент".
Если мы захотим усложнять задачу, мы рано или поздно заколебаемся и перейдём в цифровой мир, в котором есть абстрактная железка "микроконтроллер", которая управляет чем угодно. И есть программная часть решения задачи. Так вот — совершенно непонятно, зачем в этот момент внезапно в программной части решения возникнет какая-то модель задачи, которая до сих пор была не нужна. Я не говорю, что там неприменимо ООП. Нет, ООП там очень даже может быть применимо. Но только объекта "лампочка" там, скорее всего, не будет. Вот программный аналог объекта "выключатель" там запросто может оказаться — тот самый регистр.
А тем временем укушенные ООП люди на полном серъёзе предлагают писать программу, в которой будут объекты Лампочка и Фотодатчик.
V>Все становится интересней, если в цепи есть активные элементы: емкости и индуктивности. Во временной области они имеют вполне четкое мнгновенное состояние, т.е. при моделировании работы такой цепи путем численного интегрирования нам опять же удобно где-то хранить текущие мгновенные значения токов и напряжений. В операторной области, что характерно, активные элементы представлены опять же чистыми ф-ями. Но это же совсем другая модель, не имеющая состояния, а имеющая только однократно устанавливаемые параметры. И для этой другой модели вполне удобно использовать то же ФП.
Вы всё время путаете задачу и решение. Задача была — управлять лампочкой. Не смоделировать лампочку, а управлять ей. Если вам вдруг потребовалась модель электрической цепи, значит задача у вас была в чём-то другом. Например, рассчитать параметры цепи, для того, чтобы подготовить документацию для продукта "электрический звонок" или "аналоговая сигнализация".
V>Я вообще предмета спора не понимаю. Если нам удобно обслуживаемую компьютером целевую автоматизацию чего-либо представить в виде модели, участники которой имеют состояние, то самое удобное на сегодня — это ООП.
Совершенно верно. Только эта модель будет, грубо говоря, моделью идеального устройства, решающего целевую задачу. А не моделью объектов, из которых состоит предметная область.
Именно поэтому в реальных программах полно объектов типа Window, Control, Connection, и прочих, которые никакого отношения к предметной области не имеют.
Что очень сильно отличается от того, что преподают на курсах "ООП за 21 день".
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[42]: Почему объектно-ориентированное программирование про
Здравствуйте, samius, Вы писали:
S>value-семантика гарантирует копирование при присваивании и передаче в качестве аргумента. То что она имеет одинаковое поведение со ссылками на иммутабельные объекты, не делает их неразличаемыми.
Нет. Объекты класса String в .Net имеют value-семантику. Очевидно, никаких гарантий копирования эта семантика не даёт. Value-семантика гарантирует взаимозаменяемость объектов с одинаковым состоянием, ни больше и ни меньше. Вы путаете математическую семантику "значение" с реализацией value-типов в конкретной платформе.
S>Что значит вводить? Она есть. Пользоваться ей мало смысла — возможно.
Её нету. S>А вообще, в ООП паттернах у объектов есть куча ролей, где идентичность не имеет физического смысла. Это делает их не объектами?
Вопрос на миллион долларов.
S>В неизменяемой фазе — все те же, что и для неизменяемых объектов. В изменяемой фазе — может иметь место императивное построение/конфигурация обеъкта. S>>>"Монотонное изменяемое состояние" — типичный иммутабельный объект. Что отличает его от "нормального" объекта? То что он меняет свое состояние лишь однажды? S>>Это не совсем изменяемое состояние. Объект своё состояние никак не меняет, это, фактически, SSA-форма (single static assignment). S>Никакого отношения к SSA, имхо. Типичный Lazy<T>.
Lazy<T>, по приведённой классификации, меняет своё состояние дважды. Сначала — при инициализации, второй раз — при первом обращении.
S>Предлагаю закругляться. Сам я не вижу смысл судить об "объектности" объекта по наличию физического смысла идентичности этого объекта. Жаль, если мне не удалось склонить к своему мнению, или хотя бы посеять сомнения в ценности деления на объекты и необъекты по смыслу идентичности. В любом случае спасибо за дискуссию. Да, я получил много поводов подумать. на jot.fm была серия статей про математические модели, стоящие за ООП. Надо бы перечитать. А то среди народа упорно бытует мнение о том, что ООП, в отличие от ФП, не формализовано
Вообще, в программировании сейчас наблюдается значительный разрыв между теорией и практикой. Я не знаю, почему он происходит, но выглядит всё просто ужасно. Детям сначала рассказывают про высокое, а потом они приходят работать, а там ужосчто. И про этот ужосчто никаких вменяемых книг уже нету, приходится дотумкивать своим умом. Не всегда успешно. Тем более, что существуют упорно тиражируемые заблуждения, которые только отвлекают от сути вещей. Я уже упоминал про эпический спор об уровнях изоляции в РСУБД? Мне даже ссылки на Бернстайна приводили. Вот только оппа в том, что Бернстайн ни в одном месте про уровни изоляции явно не пишет. Как будто их нет. А они — есть. И вот люди начинают изобретать такие объяснения этим уровням изоляции, что шуба заворачивается. Включая искреннюю веру в то, что не все шедулеры транзакций обязаны обеспечивать сериализуемость.
И вот с ООП — то же самое.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[38]: Почему объектно-ориентированное программирование про
Здравствуйте, vdimas, Вы писали:
V>Здравствуйте, Sinclair, Вы писали:
S>>Имхо, да. Вы поймите — не всё, что можно запрограммировать на ОО-языке является реализацией корректной объектной модели. На C# можно, к примеру, сделать чисто статический класс. С точки зрения ООП его не может быть.
V>Может. Это аналог объекта-синглтона. Разве что чуть упростили интерфейс к нему.
Ну да. Но это такой довольно отдалённый аналог . Впрочем, можно же усложнять базовую модель ООП. Это в самом минимуме объекты, идентичность, поведение. Потом начинается — классы, интерфейсы, полиморфизм, прототипы, метаклассы, и всё остальное во всё более интересных сочетаниях.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[43]: Почему объектно-ориентированное программирование про
Здравствуйте, Sinclair, Вы писали:
S>Здравствуйте, samius, Вы писали:
S>>value-семантика гарантирует копирование при присваивании и передаче в качестве аргумента. То что она имеет одинаковое поведение со ссылками на иммутабельные объекты, не делает их неразличаемыми. S>Нет. Объекты класса String в .Net имеют value-семантику.
Откуда это следует?
Вот здесь ничего нет о String. S>Очевидно, никаких гарантий копирования эта семантика не даёт. Value-семантика гарантирует взаимозаменяемость объектов с одинаковым состоянием, ни больше и ни меньше.
Можно где-то об этом почитать? S>Вы путаете математическую семантику "значение" с реализацией value-типов в конкретной платформе.
На нескольких разных платформах подразумевается одно и то же. И по ссылке выше — тоже. Где можно почитать о вашем толковании value-семантики?
S>>>Это не совсем изменяемое состояние. Объект своё состояние никак не меняет, это, фактически, SSA-форма (single static assignment). S>>Никакого отношения к SSA, имхо. Типичный Lazy<T>. S>Lazy<T>, по приведённой классификации, меняет своё состояние дважды. Сначала — при инициализации, второй раз — при первом обращении.
Есть примеры объектов, которые не меняют свое состояние при инициализации?
S>Вообще, в программировании сейчас наблюдается значительный разрыв между теорией и практикой. Я не знаю, почему он происходит, но выглядит всё просто ужасно. Детям сначала рассказывают про высокое, а потом они приходят работать, а там ужосчто. И про этот ужосчто никаких вменяемых книг уже нету, приходится дотумкивать своим умом. Не всегда успешно. ... S>И вот с ООП — то же самое.
Ну вот мне кажется, что необходимость в физическом смысле идентичности для объекта дотумкана. У Буча идентичность — это свойство объекта, а не необходимое условие для его существования. А Кей вообще ничего не говорил об идентичности, упоминая лишь поведение и состояние.
Re[44]: Почему объектно-ориентированное программирование про
Здравствуйте, samius, Вы писали: S>>Нет. Объекты класса String в .Net имеют value-семантику. S>Откуда это следует?
Из поведения строк. Я приводил примеры. Вот чуть менее платформенно-зависимое описание того, что такое value semantic http://c2.com/cgi/wiki?ValueSemantics S>Можно где-то об этом почитать? S>На нескольких разных платформах подразумевается одно и то же. И по ссылке выше — тоже. Где можно почитать о вашем толковании value-семантики?
По ссылке выше.
Очередное упражнение на логику: все struct-типы имеют value-семантику (см. вашу ссылку про C#). Но не все типы с value-семантикой обязаны быть struct-типами.
S>Есть примеры объектов, которые не меняют свое состояние при инициализации?
А, похоже, я неправильно понял ту часть статьи. Да, в таком случае это Lazy<T>.
S>Ну вот мне кажется, что необходимость в физическом смысле идентичности для объекта дотумкана. У Буча идентичность — это свойство объекта, а не необходимое условие для его существования.
Свойство любого объекта. S>А Кей вообще ничего не говорил об идентичности, упоминая лишь поведение и состояние.
Без идентичности невозможно реализовать посылку сообщения.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[45]: Почему объектно-ориентированное программирование про
Здравствуйте, Sinclair, Вы писали:
S>>>Нет. Объекты класса String в .Net имеют value-семантику. S>>Откуда это следует? S>Из поведения строк. Я приводил примеры. Вот чуть менее платформенно-зависимое описание того, что такое value semantic http://c2.com/cgi/wiki?ValueSemantics
An object has ValueSemantics when it can be treated as a single value.
Сомнительное описание. Неясно, что мешает рассматривать как single value все что угодно.
In C++ this means implementing a copy constructor and an assignment operator in such a way that when a new or existing instance is set equal to some other instance the new instance will be equivalent to the old one without acting as an alias to it.
Последняя оговорка C++ трактовки как раз исключает System.String из этой формулировки.
S>>На нескольких разных платформах подразумевается одно и то же. И по ссылке выше — тоже. Где можно почитать о вашем толковании value-семантики? S>По ссылке выше. S>Очередное упражнение на логику: все struct-типы имеют value-семантику (см. вашу ссылку про C#). Но не все типы с value-семантикой обязаны быть struct-типами.
Приведенная выше формулировка исключает value-сематнику строки .NET как и остальные, которые я встречал. Можно привести ссылку на определение, которое бы соответствовало вашим выводам?
S>>Ну вот мне кажется, что необходимость в физическом смысле идентичности для объекта дотумкана. У Буча идентичность — это свойство объекта, а не необходимое условие для его существования. S>Свойство любого объекта.
Угу, и наверное так же объекта, чье состояние не меняется. Никаких оговорок у Буча нет по этому поводу. S>>А Кей вообще ничего не говорил об идентичности, упоминая лишь поведение и состояние. S>Без идентичности невозможно реализовать посылку сообщения.
Из этого утверждения напрашивается вывод о том что иммутабельные объекты обладают идентичностью (иначе невозможно реализовать посылку сообщения, а сообщения им посылать можно), и предположение о физическом смысле идентичности для таких объектов (для возможности посылки сообщения).
Re[46]: Почему объектно-ориентированное программирование про
Здравствуйте, samius, Вы писали:
S>Сомнительное описание. Неясно, что мешает рассматривать как single value все что угодно.
Мешает, например, наличие раздельного поведения у различных экземпляров. Все строки "Hello" в дотнете эквивалентны, точно так же, как и все целые числа 5.
S>
S>In C++ this means implementing a copy constructor and an assignment operator in such a way that when a new or existing instance is set equal to some other instance the new instance will be equivalent to the old one without acting as an alias to it.
S>Последняя оговорка C++ трактовки как раз исключает System.String из этой формулировки.
Нет. Вы неправильно понимаете термин alias.
Следите за руками:
int a = 5;
int & b = a;
b += 1;
cout << a;
Вот что такое alias.
Попробуем сделать то же самое с интом-значением:
int a = 5;
int b = a;
b += 1;
cout << a; // вот чем отличается alias от copy
Теперь попробуем со строкой:
string a = "5";
string b = a;
b += "1";
Console.WriteLine(a);
Видите? Несмотря на отсутствие копирования при присваивании, b всё равно не ведёт себя как alias для a.
S>Приведенная выше формулировка исключает value-сематнику строки .NET как и остальные, которые я встречал. Можно привести ссылку на определение, которое бы соответствовало вашим выводам?
Как я показал выше, вы ошибаетесь.
S>Из этого утверждения напрашивается вывод о том что иммутабельные объекты обладают идентичностью (иначе невозможно реализовать посылку сообщения, а сообщения им посылать можно), и предположение о физическом смысле идентичности для таких объектов (для возможности посылки сообщения).
Главное для меня здесь — наличие смысла в посылке сообщения какому-то конкретному объекту. Вы меня почти убедили, что для эквивалентных иммутабельных объектов всё ещё может иметь смысл посылать сообщения кому-то конкретному.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[47]: Почему объектно-ориентированное программирование про
Здравствуйте, Sinclair, Вы писали:
S>Здравствуйте, samius, Вы писали:
S>>Сомнительное описание. Неясно, что мешает рассматривать как single value все что угодно. S>Мешает, например, наличие раздельного поведения у различных экземпляров. Все строки "Hello" в дотнете эквивалентны, точно так же, как и все целые числа 5.
Но позвольте, во-первых в том определении ничего нет про эквивалентность и раздельное поведение. std::vector<int> обладает value-семантикой по тому определению (включая уточнение о том что это значит в C++). Т.е. некто рассматривает std::vector<int> как одиночное значение. Что мешает рассматривать как одиночное значение List<int>? Именно уточнение, которого говорит что при присваивании должна создаваться копия, а не алиас.
S>>
S>>In C++ this means implementing a copy constructor and an assignment operator in such a way that when a new or existing instance is set equal to some other instance the new instance will be equivalent to the old one without acting as an alias to it.
S>>Последняя оговорка C++ трактовки как раз исключает System.String из этой формулировки. S>Нет. Вы неправильно понимаете термин alias. S>Следите за руками: S>
S>int & b = a;
S>
S>Вот что такое alias.
+1 S>Попробуем сделать то же самое с интом-значением: S>
S>int b = a;
S>cout << a; // вот чем отличается alias от copy
S>
+1 S>Теперь попробуем со строкой: S>
S>string a = "5";
S>string b = a;
S>b += "1";
S>Console.WriteLine(a);
S>
S>Видите? Несмотря на отсутствие копирования при присваивании, b всё равно не ведёт себя как alias для a.
В этом примере вы смещаете акценты... Строкой вы здесь считаете не сам экземпляр System.String, а ссылку на него.
Я соглашусь со следующей формулировкой: Строка в дотнете формально соответствует reference-семантике, хотя и обладает чертами поведения value. Т.е. alias в смысле еще одного "имени" того же экземпляра таки создается, но изменить состояние экземпляра через этот alias не удастся, потому его "можно считать" копией.
Да, в таком аспекте я готов обобщить утвреждение до иммутабельных объектов.
S>>Приведенная выше формулировка исключает value-сематнику строки .NET как и остальные, которые я встречал. Можно привести ссылку на определение, которое бы соответствовало вашим выводам? S>Как я показал выше, вы ошибаетесь.
Не готов с этим согласиться. Она обладает чертами value-типа в том плане что ее нельзя изменить через alias. Но формально все-же reference.
Осталось разобратся, почему value не являются объектами.
S>Или может строка это не объект? Тогда что отличает объект от необъекта? Ниужели наличие изменяемого состояния?
Конечно же не объект. Строка имеет семантику value-типа.
S>>Из этого утверждения напрашивается вывод о том что иммутабельные объекты обладают идентичностью (иначе невозможно реализовать посылку сообщения, а сообщения им посылать можно), и предположение о физическом смысле идентичности для таких объектов (для возможности посылки сообщения). S>Главное для меня здесь — наличие смысла в посылке сообщения какому-то конкретному объекту. Вы меня почти убедили, что для эквивалентных иммутабельных объектов всё ещё может иметь смысл посылать сообщения кому-то конкретному.
Даже если смысла нет, но раз мы можем послать сообщение конкретному, значит идентичность есть. И вот еще над чем интересно подумать: можем ли мы послать сообщение не какому-то конкретному объекту? Пусть даже сообщение посылается с предикатом, через границы домена, или еще как... Но получить-то его может только конкертный объект, если не говорить об экзотике вроде ((Foo*)rnd())->Bar();
Какие есть другие причины что бы не считать value объектами?
Re[21]: Почему объектно-ориентированное программирование про
Здравствуйте, Sinclair, Вы писали:
V>>Да есть. На токарном станке не выточишь кубик. Про фигуру вращения уже напомнил. S>Не стоит все ограничения принимать за модель.
У тебя то один элемент модели должен быть моделью другого элемента, то уже сами ограничения.
Ограничения, именно что диктуют выбор модели. Т.е. не являются моделью, но влияют на нее.
V>>Можно предположить, что модели нету, если шаблон не установлен, и токарь работает "ручками". В этом случае у него модель есть в спеке изделия, подробности которой он ручками переносит на соотв. положение резака. S>Совершенно верно. В спеке (т.е. в чертеже) модель есть. В инструменте — нету.
Инструмент i]соответствует[/i] модели. Или надо брать другой инструмент.
V>>Ты изначально выразился насчет шаблона. Или же перефразируй исходную фразу, а то разговор переходит в русло слепого с глухим. S>Я изначально выразился насчёт токарного станка.
Вот здесь сумбурно:
То есть хорошей технологией производства токарных станков будет та, которая упрощает создание шаблонов.
V>>Да, ООП есть способ упрощения создания таких моделей, где подразумевается поведение, зависимое от состояния. Например, складская программа моделирует поведение кладовщика, где текущие остатки склада — его инкапсулированное состояние.
S>Что характерно, для складских программ чистое ООП почему-то плохо применимо. Туда идеально подходит реляционная алгебра — поскольку инкапсулированное состояние мало кого интересует. Интересует как раз наоборот — возможность получать различные проекции одного и того же состояния.
ООП это не запрещает.
Запросы — это одно, а обновление карточек товара — другое. Да, реляционная алгебра хороша для выборок. Ну дык для реализаций методов объектов мы используем ту же самую алгоритмическую декомпозицию, то бишь процедурный подход. Не вижу противоречий.
S>Предлагаю поверить мне на слово — я занимался моделированием склада при помощи ООП на профессиональной основе. Ну там, объект Склад, объект Партия, объект ЕдиницаИзмерения. S>Результат вкратце: ООП сосёт. Преимуществ никаких, недостатков и ограничений — масса.
Я тоже занимался много лет — у меня ничего не сосало. Да, некие ограничения есть из-за того, что мы храним данные в SQL серверах, и в этом месте вынуждены прописывать большую часть операций из-за соображений эффективности и целостности, обеспечиваемой самими серверами. И должны бороться с ограничениями инструмента. Но никто же не запрещает вызовы этих операций из прикладного кода инкапсулировать в методах объектов. Оперировать складами как объектами, а не напрямую их ID в программе довольно удобно. Понятное дело, что стоит подумать, какую сущность удобнее представлять "объектами", а какую "данными". Хотя критерий относительно прост: если данных мало, а связанных с ними операций много — то удобнее оформлять данные в виде объектов. Например, склады, контрагенты, торговые точки, валюты. Напротив, товар и движения удобно представлять в виде данных. Отчеты и срезы опять же удобнее делать из другого инструмента — из OLAP. Т.е. прописать отображение данных и вертеть затем твою реляционную алгебру. Т.е. это уже другая задача и под нее нужен другой инструмент. Хотя опять же, удобно представлять прикладные запросы как объекты, хранящие/валидирующие свои параметры и абстрагирующие нас от подробностей совершения самих запросов. В общем, отсосать может конкретный дизайн, но никак не парадигма.
S>Поэтому в реальной складской программе, написанной на ОО-языке, объекты моделируют исключительно компоненты решения — всякие SqlStatement, DBConnection, и прочее.
По крайней мере, самая популярная складская программа с тобой не согласна. Объекты могут быть на всех уровнях.
V>>Логично, именно поэтому есть несколько парадигм программирования. S>Ну, в общем смысле да. Но я подчеркну — то, что от складской программы требуется давать остатки по партиям/видам товара/складам/поставщикам не означает неприменимости для неё ООП. В конце концов, 99% современных складских программ написаны таки на ОО-языках, и кода за пределами классов там совсем мало. Просто ООП в них применяется не для моделирования задачи или какого-то там "реального мира", а для моделирования решения этой задачи.
Гм. Опять бардак в рассуждениях. Что есть модель? Это прототип оригинала с некоторой степенью подробности. Твое "решение" — это и есть некая выбранная модель происходящего. Ведь реальные остатки со склада не уходят сами по себе, когда ты вносишь очередную накладную. Ты лишь моделируешь выдачу товара в своём решении. И корректность отчетов будет зависеть от того, насколько точно вы программе промоделировали происходящене на самом деле.
Понятное дело, что модели могут различаться, и как степенью подробностей, так и взглядом на происходящее. Например, есть два популярных способа ведения складского учета — на основе складских карточек (учет по партиям), и на основе обобщенных остатков, объединенных через общий справочник товаров (по средневзвешенной цене). Это разные модели, т.е. разные "решения". Получаем даже разные мгновенные результаты профита по каждой сделке. Но по моменту продажи всего товара со склада результат будет одинаковый, поэтому обе модели признаны корректными. Это я к тому, что разнообразие решений/моделей — это более чем нормально. А на низком уровне, когда доходит до реализации нефункциональных требований, т.е. до борьбы с конкретными библиотеками, платформами, разрядностью, языками — то этих "решений по месту" может быть вообще бесчисленное кол-во. Попроси двух спецов написать программу по одним и тем же требованиям даже на одной и той же платформе — и в этих программах не будет практически ничего общего, хотя делать они будут одно и то же.
V>>Тонкость твоего примера в том, что для отлития фигур вращения таки используют токарный станок... для создания прототипа. А последующее литье — это суть копирование прототипа. S>Прототип может быть получен чем угодно. В том числе и трёхмерным принтером. Тонкость моего примера в том, что сначала выбирают некоторый путь решения. А потом вот это вот абстрактное решение воплощают в некоторой конкретной парадигме. К примеру, я могу реализовать умножение матриц в виде семейства stateless функций, которые оперируют над immutable данными. А могу — в виде набора stateful объектов, которые обмениваются сообщениями. Уместность того или иного подхода зависит исключительно от того, каким должно получиться полное решение. А вовсе не от задачи.
Я уже делал замечание насчет вычислительной модели. Она накладывает свои ограничения и требования. Например, эффективней может оказаться императивное умножение с явным мутабельным состоянием, просто потому, что современные ФП языки и близко не научились генерить оптимизированный код. Де-факто, сегодня нет в природе таких оптимизирующих компляторов для других языков, какие есть сейчас для С++, и этот момент тоже может являться существенным при выборе парадигмы решения задачи.
S>Это не я решил — это решили те, кто убеждает в том, что основная роль ООП — в моделировании задачи.
Не перевирай. Было сказано, что ООП хорошо подходит для создания моделей, участники которых имеют поведение, зависимое от состояния.
S>Программа точно так же — всего лишь один из участников в общей модели чего-то там. Например, отслеживания отгрузок по складу. Физический склад — другой участник этой модели. И совершенно непонятно, почему один участник должен содержать в себе модель другого.
Наконец адекватное сравнение. Электронный склад таки является моделью реального (касательно остатков и цен прихода). В отличие от твоего примера выключателя и лампочки. Другое дело, что модель склада может являться составной частью модели более высокого уровня — модели организации работы фирмы, в которой синхронизация реально происходящего на складе с вводимыми в учетную программу данными будет являться одним из бизнес шагов. Ну дык это и правильно, если моделирование в электронном виде не будет соответствовать реально происходящему, то нафиг оно вообще нужно.
S>Торговля идёт относительно того, насколько часто приходится моделировать в программистской деятельности. О применимости ООП для этого торговля идёт уже во вторую очередь.
Да всегда приходится. Я еще не видел примера, относительно ПО, чтобы оно не являлось моделью чего-либо.
V>>Ну дык, почему нет? В чистом ФП при численном интегрировании мы бы получали иммутабельные "сшапшоты" динамического процесса, в ООП мы эти же наборы чисел храним явным образом в тех же самых ячейках памяти, что и на предыдущем шаге, вот и все отличие. S>Ну как же — вы очень упрощаете ООП. Какие ещё ячейки памяти? ООП расположено на значительно более высоком уровне абстракции.
Нет, "само по себе" ничего не расположено. В ООП мы напрямую ручками размечаем поля, где будем хранить данные в памяти объекта. Даже если речь о полях ссылочного типа, то значит ссылки и храним, ссылки — тоже данные. Абстракция тут — это лишь публичный интерфейс объекта и нигде больше. Сами же объекты не из воздуха берутся, их кто-то программирует, именно в терминах ячеек памяти и операций над ними.
Хотя, некоторые языки умеют делать автосвойства, но это фактически одно и то же, и нужно лишь для обхода ограничений, наложенных платформой, например для работы биндинга и всего остального, завязанного на PropertyDescriptor/PropertyInfo.
S>Вполне возможно, что ФП-компилятор решит повторно использовать те же ячейки памяти, поскольку иммутабельность — это свойство исходной программы, а не ячейки памяти.
Теоретически сия возможность есть, фактически ФП компиляторы на сегодня не умеют оптимизировать толком. В дотнете, например, основной тормоз для числобробилок — это время доступа к элементам массивов. И, хотя теоретически лишние проверки доступа можно исключить в очень большом кол-ве сценариев, фактически реализован всего один сценарий. Поэтому дотнет до сих пор сосет и причмокивает, хотя уже 9 лет как.
S>В принципе, я могу поверить, хотя и с оговорками, в то, что для моделирования моста удобно будет применять ООП-шные объекты, которые соответствуют его деталям. S>А вот для моделирования работы датчика скорости потока на эффекте Холла вы какие объекты собираетесь описывать? Вода, МагнитноеПоле, Датчик?
Мы же уже договорились, что для разных моделей есть разные парадигмы.
V>>Выключатель — это часть цепи. Осуществляет замыкание/размыкание в этой модели и имеет вполне определенные состояния. Заметь, лампочка и источник напряжения не имеют состояния, они являются чистыми ф-иями (если не учитывать нагрев спирали), но выключатель — имеет. Соотв, для модели такой цепи нужен один регистр памяти и пара ф-ий. S>Нам не нужна модель цепи. Выключатель прекрасно работает безо всякой модели. Это была аналогия.
Это была натяжка. Я вообще плохо понимаю попытки выдать одни элементы модели за другие. Модель цепи нам нужна хотя бы на бумаге или в голове, чтобы проверить, подходит ли данный выключатель, лампочка и т.д. в эту цепь. ИМХО, электроника — это самая идеальная область для моделирования, и она фактически вся на кончике карандаша была выведена. По состоянию на сегодня, любые более-менее сложные электронные компоненты разрабатываются исключительно через программное моделирование. Т.е. опытные образцы делают только тогда, когда программная модель является уже довольно-таки "вылизанной".
S>Вот у нас стоит задача управления освещением в комнате. С этим справляется выключатель. В нём, очевидно, модели лампочки нет. Можете на досуге разобрать выключатель и поискать там модель лампочки.
Да, модели лампочки в выключателе нет... говоришь, нет бардака?
В проводах ее тоже нет, что характерно. И в розетке.
S>Далее, переходим к более сложной задаче — управление яркостью света. Появляется диммер. Он устроен сложнее, чем выключатель, но модели лампочки в нём по-прежнему нет. S>Теперь сделаем управление яркостью света с обратной связью — чтобы ночью свет автоматически включался, а днём выключался. В цепи появятся фотоэлементы, и прочая электроника. Способов решить эту задачу существенно больше, но и в них никакой модели лампочки и окружающей среды по прежнему нет. Есть модель некоего устройства "управляющий элемент".
Скажу честно, мне сложно пока воспроизвести в своем воображении последовательность рассуждений, приведшей к необходимости искать модель одного элемента более общей модели в другой. Я уже пытался тебе напомнить, что участники некоей модели взаимодействуют по неким интерфейсам. Но с чего ты упорно пытаешься спросить — являются ли они моделью друг-друга? Мой ответ: зачем?
S>Если мы захотим усложнять задачу, мы рано или поздно заколебаемся и перейдём в цифровой мир, в котором есть абстрактная железка "микроконтроллер", которая управляет чем угодно. И есть программная часть решения задачи. Так вот — совершенно непонятно, зачем в этот момент внезапно в программной части решения возникнет какая-то модель задачи, которая до сих пор была не нужна.
Модель была нужна с самого начала. Это — схема цепи. Эту же модель можно перенести в цифровую область без проблем. Одноконтурной электронной цепи с пассивными элементами будет соответствовать линейное тело программы. Само это тело можно будет запускать с некоей периодичностью. Чем выше периодичность, тем меньше будет время срабатывания схемы, управляемой контроллером.
S>Но только объекта "лампочка" там, скорее всего, не будет. Вот программный аналог объекта "выключатель" там запросто может оказаться — тот самый регистр.
Дык, я уже делал замечание, что лампочка это объект без собственного состояния. То бишь, если у нас в модели есть объект — регулятор напряжения, то состояние лампочки от него зависит функционально, то бишь не требует оформления в виде отдельного объекта.
S>А тем временем укушенные ООП люди на полном серъёзе предлагают писать программу, в которой будут объекты Лампочка и Фотодатчик.
Скорее наоборот, не понимающие, что есть ООП. Нет состояния — нет ООП. Датчик, кстати, имеет объективное состояние, которое мы с некоей периодичностью опрашиваем.
V>>Все становится интересней, если в цепи есть активные элементы: емкости и индуктивности. Во временной области они имеют вполне четкое мнгновенное состояние, т.е. при моделировании работы такой цепи путем численного интегрирования нам опять же удобно где-то хранить текущие мгновенные значения токов и напряжений. В операторной области, что характерно, активные элементы представлены опять же чистыми ф-ями. Но это же совсем другая модель, не имеющая состояния, а имеющая только однократно устанавливаемые параметры. И для этой другой модели вполне удобно использовать то же ФП. S>Вы всё время путаете задачу и решение. Задача была — управлять лампочкой. Не смоделировать лампочку, а управлять ей. Если вам вдруг потребовалась модель электрической цепи, значит задача у вас была в чём-то другом. Например, рассчитать параметры цепи, для того, чтобы подготовить документацию для продукта "электрический звонок" или "аналоговая сигнализация".
V>>Я вообще предмета спора не понимаю. Если нам удобно обслуживаемую компьютером целевую автоматизацию чего-либо представить в виде модели, участники которой имеют состояние, то самое удобное на сегодня — это ООП. S>Совершенно верно. Только эта модель будет, грубо говоря, моделью идеального устройства, решающего целевую задачу.
Да нет, не идеального. С большим кол-вом допущений, вплоть до погрешности вычислений из-за ограниченной разрядности вещественных чисел.
S>А не моделью объектов, из которых состоит предметная область.
А это уже зависит от выбранного решения и проведенных предварительно "сокращений общих частей ураневний". Бери для примера LL(k) парсер. Никто же, право, не делает k предпросмотров вперед в реальных парсерах, хотя именно так описывается модель его поведения. Вместо этого строится k-мерная таблица, и по каждому входному терминалу осуществляется непосредственный переход под этой таблице. Т.е. да, зачастую мы программируем не исходную модель, а её оптимизированный вариант. То же самое насчет лексических анализаторов. Там же когда минимизируешь состояния, а потом минимизируешь мн-во входов, то таблица переходов получается на 2 (!!!) порядка меньше обычно. И вроде бы с исходной грамматикой никакой связи, а работает эквивалентно. И вовсе не чудеса.
S>Именно поэтому в реальных программах полно объектов типа Window, Control, Connection, и прочих, которые никакого отношения к предметной области не имеют.
И что с того? Мы же должны как-то организовать ввод/вывод данных в нашу модель? Если модель не требует взаимодействия с человеком, то ей и Window не нужен.
S>Что очень сильно отличается от того, что преподают на курсах "ООП за 21 день".
Любые курсы на 21 день — разводняк. ООП тут не при чем.
Re[48]: Почему объектно-ориентированное программирование про
Здравствуйте, samius, Вы писали:
S>Но позвольте, во-первых в том определении ничего нет про эквивалентность и раздельное поведение. std::vector<int> обладает value-семантикой по тому определению (включая уточнение о том что это значит в C++). Т.е. некто рассматривает std::vector<int> как одиночное значение. Что мешает рассматривать как одиночное значение List<int>? Именно уточнение, которого говорит что при присваивании должна создаваться копия, а не алиас.
Уточнение, что не должен создаваться алиас. Копия создаваться не обязана — до тех пор, пока я не пытаюсь выполнить модификацию, копия и алиас ведут себя одинаково.
S>В этом примере вы смещаете акценты... Строкой вы здесь считаете не сам экземпляр System.String, а ссылку на него.
С точки зрения пользователя нет никакого "экземпляра" string. Есть исключительно ссылки. Вот вы интом считаете само число или переменную?
S>Я соглашусь со следующей формулировкой: Строка в дотнете формально соответствует reference-семантике, хотя и обладает чертами поведения value. Т.е. alias в смысле еще одного "имени" того же экземпляра таки создается, но изменить состояние экземпляра через этот alias не удастся, потому его "можно считать" копией. S>Да, в таком аспекте я готов обобщить утвреждение до иммутабельных объектов.
S>>Как я показал выше, вы ошибаетесь. S>Не готов с этим согласиться. Она обладает чертами value-типа в том плане что ее нельзя изменить через alias. Но формально все-же reference.
Вы слишком много внимания уделяете низкоуровневой реализации. Чисто между нами: строки в дотнете всё-таки mutable.
Но зачем на этом фокусироваться? Весь дотнет построен на предположениях об иммутабельности строки, и использование строк в этом стиле максимально облегчено.
То, что вы можете сделать ReferenceEquals для строк и отличить какие две из трёх переменных, содержащих Hello, показывают на физически один и тот же набор байт — такая же малоинтересная подробность.
Малоинтересная она потому, что ей можно пренебречь. Всё, чего вы хотите сделать со строками, работает без ReferenceEquals и затачивания под identity. Вместо неё имеется эквивалентность состояния и ссылочная прозрачность. Именно благодаря ссылочной прозрачности не нужно физически копировать строку всякий раз, как мы встречаем оператор присванивания.
Поэтому то, что строка реализована при помощи reference-типа, не мешает ей наслаждаться value-семантикой.
S>Даже если смысла нет, но раз мы можем послать сообщение конкретному, значит идентичность есть. И вот еще над чем интересно подумать: можем ли мы послать сообщение не какому-то конкретному объекту? Пусть даже сообщение посылается с предикатом, через границы домена, или еще как... Но получить-то его может только конкертный объект, если не говорить об экзотике вроде ((Foo*)rnd())->Bar();
Ну, вот к примеру в реляционной алгебре нет "встроенной" возможности "отправить сообщение" конкретной строке.
Чтобы это сделать, приходится изобретать primary key.
Некоторым аналогом этой математики является linq — можно отправлять сообщения, не упоминая конкретные объекты. S>Какие есть другие причины что бы не считать value объектами?
Других вроде бы нет.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[49]: Почему объектно-ориентированное программирование про
Здравствуйте, Sinclair, Вы писали:
S>Здравствуйте, samius, Вы писали:
S>>Но позвольте, во-первых в том определении ничего нет про эквивалентность и раздельное поведение. std::vector<int> обладает value-семантикой по тому определению (включая уточнение о том что это значит в C++). Т.е. некто рассматривает std::vector<int> как одиночное значение. Что мешает рассматривать как одиночное значение List<int>? Именно уточнение, которого говорит что при присваивании должна создаваться копия, а не алиас. S>Уточнение, что не должен создаваться алиас. Копия создаваться не обязана — до тех пор, пока я не пытаюсь выполнить модификацию, копия и алиас ведут себя одинаково.
Пусть так. Т.е. это отличие делает std::vector<int> значением, а List<int> — объектом?
S>>В этом примере вы смещаете акценты... Строкой вы здесь считаете не сам экземпляр System.String, а ссылку на него. S>С точки зрения пользователя нет никакого "экземпляра" string. Есть исключительно ссылки. Вот вы интом считаете само число или переменную?
Преимущественно сам тип, но в зависимости от контекста и переменную и значение. В случае со строкой — под строкой я подразумеваю сам экземпляр. Переменная для меня — ссылка.
Хорошо, посмотрим с такого ракурса на std::vector<int>. Как мы вроде бы определились ранее, это значение. Но когда у нас переменная типа указатель на вектор (vector<int>*), то для пользователя нет никакого "экземпляра", есть только указатель. А он ведет себя в соответствии с reference-семантикой. Значит ли это что vector<int> стал объектом, будучи значением?
S>>>Как я показал выше, вы ошибаетесь. S>>Не готов с этим согласиться. Она обладает чертами value-типа в том плане что ее нельзя изменить через alias. Но формально все-же reference. S>Вы слишком много внимания уделяете низкоуровневой реализации. Чисто между нами: строки в дотнете всё-таки mutable.
Это не суть важно. S>... S>Поэтому то, что строка реализована при помощи reference-типа, не мешает ей наслаждаться value-семантикой.
Хорошо, оставим это. Не суть важно, ведет себя как value, или обладает чертами.
S>>Даже если смысла нет, но раз мы можем послать сообщение конкретному, значит идентичность есть. И вот еще над чем интересно подумать: можем ли мы послать сообщение не какому-то конкретному объекту? Пусть даже сообщение посылается с предикатом, через границы домена, или еще как... Но получить-то его может только конкертный объект, если не говорить об экзотике вроде ((Foo*)rnd())->Bar(); S>Ну, вот к примеру в реляционной алгебре нет "встроенной" возможности "отправить сообщение" конкретной строке. S>Чтобы это сделать, приходится изобретать primary key.
+1 S>Некоторым аналогом этой математики является linq — можно отправлять сообщения, не упоминая конкретные объекты.
Отправлять можем. Но получить сообщение может только конкретный объект при непосредственной посылке конкретно ему (пусть где-то в реализации linq-а).
Re[50]: Почему объектно-ориентированное программирование про
Здравствуйте, samius, Вы писали:
S>Пусть так. Т.е. это отличие делает std::vector<int> значением, а List<int> — объектом?
Я, если честно, не помню деталей контракта std::vector<int>. Он иммутабелен? При его копировании создаётся полная копия?
S>Хорошо, посмотрим с такого ракурса на std::vector<int>. Как мы вроде бы определились ранее, это значение. Но когда у нас переменная типа указатель на вектор (vector<int>*), то для пользователя нет никакого "экземпляра", есть только указатель. А он ведет себя в соответствии с reference-семантикой. Значит ли это что vector<int> стал объектом, будучи значением?
Ну, если vector<int> сам по себе не имеет идентити, то получение указателя на него эквивалентно боксингу в дотнете — когда мы искусственно порождаем объект, хранящий внутри себя значение.
S>Хорошо, оставим это. Не суть важно, ведет себя как value, или обладает чертами.
Согласен.
S>Отправлять можем. Но получить сообщение может только конкретный объект при непосредственной посылке конкретно ему (пусть где-то в реализации linq-а).
Ну, это опять начинаются проблемы выбора степени детализации. Если мы копнём слишком глубоко, то увидим ту же память, регистры, и команды процессора.
Если копнуть в "середину" linq, то там везде сплошные вызовы — т.е. посылки сообщений. Как правило — объектам.
А если опять же глянуть в "смысл" того, что происходит, то может оказаться, что никаких объектов нет.
И можно заставить линк работать без объектов.
Есть, скажем, статический класс, на котором вызывается статический метод, в который передаётся ссылка на value-тип, который служит исключительно маркером, и передаётся предикат. Статический метод применяет предикат к совершенно необъектным данным, и получает некоторый результат, который по-прежнему не обязан быть объектом.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[51]: Почему объектно-ориентированное программирование про
Здравствуйте, Sinclair, Вы писали:
S>Здравствуйте, samius, Вы писали:
S>>Пусть так. Т.е. это отличие делает std::vector<int> значением, а List<int> — объектом? S>Я, если честно, не помню деталей контракта std::vector<int>. Он иммутабелен? При его копировании создаётся полная копия?
нет, не иммутабелен. При копировании копируется вместе с содержимым.
S>>Хорошо, посмотрим с такого ракурса на std::vector<int>. Как мы вроде бы определились ранее, это значение. Но когда у нас переменная типа указатель на вектор (vector<int>*), то для пользователя нет никакого "экземпляра", есть только указатель. А он ведет себя в соответствии с reference-семантикой. Значит ли это что vector<int> стал объектом, будучи значением? S>Ну, если vector<int> сам по себе не имеет идентити, то получение указателя на него эквивалентно боксингу в дотнете — когда мы искусственно порождаем объект, хранящий внутри себя значение.
Мы договорились что иммутабельные объекты не имеют практического смысла identity, про мутабельные речи не было.
Во всяком случае идентичность в следующем коде смысл имеет:
std::vector<int> a = std::vector<int>();
a.push_back(0);
std::vector<int> b = a; // копирует вместе с содержимым.
cout << (a == b); // true
a.push_back(1);
cout << (a == b); // false
Нет, боксингу это не эквивалентно, т.к. значение в боксе изменить нельзя, а значение по указателю — можно:
std::vector<int> *p = &a;
p->push_back(2);
В случае с указателем он ведет себя адекватно List<int>.
Все это я к тому, что один и тот же тип vector<int> ведет себя в соответствии с определением value-семантики при оперировании значениями, и в соответствии с reference-семантикой при оперировании через ссылки, указатели. Т.е. по вашему он в одном случае значение, а в другом — объект?
S>>Хорошо, оставим это. Не суть важно, ведет себя как value, или обладает чертами. S>Согласен.
Важно почему value не объект
S>>Отправлять можем. Но получить сообщение может только конкретный объект при непосредственной посылке конкретно ему (пусть где-то в реализации linq-а). S>Ну, это опять начинаются проблемы выбора степени детализации. Если мы копнём слишком глубоко, то увидим ту же память, регистры, и команды процессора. S>Если копнуть в "середину" linq, то там везде сплошные вызовы — т.е. посылки сообщений. Как правило — объектам.
S>А если опять же глянуть в "смысл" того, что происходит, то может оказаться, что никаких объектов нет.
S>И можно заставить линк работать без объектов. S>Есть, скажем, статический класс, на котором вызывается статический метод, в который передаётся ссылка на value-тип, который служит исключительно маркером, и передаётся предикат. Статический метод применяет предикат к совершенно необъектным данным, и получает некоторый результат, который по-прежнему не обязан быть объектом.
Замнем тему про посылки, т.к. возможность посылки сообщения в широком смысле (маркерам) не является признаком объекта.
Re[52]: Почему объектно-ориентированное программирование про
Здравствуйте, samius, Вы писали: S>Мы договорились что иммутабельные объекты не имеют практического смысла identity, про мутабельные речи не было. S>Во всяком случае идентичность в следующем коде смысл имеет: S>
S>std::vector<int> a = std::vector<int>();
S>a.push_back(0);
S>std::vector<int> b = a; // копирует вместе с содержимым.
S>cout << (a == b); // true
S>a.push_back(1);
S>cout << (a == b); // false
S>
Как раз здесь никакой идентичности нет. То, что копия выполняется в момент присваивания — это всего лишь неэффективная реализация. Строка в дотнете ведёт себя точно таким же образом, но "копия" создаётся только в момент попытки модификации.
S>Нет, боксингу это не эквивалентно, т.к. значение в боксе изменить нельзя, а значение по указателю — можно: S>
S>std::vector<int> *p = &a;
p->>push_back(2);
S>
S>В случае с указателем он ведет себя адекватно List<int>.
Ага. Адекватно. Да, это всё-таки нифига не боксинг. S>Все это я к тому, что один и тот же тип vector<int> ведет себя в соответствии с определением value-семантики при оперировании значениями, и в соответствии с reference-семантикой при оперировании через ссылки, указатели. Т.е. по вашему он в одном случае значение, а в другом — объект?
Вынужден признать что да, таки ведёт себя по-разному. Значит, я что-то не так понимаю в теории. Либо мы имеем дело с особенно злостным коварством системы типов С++.
S>>>Хорошо, оставим это. Не суть важно, ведет себя как value, или обладает чертами. S>>Согласен. S>Важно почему value не объект
S>>>Отправлять можем. Но получить сообщение может только конкретный объект при непосредственной посылке конкретно ему (пусть где-то в реализации linq-а). S>>Ну, это опять начинаются проблемы выбора степени детализации. Если мы копнём слишком глубоко, то увидим ту же память, регистры, и команды процессора. S>>Если копнуть в "середину" linq, то там везде сплошные вызовы — т.е. посылки сообщений. Как правило — объектам.
S>>А если опять же глянуть в "смысл" того, что происходит, то может оказаться, что никаких объектов нет.
S>>И можно заставить линк работать без объектов. S>>Есть, скажем, статический класс, на котором вызывается статический метод, в который передаётся ссылка на value-тип, который служит исключительно маркером, и передаётся предикат. Статический метод применяет предикат к совершенно необъектным данным, и получает некоторый результат, который по-прежнему не обязан быть объектом. S>Замнем тему про посылки, т.к. возможность посылки сообщения в широком смысле (маркерам) не является признаком объекта.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[53]: Почему объектно-ориентированное программирование про
S>>a.push_back(1);
S>>cout << (a == b); // false
S>>
S>Как раз здесь никакой идентичности нет. То, что копия выполняется в момент присваивания — это всего лишь неэффективная реализация. Строка в дотнете ведёт себя точно таким же образом, но "копия" создаётся только в момент попытки модификации.
Согласно некоторым источникам, идентичность, основанная на состоянии, называется value identity, или internal identity (http://c2.com/cgi/wiki?ObjectIdentity, http://today.java.net/pub/a/today/2006/07/27/defining-object-identity.html).
Но я не совсем верно классифицировал vector как value-object. Для value-object-а недостаточно value-семантики, требуется еще и иммутабельность (согласно тем же источникам).
Наткнулся еще на любопытную книгу, полагаю что она будет интересна и vdimas-у тоже. Обсуждаемые вопросы в ней затронуты (и Identity и Value).
S>>Все это я к тому, что один и тот же тип vector<int> ведет себя в соответствии с определением value-семантики при оперировании значениями, и в соответствии с reference-семантикой при оперировании через ссылки, указатели. Т.е. по вашему он в одном случае значение, а в другом — объект? S>Вынужден признать что да, таки ведёт себя по-разному. Значит, я что-то не так понимаю в теории. Либо мы имеем дело с особенно злостным коварством системы типов С++.
Да, в C++ с любой сущностью можно обращаться как с value и как с reference (если не запрещены соответствующие конструкторы и операторы). Потому проще считать что поведение объекта неизменно, а разница в том, как именно мы с объектом работаем, подразумевая под объектом саму его тушку, а не переменную.
Re[43]: Почему объектно-ориентированное программирование про
Здравствуйте, Sinclair, Вы писали:
S>Вообще, в программировании сейчас наблюдается значительный разрыв между теорией и практикой. Я не знаю, почему он происходит, но выглядит всё просто ужасно. Детям сначала рассказывают про высокое, а потом они приходят работать, а там ужосчто. И про этот ужосчто никаких вменяемых книг уже нету, приходится дотумкивать своим умом. Не всегда успешно. Тем более, что существуют упорно тиражируемые заблуждения, которые только отвлекают от сути вещей. Я уже упоминал про эпический спор об уровнях изоляции в РСУБД? Мне даже ссылки на Бернстайна приводили. Вот только оппа в том, что Бернстайн ни в одном месте про уровни изоляции явно не пишет. Как будто их нет. А они — есть. И вот люди начинают изобретать такие объяснения этим уровням изоляции, что шуба заворачивается. Включая искреннюю веру в то, что не все шедулеры транзакций обязаны обеспечивать сериализуемость. S>И вот с ООП — то же самое.
Помнится два года назад я тебе тож самое и говорил, а ты мне талдычил что де твой тесть ездит по вузам по всему миру и утвержает что так везде в инженерных вузах и это, дескать, нормально
Реально отрыв теории от практики происходил всегда и везде — и решалось это во все времена разделением труда и введением более узкой специализации в обучении, потому что в какой то момент специалистов на все руки перестало хватать.
Сейчас в IT идет ровно тоже самое, только в силу того, что прогресс за 20 лет шагнул дальше, чем за последние 100 лет (!!! именно так !!!), разницу в образовании очень сложно закрыть. А вузы и школы тупо пытаются заменить нехватку практики теоретическими знаниями.
Собственно это нормально — прогресс "сейчас" всегда идет быстрее чем прогресс "чуть раньше".
Re: Почему объектно-ориентированное программирование провали
ИС>Авторы: ИС> Игорь САВЧУК
ИС>Аннотация: ИС>Среди множества идей, которые звучат красиво скорее в теории, чем на практике, объектно-ориентированное программирование занимает особое место. Попробуем разобраться и ответить на главный вопрос, почему всё же объектно-ориентированное программирование провалилось?
Ричард Гэбриел неожиданно сравнивает нынешнюю ситуацию с ООП с провалом эфиродинамики в физике начала 20 век..."тихая революция"
Интересно, цитирует ли РГ Томаса Куна и его "Структуру научных революций"? Впрочем, если бы он читал эту очень известную книгу, в которой описано, как происходят научные революции, он бы знал такие вещи: "научная революция" — это вполне уже известное понятие, которым никого особо не удивишь... имеется в виду смена научной парадигмы с использованием в том числе и "административного ресурса", Кун, правда, считал, что такое происходит, когда прежняя парадигма изживает себя. Но изживает она себя для чего? Она больше неспособна давать решения для проблем-головоломок. Именно проблемы-головоломки, внутренаучные, в основном интересуют учёных, а не их применение в практической жизни. Конечно, это точка зрения, близкая к крайней, но это известный философский тезис, который не так просто опровергнуть. А Гэбриел так просто аппелирует к практической значимости науки: "Ну и где мы теперь, с этой вашей красивой теорией относительности, кто-нибудь может мне назвать хоть какие-то реально-практические результаты её применения в вашей обыденной жизни..." Хотя бы предложил какие-нибудь практические приложения эфира в "обыденной жизни", не достижимые с помощью ТО.
Вторая проблема с этим примером более серьёзная. Что значит вводить эфир, не меняя структуру теории в целом? А не означает ли это онтологическую инфляцию? Мы вводим новый объект, в котором инкапсулируются некоторые свойства и состояния (пока ещё до конца неизвестные). Свойства эти будут уточняться, но "каркас" теории не изменится. Либо же мы "перепишем" теорию — получится другая с другим "каркасом"? Тут ещё одна философская тема проскальзывает, а именно недоопределённость теории опытом, но не будем углубляться в этом направлении. Скажем лишь, что старый "каркас" можно было бы подстроить под новые эмпирические данные. А не встречаются ли знакомые для программистов слова, в том что я сейчас написал? А не предлагает ли Гэбриел повторного использования старой теории с эфиром, заюзав ООП-фичи?
Кстати, в науке такое "повторное использование" не очень приветствуется — нужна фальсифицируемость. А вот при построении практических систем это часто нужно...
To be is to be the value of a variable
Re[2]: Почему объектно-ориентированное программирование пров
Здравствуйте, wvoquine, Вы писали:
W>Хотя бы предложил какие-нибудь практические приложения эфира в "обыденной жизни", не достижимые с помощью ТО.
Теория Максвелла, например. Когда из под этой теории выдернули эфир, она превратилась в пустую и непонятную абстракцию, т.к. представить, к примеру, вихрь в пустоте мягко говоря непросто. Собственно все научные теории до начала 20 века базировались на концепции эфира. А на практике в основном теории 19 века и используются.
Re[5]: Почему объектно-ориентированное программирование пров
Здравствуйте, SV., Вы писали:
SV.>Что делали оверхайперы? Одни засирали эту простую и понятную схему тысячами типов-терминаторов (воробьи — воробьиноклювые — воробьинообразные — ... — серокрылые — птицевидные — ... — зерноядные — ... — летающие динозавры) до полной нечитаемости. Другие засирали эту простую и понятную схему неумеренной детализацией ("воробей" состоит из костей 100 видов, примерно 1.314 костей каждого вида, тканей 100 видов, а расфазовка отдельного "маха" приведена на той же схеме) до полной нечитаемости. Третьи, совсем никчемные, выводили бескрылых воробьев, оброщенных мехом, и получали таким образом белку-летягу (хороший пример из жизни — если повар наш не врет — можно найти тут: http://burrarum.livejournal.com/32707.html).
SV.>Грамотная декомпозиция на значимые сущности должна быть переложена на ЯП без изменений, с сохранением всех отношений, в т.ч. наследования реализаций.
отличная биллетристика сложилась
автор! мне вспомнился на это всё эссе — мультик "надо-в-дорогу, надо-в дорогу нам то-ро-пится, надо узнать, надо узнать — что я за птица.. ну и так далее ко-ко-ко-ро-ко-ко"
и конкретно по классам — не все что летает — птицы, не всё что несёт яички — птицы, только что имеет пёрышки — птицы
Re[2]: Почему объектно-ориентированное программирование пров
Здравствуйте, Donz, Вы писали:
D>Здравствуйте, Игорь САВЧУК, Вы писали:
D>По-моему, это все же сарказм. Одно упоминание эфиродинамики и ненужности ТО чего стоит. D>Или у автора совсем все плохо.
очередной высер в сторону Анри Пуанкаре или просто поклонни культового Альберта? а ты то готов высказать различие в действии эфиродинамики (световой эфир) и тёмной материи на модель вращения звезд в рукавах спиральных галлактик к примеру?
Re[4]: Почему объектно-ориентированное программирование пров
Здравствуйте, Donz, Вы писали:
D>Здравствуйте, mister-AK, Вы писали:
D>>>По-моему, это все же сарказм. Одно упоминание эфиродинамики и ненужности ТО чего стоит. D>>>Или у автора совсем все плохо. MA>>очередной высер в сторону Анри Пуанкаре или просто поклонни культового Альберта? а ты то готов высказать различие в действии эфиродинамики (световой эфир) и тёмной материи на модель вращения звезд в рукавах спиральных галлактик к примеру?
D>Я то не готов. Но у меня хватает мозгов понять, что для опровержения общепринятой фундаментальной теории
общепринятой кем, простит узнать хотелось бы?
D>культ автора.
хрен с ним с культом то. вот усатый коба до сих пор в сердцах мильёнов
ты нам скажи по-существу, каким образовм gps соотносится с ОТО, а например не с теорией Логунова. очень бы хотедось услышать
Re[5]: Почему объектно-ориентированное программирование пров
Здравствуйте, mister-AK, Вы писали:
MA>хрен с ним с культом то. вот усатый коба до сих пор в сердцах мильёнов MA>ты нам скажи по-существу, каким образовм gps соотносится с ОТО, а например не с теорией Логунова. очень бы хотедось услышать
Насколько я знаю РТГ Логунова на данный момент не имеет никаких значимых подтвержденных экспериментально расхождений с ОТО и
поэтому по принципу приоритета идет лесом.
Re[5]: Почему объектно-ориентированное программирование пров
Здравствуйте, mister-AK, Вы писали:
D>>Я то не готов. Но у меня хватает мозгов понять, что для опровержения общепринятой фундаментальной теории MA>общепринятой кем, простит узнать хотелось бы?
Как минимум авторами учебников для школ и ВУЗов.
D>>культ автора. MA>хрен с ним с культом то. вот усатый коба до сих пор в сердцах мильёнов MA>ты нам скажи по-существу, каким образовм gps соотносится с ОТО, а например не с теорией Логунова. очень бы хотедось услышать
Ты о чем? Причем тут GPS? Кому нам?
Любителям альтернативных теорий надо завязывать с альтернативными веществами для альтернативного сознания.