Здравствуйте, 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[9]: Почему объектно-ориентированное программирование пров
DG>>но значит у тебя модель другого мира. модель проекта, например. G> G>Ты всегда сводишь к абсурду. У тебя получается что объект — модель какого-то "мира".
объект — это слово(понятие) модели обычно.
DG>наследовать реализацию обычно проще, чем писать ее заново. G>Есть другие способы повторного использования кода.
например?
DG> стати практика показывает обратное, если мы на этапе проектирования будет модели 1-в-1 перекладывать в структуры классов то получится *опа.
значит не надо так делать.
Re[9]: Почему объектно-ориентированное программирование пров
Здравствуйте, 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[10]: Почему объектно-ориентированное программирование про
DG>>>но значит у тебя модель другого мира. модель проекта, например. G>> G>>Ты всегда сводишь к абсурду. У тебя получается что объект — модель какого-то "мира".
DG>объект — это слово(понятие) модели обычно.
А мы вообще-то говорим про объекты и классы в ОО-языках.
DG>>наследовать реализацию обычно проще, чем писать ее заново. G>>Есть другие способы повторного использования кода. DG>например?
Композиция.
Re[11]: Почему объектно-ориентированное программирование про
Здравствуйте, 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[12]: Почему объектно-ориентированное программирование про
Здравствуйте, DarkGray, Вы писали:
DG>>>>наследовать реализацию обычно проще, чем писать ее заново. G>>>>Есть другие способы повторного использования кода. DG>>>например? G>>Композиция.
DG>и чем наследование реализации отличается от композиции кроме названия?
Наследование реализации создает отношение is-a (кроме приватного наследования в C++), тогда как композиция не создает.
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[13]: Почему объектно-ориентированное программирование про
G>Наследование реализации создает отношение is-a (кроме приватного наследования в C++), тогда как композиция не создает.
это есть часто повторяемое заблуждение.
если брать пару: круг и эллипс, то можно для круга наследовать реализацию от эллипса и "открутить лишнее", а можно
для эллипса наследовать реализацию от круга и "прикрутить дополнение".
и оба подхода будет верными в том, или ином контексте.
проблема начинается, когда люди начинают считать, что наследуя реализацию — они при этом автоматически получают наследование внешнего контракта, а также что получили отношение is-a.
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[15]: Почему объектно-ориентированное программирование про
G>Оба они почти наверняка будут нарушать LSP. Есть реальный пример обратного — приводи.
если учесть, что круг и эллипс состоят в отношениях нарушающих принцип Лискова (в обе стороны), то это нормально.
зы
если брать полный контракт эллипса, то круг вместо него нельзя использовать (т.к. он, например, не имеет двух фокусов)
а эллипс нельзя использовать вместо круга.
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[13]: Почему объектно-ориентированное программирование про
Здравствуйте, gandjustas, Вы писали:
G>Ты рассматриваешь проектирование классов не знаю какие задачи на них возлагаются. так нельзя делать, ничего хорошего их этого не выйдет. G>А правильные задачи класса можно получить декомпозиции общей задачи. G>Это и называется проектирование "сверху вниз", которое многие адепты ООП как раз и не любят, потому что в итоге оно не дает нам модели объектов реального мира.
Вот это пропустил. А зря. Как говорил наш преподаватель математики, ЧТД. Человек, которому попадет в руки ваш код, должен будет разбираться с особенностями вашей индивидуальной "декомпозиции общей задачи", вашего понимания общей задачи, и со всеми вашими тараканами. Человек, которому попадет в руки ООП-код с моделью, будет одновременно изучать и предметную область. Если он знает предметную область, то на понимание кода ему вообще не понадобятся усилия.
И опять у меня нет выхода, кроме как процитировать себя:
Моя цель, извините, это код, который проще писать, читать и понимать, и с гарантированным уничтожением риска противоречий (если какие-то отношения непротиворечивы в природе, значит в модели они тоже будут такими же).