- 1
Про убогость ООП подхода.
Нашли или выдавили из себя код, который нельзя назвать нормальным, на который без улыбки не взглянешь? Не торопитесь его удалять или рефакторить, — запостите его на говнокод.ру, посмеёмся вместе!
−7
Про убогость ООП подхода.
Итак, вот допустим наследование. Есть всякие там тупые примеры ООП, типа "котик и собачка наследуется от четырехногих" и проч., где подобный бред вполне работает. Но давайте попробуем рассмотреть более интересные ситуации.
Допустим что мы пишем некую игру. В игре есть некое оружие, например там есть огнестрел и дубинки. И мы делаем ружье, которое одновременно и огнестрел и дубинка, т.е. ружьем можно и как палкой уебать, и пальнуть как из револьвера. У родительского класса "огнестрел" есть свойства, типа дальности выстрела, точности, используемых боеприпасов, уровень прочности(износ), вес, наносимый урон при попадании. У дубинки есть свойства длины дубинки, уровень прочности(износ), вес, наносимый урон при ударе. Вес для ружья нам нужен только один, т.е. нет смысла делать два "веса" одному предмету. И огнестрел и дубинка наследуется от родительского класса "объект инвентаря", в общем тут ромбовидное наследование, которое в разных языках решается разными способами. Ну ок, допустим что мы там каким-то образом указали компилятору некоего языка X, что наследовать свойство "вес" надо лишь один единственный раз, как и прочие хрени, которые являются общими для родительского класса "объект инвентаря". Теперь надо решить с прочностью. Не все "объекты инвентаря" в этой игре имеют свойство прочности, есть например какие-то расходные материалы, типа патронов, для которых понятие прочности неприменимо. Использование ружья как дубинки изнашивает его не таким же самым образом, как использование ружья как огнестрела, но при этом слишком большой износ ружья-как-дубинки может настолько повредить его, что как огнестрел его уже и не поиспользовать из-за погнутого ствола. Но использование ружья как огнестрел никак на износ ружья-как-дубинки не влияет, типа это механический износ спускового механизма, износ ствола при стрельбе...
Короче, если мы хотим от этих двух говен унаследоваться так, как надо по такому вот хитровыебаному условию, надо иметь некий способ чтобы указать то, как правильно эти хрени накладывать, какие общие свойства двух родительских классов будут сведены к одному, какие будут дублироваться (типа "прочность как огнестрела" и "прочность как дубины") и их взаимное влияние(т.е. если ружье сильно раздолбать как дубинку, стрелять из него тупо нельзя).
https://ru.wikipedia.org/wiki/Ромбовидное_наследование :
> Common Lisp пытается реализовать и разумное поведение по умолчанию, и возможность изменить его. По умолчанию выбирается метод с наиболее специфичными классами аргументов; затем, методы выбираются по порядку, в котором родительские классы указаны при определении подкласса. Однако программист вполне может изменить это поведение путём указания специального порядка разрешения методов или указания правила для объединения методов.
Вот что Lisp животворящий делает!
хорошее, годное ооп у смалтокообразных япов типа рубей (и немножко даже у обжсей)
ынтерфейс лишь контракт на обработку сообщений. сообщения можно отказаться принимать
# хорошее, годное ооп у смалтокообразных япов типа рубей (и немножко даже у обжсей)
ООП везде одинаковое, хоть это Smalltalk, хоть это C++, хоть это Java, отличаются только их причуды.
Или нет? Кто сможет привести убийственную фичу у Python, Ruby, Smalltalk и докажет их сильное отличие от C#, тот молодец.
Можно юзать ООП даже в языках без ооп (hint: object manager в windows executive):
Просто смалток говорит: "объекту можно послать сообщение, он может его обработать, может форварднуть дальше (делегировать), сохранить итд. Объекта можно спросить: умеет-ли он получать сообщение".
А в несмалтокообразных ЯПах вместо сообщения просто вызывают функцию, которая неявно получает указатель на объект (или явно в питоне). Это позволяет делать перегрузки, но усложняет форвардинг, и менять список поддерживаемого/неподдерживаемого сообщения в рантайме сложнее
https://stackoverflow.com/questions/1143993/what-are-the-schools-of-oop
# сообщения просто вызывают функцию
Но чем эти два подхода лучше другого?
Технически можно тоже самое сделать в java, просто это будет многобуквенно, не естественно
Вместо
будет
Обычное делегирование. Да, в жабе многобуквенней, но она никогда и не претендовала на краткость.
Толи дело Сишарпик:
void talk() => cosplay.talk();
ты всех их будешь так писать?
еще раз подчеркиваю!
"Технически можно тоже самое сделать в java, просто это будет многобуквенно, не естественно"
я, кстати, нифига не уверен что это так уж хорошо
просто показываю какую можно магию делать
а вот в obj-c типизация статическая есть, но там все равно можно спросить у объекта отвечает-ли он на message, и если да то послать
А что, так бывает?
Вот тебе еще прымер
.
В C# ты тоже так можешь сделать, но понадбится наверное рефлексия.
Понимаеш что тут происходит? когда мне шлют message на который у меня нет ответа (method missing) я просто форварджу его дальше
Тут вообще плохая архитектура, масса должна быть обычным свойством, а jump должен считать высоту на основе массы
Хуита. В руби вызов метода это все еще вызов метода, просто создатели обчитались статей с хабра о Правильном ООП и начали называть это пересылкой сообщений, потому что в их представлении именно этот факт и отделяет обычные реализации от Правильного ООП. Технически то же самое можно сделать и на жабе через прокси.
А манки патчинг и дак тайпинг это все еще манки патчинг и дак тайпинг.
Из Википедии:
К тому же использование такого подхода нарушает принцип инкапсуляции объектно-ориентированного программирования.
кресты и OOP тут ни причем. ты просто ОО еще пользоватся не научился.
> Ромбовидное_наследование
вообще тут ни причем. читай ООАиД - и учись классы из предметной областы выделять.
и если правильно научишься "классифицировать", тебе уже будет по барабану язык программирования - ОО или не ОО. потому что те же яйца вид с боку. или как классики говорили: наследование это всего лишь синтаксический подсластитель аггрегации.
ООП просто для этого НЕ ПОДХОДИТ. Оно ограничено. ООП-наследование подразумевает что у чего-то там есть родитель, и "наследник" у родителя все свойства копирует себе, но это часто не нужно. Есть четвероногие, мы наследуем псов от четвероногих. Потом у нас появляются в игре псы-мутанты с 5 ногами, мы хотим унаследовать их от обычных псов, но без унаследования четвероногости. Т.е. скопировать все что есть у псов кроме отдельных кусков, связанных с четвероногостью. Как это решается в ООП наследовании?
ночью лень тебе много писать. но еще одна - сопряженная - тема для медитации: поразмышляй на тему отношений/реляций/relationships между классами. и более конкретно над ответом на вопрос: в ОО, что такое реляция? (или: сколькими способами ее можно представить?)
Требование какой задачи я игнорирую?
Спрашиваю еще раз:
Как мне с этой ООП моделью взять из некоторого одного класса некую одну часть, из некоторого другого класса другую часть? Не унаследовать и то и то целиком, а просто взять там и там куски?
С таким подходом создатель языка и его пользователи столкнутся с кучей граблей по поводу применимости в данной ситуации этих кусков кода. В ООП это делается намного проще: создай вспомогательный класс и с помощью них реализуй нужные тебе интерфейсы.
кучи уже понаписали, а времени/мозгов у меня читать все уже нету (мля уже опять ночь).
> > Есть четвероногие, мы наследуем псов от четвероногих. Потом у нас появляются в игре псы-мутанты с 5 ногами, мы хотим унаследовать их от обычных псов, но без унаследования четвероногости.
все зависит от того *чем* 4-ре- и 5-ти- ногие собаки отличаются от друг друга - с точки зрения требований решаемой задачи.
например в графических играх они от друг друга вообще ничем отличаться не будут - кроме номера модели/текстур которыми они будут рисоватся на экране.
та же херня и относительно твоих {свойство "прочность огнестрела" и "прочность дубинки"}. вопрос не в том как словарь русского языка смотрить на эти вещи - а что с ними нужно делать. в большинстве програм которые что-то будут с ними делать все будет намного сложнее - и все в лоб будет своим отдельным классом/интерфейсом, и поверху еще будут стэки эффектов, и все будет считаться скорее всего процедурально. в добавок эти все мелочи еще будут state machine'ами потому что например игры любят это все через effect-over-time делать (т.е. эффект аттаки применяется не мнгновенно, а за, например, 0.5 секунд).
поэтому то твои жалобы на ООП выглядят весьма глупо. почему я и говорил о реляциях. классы/объекты как-то к друг другу относяться. и более того: некоторые реляции приходится описывать своим классом, потому что у реляций (тот же damage в играх) тоже могут быть свойства.
Наследование — это самая большая провокация в индустрии. Ни в каком моделировании наследования не существует (и в реальной жизни его нет тоже) — ни в электронике, ни в бухгалтерии, ни в политике, ни где бы то ни было еще. Есть лишь одна область, где наследование теоретически встречается — генеалогия (эй, парни, лучше не путать это с гинекологией). Но это не имеет ни малейшего отношения к тому, что называется наследованием в программировании. Все эти многоэтажные иерархии классов только усложняют жизнь программиста, вместо того, чтобы упрощать по своему замыслу.
Особенно порадовал нахрюк на рефакторинг: в процедурном коде-то никто ничего не рефакторит, там все сразу правильно пишут.
Запишите уже себе на лбу: наследовать нужно интерфейсы (протоколы) а не реализации.
А я всегда говорил, что наследование - говно (т.к. все пытаются наследовать реализацию, городить уёбищные иерархии и рано или поздно наступают на грабли). Самая сомнительная часть ООП.
А твоя задача даже на обычных языках вполне решается внешними хелперами, интерфейсами, агрегацией и какой-то матерью...
Разберем ООП применительно к плюсам (в других языках могут быть свои ньюансы):
Плюсовый класс это такая хрень типа структуры(можно наобъявлять там переменных всяких), но с возможностью там объявлять еще функции(которые в данном случае называют методами), и это все (переменные, методы) еще размещается (помечается) в public protected private кусках, в которых различаются права доступа к этим штукам. Protected хрень доступна для классов, производных от данного, public доступна всем, private доступна только членам класса и friend-ам. ОК, а если я хочу сделать помимо public private protected еще одну хрень, специфицирующую доступ, назову ее huekted, которая например будет доступна всем функциям/методам кроме членов класса и friend-ов (хуй знает нахуй это нужно, просто придумал от балды) то что тут можно сделать? Нихуя!
А есть ведь еще и public, private, protected наследование. Почему я не могу добавить еще какой-то способ наследования? Почему нельзя было все это реализовать в максимально общем (кастомизируемом) виде, чтобы помимо public private protected можно было вводить свои принципиально новые модификаторы доступа, придумывать свои хитровыебаные способы отнаследоваться и прочее прочее?
Очень хорошая точка зрения. А теперь приведи пример, где бы тебя это спасло.
# то что тут можно сделать? Нихуя!
Т.е. С++ не нужен, потому, что ты не можешь на нём сделать фичу, не имеющую практического применения?
Но зачем тебе больше?
/thread
Предложи ещё, но чтобы они были полезны.
Или сделать public2. Методы, объявленные как public2 не могут в своем коде вызывать методы данного класса, которые public или public2 кроме ситуаций с рекурсией.
В такой способ мы говорим программисту, что public методы только извне вызывать разрешено.
# В такой способ мы говорим программисту, что public методы только извне вызывать разрешено.
Я вот не понимаю, это ограничения помогут как-то сделать более понятный код, помогут при составлении документации, благодаря им ты сможешь избежать уязвимостей? Что тебе это даст?
А чем помогают ограничения, накладываемые private? Что они дают? Давайте все методы делать public, настоящие цари ж лучше компилятора знают, что им там можно и чего нельзя откуда вызывать.
Таким ограничением мы декларируем что вот функции эти - внешние и их можно дергать только извне класса - они не предназначены для внутреннего использования внутри классов. Интерфейс для взаимодействия с объектом из внешнего мира нужен только как интерфейс, и не должен внутри как-то сильно задействоваться в самой логике класса, т.е. пусть он просто вызывает какие-то внутренние функции или что-то там сам по себе делает. Изнутри он вызываться не должен т.к. нужен именно для взаимодействия с внешним миром
Дают они очень важную вещь: скрыть детали реализации от внешнего мира.
А вот то, что ты предлагаешь (скрывать публичных членов от самого себя) - глупость.
А зачем их скрывать? Можно просто не обращать внимания, т.е. тупо НЕ ВЫЗЫВАТЬ те методы, которые являются деталями реализации.
> А вот то, что ты предлагаешь (скрывать публичных членов от самого себя) - глупость.
А почему глупость? Я вот может хочу, чтобы публичные методы годились только для вызова приватных методов, т.е. считаем что все публичные методы это такая хрень, которая что-то там приватное вызывает, а вызывать публичные методы из приватных и публичных нафиг не надо.
Всю логику выносим в приватные методы, а публичные просто вызывают приватные. Кроме того, можно придумать несколько слоев приватных методов. Например, первый слой приватных методов может вызывать методы из первого слоя приватных методов, и методы из второго слоя приватных методов. А приватные методы из второго слоя только такие же методы могут вызывать, или методы еще более глубокого слоя. И чем глубже слой, тем ближе к "железу" работает тот метод.
Не нужны для этого никакие хитрые изменения прав доступа, просто вкладываешь объекты разного уровня друг в друга.
Если вкладывать объекты разного уровня друг в друга, это поможет мне поставить ограничения вида "public метод уровня N имеет доступ только к public методам уровня N и N+1, но не более низкого уровня"?
Вот например, пишем допустим хрень для создания-удаления файла. Функции типа open() fstat() lseek() unlink() и прочая такая хрень - public. Им можно обращаться к слою функций, которые абстрагируются вообще от всей питушни, и совершенно не предполагают прямой доступ к жесткому диску. Ну там может быть FUSE или подмонтированная NFS или SMB хрень. В одном из случаев этот слой доступных из юзерспейса функций будет взаимодействовать с каким-то уровнем драйвера ФС. Рассмотрим такой случай
Уровнем ниже будет питушня ФС. Например, если это какой-то там EXT3 то это журналируемая ФС и она там пишет в внутренний журнал какую-то питушню при удалении-создании файлов и прочее, управляет свободными блоками ФС, делает какие-то там манипуляции со структурами данных, специфичных для конкретной ФС. В общем эта какая-то внутренняя питушня для конкретной ФС, которую нельзя вызывать из юзерспейсного слоя, потому что можно что-то легко запороть. Из юзерспейсного слоя можно вызывать только питушню open() read() write(), которая уже у себя делает вызовы более низкого уровня абстракции.
А еще слоем ниже будет какая-то питушня, которая отпавляет ATA команды к жесткому диску на запись каких-то там блоков в какие-то там области, и эти ATA команды можно вызывать только из слоя на один выше т.е. из слоя драйвера ФС. Из слоя, где разрешено вызывать open() read() write их вызывать нельзя. Т.е. есть строгий набор правил, из какой питушни что можно, и что нельзя делать
Да. Именно так я обычно и структурирую приложения. Для этого даже ООП никакого не нужно.
Не надейся на чужую порядочность. Для этого и создан private.
# Я вот может хочу
Хотеть не вредно (с).
# а вызывать публичные методы из приватных и публичных нафиг не надо
Тебе не надо - не вызывай, в чём проблема? Тем более это почти никогда не требуется, разве что в конструкторах.
Вот я тоже на чью-то там порядочность не надеюсь, и создаю особые private2 из которых нельзя вызвать public
> Тебе не надо - не вызывай, в чём проблема?
Вот правильно, давайте тогда и private уберем, чтоб все public было. Если кому-то не надо что-то там вызывать, пусть не вызывает.
Это никакая не порядочность, это попытка спасти самого себя от свой глупости. Себя надо спасать только от глупости других, а не от своей.
# Вот правильно, давайте тогда и private уберем, чтоб все public было. Если кому-то не надо что-то там вызывать, пусть не вызывает.
Ты вообще понимаешь, что ты поехавший. Не я поехавший, не он поехавший, а ты?
Приватные члены созданы для сокрытия логики реализации, публичные - для проверок данных извне. Ты хочешь такой модификатор, которым ты хочешь запретить САМОМУ СЕБЕ из логики вызывать другую логику с защитой. Что ты этим добьёшься? На небе появится радуга, а на ней будут скакать анимешные девочки на розовых пони?
Начнем с того, что обычные публичные приватные я не предлагал менять, я предлагал создавать новый вид публичных2 и приватных2 методов, для которых подобные ограничения можно сделать.
Моя претензия к всей этой ерунде с публичными приватными и защищенными методами класса заключается в том, что это всего лишь какой-то частный случай, заложенный на уровне стандарта самого языка, т.е. язык не позволяет добавлять какие-нибудь private2 виды методов, для которых работают какие-то иные правила доступа. Т.е. на мой взгляд вся подобная ерунда должна быть не захардкожена (типа вот есть ключевое слово public - там такие-то правила для таких методов, private - такие-то правила...), должна быть возможность самому свои типы методов делать, самому придумывать всякие произвольные правила для них.
Предлагаешь-то ты ввести ещё более частные случаи, у которых потенциально ещё меньше юзкейсов.
Кашицын тебе ж сказал, ты нахуя в ситуации, где надо не наследование, а что-то другое, хочешь использовать наследование, и жалуешься, что наследование плохое? Тут то же самое, только с областями видимости.
Ты вот там приводил пример со слоями методов. Это ты предлагаешь, чтобы один объект был многослойным? Чтобы в пределах одного объекта какие-то его члены имели или не имели друг к другу доступ сложным образом? Это идиотизм, ты огребёшь кучу бойлерплейта и сложнейшую документацию. Кроме того, ты вряд ли придумаешь красивый синтаксис для этого. Не числами же слои обозначать. Стало быть, заворачивать в какие-нибудь обертки, нижние слои завернуты в более верхние. Ну и чем это отличается от где надо -- заворачивания объекта в объект, где надо -- наследования.
---> см. далее
Как уже говорили чуваки, уметь выделить из задачи суть, и понять, какие абстракции потребуются -- отдельная задача. Иногда однотипные для русского языка или человеческой психики сущности совсем не имеют общего в реализации, и какого бы хуя им быть родственниками в ООП тогда.
Короче, присмотрись к существующему ООП, и представь, что оно и есть набор тех самых кирпичиков, из которых ты можешь построить всё, что хочешь для частного случая.
Скорее всего, так и есть.
Можно вообще одним public ограничиться, и никакие private нафиг не нужны. Ничего фундаментального в этом говне нет и быть не может. Так что если исходить из позиции "если этим говном можно и ограничиться, то другого не надо" то давайте вообще все нахер выкинем, оставим только public
Я считаю что никакой это не идиотизм. Не нравится - не пользуйся. Возможность доопределять новые фичи ЛУЧШЕ чем отсутствие такой возможности. Эта хренота с классами может быть расширена только запатчиванием самого компилятора, т.е. это говно встроено в само ядро языка, и доопределить новые спецификаторы доступа нельзя вообще никак. Нельзя придумать новый способ наследования. Нельзя добавить новые языковые сущности, помимо классов, структур.
Ведь по-хорошему, всю эту хрень с классами, все эти варианты наследования, это все можно реализовать как некую компилтайм-библиотеку, добавляющую эти конструкции. Типа вот есть чистая сишка, подключаем какую-то библиотеку, и вот в сишке уже есть классы. Подключаем еще библиотеку - и вот лямбды появились. Еще одну библиотеку подключили - добавились констэкспры. И так далее. Но таких механизмов нет, да и реализовать их поверх сишного говносинтаксиса будет затруднительно(если вообще возможно), тут разумеется нужна гомоиконность с нормальными макросами т.е. возможностью легко и удобно обрабатывать код самого себя и трансформировать его произвольным образом.
Не припонмю, что ты писал на ГК раньше, но почти уверен, что ты нигде не работаешь, не имеешь опыта поддержки чужого кода и целыми днями пишешь синтетические хелоуворлды.
У меня нет сейчас обычной работы (такой, где надо было б каждый будний день ходить в офис и какой-то там хренью заниматься) но вообще я работаю над кое-чем. Опыт поддержки чужого кода у меня есть. Мне вот например недавно в Киеве предлагали постоянную работу с з.п. 3000$ в месяц, но я отказался. Постоянную работу мне найти несложно, просто мне это нафиг не надо
Я понял, спасибо.
http://lurkmore.to/_/61475
Я могу захотеть запретить вызывать публичные методы из приватных, к примеру, когда я пишу класс для коммуникации потоков, и (почти) все публичные методы захватывают локи, а приватные работают в предположении, что лок уже взят.
Но и для этого использовать private/public — говно, потому что локов может быть больше одного. Уж лучше использовать специализированные инструменты
См. мое предыдущее предложение про слои методов.
Зачем мне на него смотреть? Я описал ситуацию, когда твои слои могут выглядеть как что-то полезное, но на самом деле всё равно говно по сравнению с алтернативами.
Это вообще совсем никак не относится к ООП.
Бери язык, в котором есть кое-что ещё.
https://docs.racket-lang.org/reference/createclass.html#%28part._clmethoddefs%2 9
https://stackoverflow.com/questions/29379758/in-rackets-class-system-what-do-augment-overment-augride-etc-do
To clarify the difference between overriding and augmentation, when an overridden method is called, the overriding implementation is executed, which may optionally call the superclass's implementation via inherit/super. In contrast, in an augmented method, the superclass's implementation receives control, and it may optionally call the subclass's implementation via inner.
Песдец какой-то !!111
выведет
200
400
Урок домоводства. Учительница:
–— Сегодня мы будем выполнять выворачивание канта наизнанку. Тема сложная, поэтому не отвлекайтесь.
—– Марья Ивановна, это что же получается, моральный закон над нами и звёздное небо внутри нас?
https://ru.wikipedia.org/wiki/Кант_(элемент_одежды)
https://ru.wikipedia.org/wiki/Кант,_Иммануил
Я даже видел в интернетах срач на тему, можно ли вывернуть кант. Оказывается, можно. Есть специальный крючок из проволоки для выворачивания канта:
https://www.nadel.ru/upload/iblock/7f3/Prym611346.jpg
Что же касается, второй части анекдота, она восходит к цитате Иммануила Канта: «Две вещи наполняют душу всегда новым и всё более сильным удивлением и благоговением, чем чаще и продолжительнее мы размышляем о них, — это звёздное небо надо мной и моральный закон во мне». В оригинале она звучала так: «Zwei Dinge erfüllen das Gemüt mit immer neuer und zunehmender Bewunderung und Ehrfurcht, je öfter und anhaltender sich das Nachdenken damit beschäftigt: Der bestirnte Himmel über mir, und das moralische Gesetz in mir».
В динамическах языках -- понятно куча рантайм проверок, поэтому в том числе дорогая абстракция, а в языках типа C++ это реально какие-то "защищенные" области (памяти?), у одного нет права доступа к другому, или это просто компилятор смотрит, не нарушил ли программист в коде какие-либо полномочия?
Что будет, если в крестах написать класс, который в одном из своих методов возвращает другой свой private метод как функцию, а ты во внешнем коде получаешь эту ссылку и пытаешься вызвать?
(Возможно, я сейчас объявил своё глубочайшее непонимание ООП.)
Как мы на этапе выполнения проверим, откуда вызван метод? Компилятор должен в преамбулу метода втыкать код проверки и таблицу адресов памяти, из которых разрешён вызов? Но это получится уже динамическая питушня.
Кстати, в «Винде» именно так сделан «Control Flow Guard»: https://docs.microsoft.com/en-us/windows/win32/secbp/control-flow-guard.
Можешь привести реальный пример ассемблерного выхлопа cl /guard:cf test.cpp?
Этот самый «__guard_dispatch_icall_fptr» на самом деле является синонимом ntdll!LdrpDispatchUserCallTarget и выглядит так:
*fxd
Конпелятор же не знает, что в эту «f» могут передать. Может, её вообще из дллки будут дёргать. Вот в «Microsoft» и нашли довольно элегантный выход.
не нужно наследовать реализацию
Зачем наследование реализации является обязательным для ООП?
Много реализация наследуется.
Много UML-диаграмма вращается.
О. СёмуРеал забанили?
Зачем забанили СёмуРеал? Зачем? Зачем?
# псы-мутанты с 5 ногами
Так унаследуй их от n-ногих
А вообще, достаточно одного класса для всех видов крипов.
Возьми и втуль, чем тебе ООП то мешает?
нарисуй-ка класс диаграмму.
Пока я вижу что можно сделать абстрактный метод у интерфейса IУёбыбл (родителя у всех, кем можно уебать)
метод назвать isМожноУебать()
который у дубинки будет всегда true, а у огнестрела -- функцией от количества уёбанных раз (потом ружжо сломается)
интерфейс IУёбыбл можно удалить из цепочки наследования как только сломается ружье
if item is IУёбыбл
либо
if item.acceptsMessage(уебать)
тогда item.уебать()
else
print "извини чувак, ЭТИМ уебать нельзя"
Можно не суметь стрелять огнестрелом аж по трем причинам - износился огнестрел (типа там спусковой механизм раздолбался). Износилась дубинка (ствол погнули, когда кого-то уебывали). И нет патронов.
Тогда ж будут виртуальный методы, будет создана таблица виртуальных методов для такого класса. Что вообще говоря нафиг не нужно для решения той мелкой задачи. Можно все решить статически, без всей ерунды. Тут не нужно позднее связывание
Ахахахахахахахахах бляяяяя
Какой текст, какие слова!
И чем же ты предлагаешь его заменить?
А теперь покажи изумлённой публике, как бы ты это сделал без ООП подхода, используя свой аналог.
В твоей задаче я поступил бы примерно так: каждый предмет обладает набором свойств: вес, износ, размеры, изображение, тип патронов и т.п. Для каждого предмета также можно получить список доступных с ним действий (да, действия — это значения, а не методы). Действия можно применять к паре объектов и изменять их нужным образом. Например, Hit.apply(дубина, враг), Fire.apply(дубина, враг), Load.apply(пушка, патроны_нужного_калибра). Поскольку действия конструируют пользователи в рантайме, не все из них будут валидны, на этапе компиляции недопустимые комбинации не поймаешь. Можно добавить Action.canApply, чтобы показывать пользователю жирный крестик, когда но пытается зарядить гранатомёт патронами девятого калибра.
Это очень базовая ограниченная модель. Кстати, объекты часто определяют в каком-нибудь скриптовом языке (или просто текстовом файле), который используется движком. Указание объекта в качестве простого набора атрибутов в таком случае гораздо проще и удобнее, чем сложные схемы наследования.
А если у меня все классы final, то я не использую ООП?
Кмк, сама концепция класса и наследования ущербна. Что по-настоящему нужно, так это модульная система,
абстрактные типы данных и интерфейсы модулей. Наследование реализации в OOP-стиле — это убожество.
Имхо, близкая к идеальной система организации кода — это ML-style модули с first-class modules (т.е. когда можно создавать оперировать объектами модулей, например, складывать модули с одинаковым интерфейсом в коллекции).
Отвечу на твой вопрос: если у тебя все классы final, то можно найти взаимно-однозначное соответствие между твоим "OOP"-кодом и модульной системой, похожей на ML.
Классы будут соответствовать типам, объявленным в модуле, публичные методы — интерфейсу модуля, приватные методы — деталям реализации модуля.
Я после неё боюсь слова "модуль". Мне страшно представить, во что может превратиться C++20 (если введут модули), хоть он мне и не нужен.
"Модуль" — слово довольно безобидное. Я вот опасаюсь слова "функтор", поскольку в разных коммьюнити оно означает совершенно разные вещи:
1. Термин из теории категорий
2. Класс типов Functor из Haskell/Idris/...
3. "Функциональный объект" в C++, т.е. класс с перегруженным operator()()
4. Модуль в ML, параметризованный другим модулем (т.е. по сути функция на модулях)
- очень нравится, как сделано в Racket (и, возможно, в остальных схемах).
(provide blabla)
А что там такого сделано? Почитал доку, там вроде всё довольно примитивно. Один файл — один модуль, есть явные списки экспорта, но нет явных списков импорта. Непонятно, как делать локальные алиасы модулей.
Детский сад по сравнению с ML. Даже в Haskell лучше.
Или я чего-то не понимаю?
Очень хорошая идея, в полностью процедурных подходах ее тоже уважают
>доказывать кому-то ущербность ООП
И чуть не забыл: Hurd не нужен.
А ещё Linux это ядро, а FreeBSD это операционная система.
Linux-based OS vs FreeBSD.
Ты серьёзно думаешь, что любой дистрибутив Linux лучше FreeBSD?
Я серьёзно думаю что существующего ООП в Сишарпике достаточно, что бы красиво сделать всё, что я хочу.
Тем не менее у тебя парадокс балба
Что за ниша? Лучший объекто-ориентированный си-подобный язык для платформы .NET под Windows? Тесновато.
Понятно же что я сравнил его с жабой, и конечно жаба хуже
А C# бывает и за пределами MS: Например Xamarin. А Xamarin же единственный способ шарить логику между аппликухами под IOS и Android не трогая вонючее говно типа javascript
Не все могут себе это позволить, но связка "ядро на C++ + нативный гуй" неплохо работает.
Тем более что ios у нас на arm, а android бывает на mips, x86/atom и тоже arm.
У ябла clang, а у андроида наверное gcc, да?
Так что писать придется очень осторожно: подразные компиляторы и разные платформы
Не знаю, про какую бизнес-логику в приложениях ты говоришь, вся бизнес-логика не сервере, клиенты в основном качают из сети, кэшируют и рисуют формочки.
Например, в которых ты можешь составить заявку, и она отошлется когда будет связь с Инетом, и такое приложение должно ее валидировать, например?
Или ты не видел приложений которые имеют локальную БД (CoreData в IOS, sqlite в android) и что-то по ней ищут?
Валидировать заявки на сервере тоже надо.
Если сервер написан на C++, то вообще сплошной вин.
Ты, видимо, хороших либ для C++ не видел.
Потому что LINQ, например) Или потому что рефлексия упрощает ORM.
Но речь была не об этом, а о бизнес логике
>>Валидировать заявки на сервере тоже надо.
конечно.
>>Если сервер написан на C++, то вообще сплошной вин.
Да, но обычные люди скорее напишут бекенд на C#, чем на С++.
Конечно, если они не Гугл, Фейсбук или Яндекс. Я говорю про обычных людей.
>>Ты, видимо, хороших либ для C++ не видел.
Обычно нужно выбирать максимально высокоуровневый инструмент из всех возмжных, ты согласен?
C# более высокоуровневый, в нем сложнее выстрелить себе в ногу, да и программисты дешевле)
Если структура базы не меняется после конпеляции - разницы особо нет, просто без рефлексии будет лишний шаг при сборке проекта.
Ага.
причем это еще и будет работать во много раз быстрее:)
Ну всё равно всякую хуйню про "скидка 23 процента если чел из города КоньКолодезь" и "длина фамилии не больше 10 буков" в общем случае лучше писать на c#, чем на С++
Хотя такие штуки вообще лучше выносить в какие-нить таблицы
Если бы было две реализации (открытая и не очень) SDK и VM под Linux, Windows и Mac (как это есть у жабы) то было бы в тыщу раз круче.
Я думаю многие перешли бы на C# с java.
Он лучший во ВСЕХ нишах. На нём можно писать под что угодно, под телефоны, под древние игровые приставки, операционные системы, приложения рабочего стола, веб-программирование.
А теперь докажи, что есть язык, который лучше Сишарпика и при этом под все платформы, на которых можно запустить Сишарпик (т.е. просто под все существующие платформы)
больше полезных идиом, литералов, операторов, сахара
есть просто такие вещи которые однозначно полезны
например, сахар для аксесоров/мутаторов или вывод типов или генерики в рантейме
Всех пытаются пересадить на "PHP7" с расширением "mysqli_*"; я же до сих пор пишу под "PHP5" с расширением "mysql_*", и при этом все довольны (особенно клиенты, которым, в целом, похуй, как работает, лишь бы работало). В случае, если требуется миграция на "PHP7", я просто подключаю готовую библиотеку с функциями-обёртками для "MySQL", и всё заебца.
По сути, объектно-ориентированный подход (а точнее - троебучий MVC) является всего лишь одним из агрегатных состояний того языка программирования, в рамках которого применяется. Мне этот кипяток, бурлящий лишними файлами, директориями, ключевыми словами и т.д., весьма неприятен; я предпочитаю процедурный подход комнатной температуры.
А теперь представь, какого размера будет index.php у более-менее крупного проекта.
Тогда лучше разбить на index2.php и index3.php
Или вообще так: govnokod23477.php, govnokod23478.php, kabinka25723.php, kabinka1659.php.
это удобно
Добавить страницу очень просто. Никакие MVC и иже с ними такой гибкости не дают.
ахахахахахахаххаха
... а также все необходимые стили и скрипты для фронтенда.
А скрипты для фронтэнда тоже можно подключать. Например, страничка может выглядеть вот такт
<SCRIPT LANGUAGE=JavaScript SRC="jquery.js"></SCRIPT>
<SCRIPT LANGUAGE=JavaScript SRC="jquery.ui.js"></SCRIPT>
<SCRIPT LANGUAGE=JavaScript SRC="carousel.js"></SCRIPT>
<SCRIPT LANGUAGE=JavaScript SRC="bdccbcfef4526.js"></SCRIPT>
<SCRIPT LANGUAGE=JavaScript SRC="stranitsa_pokupok.js"></SCRIPT>
<SCRIPT LANGUAGE=JavaScript SRC="script.js"></SCRIPT>
Главное тут не перепутать порядок подключения включая нужные скрипты в каждую страничку
SemaReal это barop aka Roskomgovno, сейчас сидит под гостем. Возможно Stallman тоже его файка.
про него и речь
2. Скольким программистам ты испортил жизнь, вынуждая их поддерживать твои процедурные write and throw проекты без MVC?
Либо ты сайтист-визиточник, но что тогда ты делаешь одиннадцать лет?
Странно всё это.
п.с. минуснул не я.
Есть у меня привычка использовать protected вместо private, просто потому что я никогда до конца не уверен, что потом не придется на базе текущего класса создавать иерархию.
Это совсем плохо или жить можно?
Если не уверен, делай всё private. Классы для создания иерархий должны проектироваться специальным образом, а не когда вздумается. Т.е. если вздумается, всё равно рефакторить придётся. private, вероятно, будет наименьшей из проблем.
Как мне кажется, иерархии вообще нинужны.
В любой иерархии смешиваются 2 концепции - няшное наследование публичного интерфейса и сомнительное наследование реализации. А из-за наследования реализации:
1) растёт связность между классами;
2) реализация размазывается тонким слоем по всей иерархии, её становится сложно понять;
3) в классах накапливается мусор - поля и методы, которые напихали про запас или ради реализации соседних классов;
4) начинается херня в духе "а от чего мне наследовать ружьё, чтобы прикрутить его в иерархию?"
Поэтому, имхо, в иерархии стоит объединять только интерфейсы. А общие куски реализации лучше прикручивать чем-нибудь типа mixin'ов (аля CRTP), а не совать в "базовый класс".
1. Собрать класс из микс-инов, часто с CRTP, никакая динамическая диспетчеризация тут не нужна
2. Реализация интерфейса, как правило, через Non-Virtual Interface Idiom и общей логикой (проверки пред- и пост- кондишенов) в "интерфейсе".
Ололо, кто-то реально это делает.
- а потом назвать это дело аспектами. Дело хорошее, но как-то на практике всё упирается в то, что сделать грамотный и универсальный mixin посложнее, чем решить вопрос, "а от чего мне наследовать ружьё"
"Проектируйте наследование явно или запрещайте его".
Сделать класс, который можно наследовать не превратив его в говно -- тяжкий труд. Нужно очень четко понять какие методы можно открыть, и какая у них должна быть политика оверрайда (вызов super перед/после/никогда).
А идеале 99.9% твоего проекта должны быть финальными и не поддерживать наследование.
Наследовать надо интерфейсы, а не классы.
Наследоваться просто чтобы переюзать код это не правильно
Вот так в жабе и унаследовали Properties от HashTable....
Because Properties inherits from Hashtable, the put and putAll methods can be applied to a Properties object. Their use is strongly discouraged as they allow the caller to insert entries whose keys or values are not Strings. The setProperty method should be used instead.
Но тут с LSP проблемы какие-то. Это как целое число от действительного наследовать. Вот если и правда перламутровые пуговицы были бы только добавкой к уже существующему...
А, или дело тут ещё и в том, что если мы публично наследуемся, то в последующих версиях они могут сами сделать с перламутровыми пуговицами, и тогда все, кто использовал сам класс, не пострадают (обратная совместимость), а все, кто унаследовался - окажутся в зоне риска (конфликты имён, конфликты реализаций).
Для тех, кому важна хронологическая точность: The Smalltalk Report, October 1994, Volume 4, Number 2. Страницы с 4 по 10.
Вот год очень кстати. И уже тогда автор начал просекать: "что-то здесь не то".
>приверженость идеологии ООП, рекламные объявления, где объекты продают и еще всякие странные вещи с ними делают, и совсем недорого.
Помнится один умный человек говаривал что "это ваше ООП напоминает гербалайф".
- я, конечно, боюсь быть осмеянным вореционными профессорами, но всё же поинтересуюсь, как в процедурном подходе мне что-нибудь заmockать, чтобы потом заюзать в юнит-тестах тестовую реализацию вместо обычной?
Смекаешь?..
Приведи реальный пример кода, который нельзя «замокать» при помощи «Ctrl+Ins, Shift+Ins».
Да как и везде тестируют: берут какую-нибудь «Цмоку»* и вперёд, на баррикады. Именно поэтому я за «цмок».
*https://cmocka.org/
Цари вставляют printf прямо в рабочий код, а перед выпуском программы его комментируют.
Я уже объяснял вам, клоунам, про то что сишка первична.
А потом прибегают ублюдки, берут printf и прикручивают поверх него примитивный if.
Или хуже того — пилят свои говнологгеры.
Это работает через жопу.
Очевидно, что в ваших мусорных недоязычках с помойки нет препроцессора.
По причине, что авторы этого мусора — биомусор.
Цари же добавляют сишнокрестовому компилятору флаг -DNDEBUG и сливают анскильных лалок в хламину.
Хотя тут даже ненужны прошлые фиксации — всё видно сейчас.
Во-первых мы здесь не видим ответа, какой-то контр-аргументации, либо вопроса.
Ничего нет — есть попытка включать идиота, будто бы этот клоун не знает того о чём я говорю, хотя понятие «препроцессора в Си» вполне себе очевидно.
Второе и самое важное - тут сразу можно заметить, как это отребье начинает меня обзывать и в чём-то обвинять.
Но опять, как видно бездарность ничего конкретного не сказал и ничего не обосновала.
Это явный офтоп, это явные оскорбления, это явный тупняк, это явная мразь. Фиксируем.