Это привлекло мое внимание вчера вечером.
В последней версии Подкаст ALT.NET Скотт Беллвар обсуждает, как, в отличие от Ruby, такие языки, как C#, java и другие. не являются по-настоящему объектно-ориентированными, вместо этого используется фраза «ориентированные на классы». Они говорят об этом различии очень расплывчато, не вдаваясь в подробности и не обсуждая плюсы и минусы.
В чем здесь настоящая разница и насколько это важно? Какие еще языки тогда являются «объектно-ориентированными»? Это прозвучало довольно интересно, но я не хочу изучать Ruby только для того, чтобы знать, что, если чего-то мне не хватает.
Обновлять: После прочтения некоторых ответов ниже кажется, что люди в целом согласны с тем, что это ссылка на утиный ввод. Но я все еще не уверен, что понимаю, что это в конечном итоге все это меняет. Особенно, если вы уже делаете правильные tdd со слабой связью, бла-бла-бла. Может ли кто-нибудь показать мне пример чудесной вещи, которую я могу сделать с Ruby, чего я не могу сделать с C#, и который иллюстрирует этот другой подход к oop?


Может быть, они намекают на разницу между утиной типизацией и иерархией классов?
если он ходит как утка и крякает как утка, просто представьте, что это утка, и пните ее.
В C#, Java и т. д. Компилятор много думает: разрешено ли вам выполнять эту операцию с этим объектом?
Следовательно, объектно-ориентированная и классовая ориентация может означать: заботится ли язык об объектах или классах?
Например: в Python для реализации итеративного объекта вам нужно только предоставить метод __iter__(), который возвращает объект, имеющий метод с именем next(). Вот и все: нет реализации интерфейса (такого нет). Нет подкласса. Просто болтаю как утка / итератор.
Обновлено: За этот пост проголосовали, пока я все переписывал. Извини, больше никогда этого не сделаю. Первоначальный контент содержал советы выучить как можно больше языков и не беспокоиться о том, что языковые врачи думают / говорят о языке.
Я попробую это сделать.
Python и Ruby типизированы как утка. Чтобы сгенерировать любой поддерживаемый код на этих языках, вам в значительной степени придется использовать разработку, управляемую тестированием. Таким образом, для разработчика очень важно легко внедрять зависимости в свой код без необходимости создания гигантской поддерживающей инфраструктуры.
Успешное внедрение зависимостей зависит от наличия довольно хорошей объектной модели. Это две стороны одной медали. Если вы действительно понимаете, как использовать ООП, тогда вам следует по умолчанию создавать проекты, в которые можно легко вводить зависимости.
Поскольку внедрение зависимостей проще в динамически типизированных языках, разработчики Ruby / Python чувствуют, что их язык понимает уроки объектно-ориентированного программирования намного лучше, чем другие статически типизированные аналоги.
Есть три столпа ООП
Если язык может делать эти три вещи, это язык ООП.
Я почти уверен, что аргумент о том, что язык X делает ООП лучше, чем язык A, будет продолжаться вечно.
Комментарии по утиной печати здесь больше связаны с тем фактом, что Ruby и Python более динамичный, чем C#. На самом деле это не имеет ничего общего с OO Nature.
Bellware имел в виду, что в Ruby все является объектом. Даже класс. Определение класса - это экземпляр объекта. Таким образом, вы можете добавить / изменить / удалить его поведение во время выполнения.
Еще один хороший пример: NULL также является объектом. В Ruby все БУКВАЛЬНО является объектом. Наличие такого глубокого объектно-ориентированного программирования позволяет использовать некоторые забавные техники метапрограммирования, такие как method_missing.
IMO, это действительно чрезмерное определение «объектно-ориентированного», но они имеют в виду то, что Ruby, в отличие от C#, C++, Java и др., Не использует класс определение - вы действительно работаете только напрямую с объектами . И наоборот, в C#, например, вы определяете классы, который затем вы должны включить создать экземпляр в объект с помощью нового ключевого слова. Ключевым моментом является то, что вы должны объявлять класс на C# или описать его. Кроме того, в Ruby все - например, четные числа - является объектом. Напротив, C# по-прежнему сохраняет концепцию типа объекта и типа значения. На самом деле, я думаю, это иллюстрирует то, что они делают в отношении C# и других подобных языков - объект тип и значение тип подразумевают систему тип, что означает, что у вас есть целая система типов описание, а не просто работа с объектами.
Концептуально я думаю, что OO дизайн - это то, что предоставляет абстракцию для использования в наши дни для решения сложных задач в программных системах. Язык - это инструмент, используемый для реализации объектно-ориентированного дизайна - некоторые делают его более естественным, чем другие. Я все равно буду утверждать, что, исходя из более общего и более широкого определения, C# и другие по-прежнему являются языками объектно-ориентированный.
Вероятно, это сводится к тому, что, по мнению этих людей, делают другие в C# и java, в отличие от C# и java, поддерживающих ООП. Большинство языков можно использовать в разных парадигмах программирования. Например, вы можете написать процедурный код на C# и схему, и вы можете выполнять программирование в функциональном стиле на java. Это больше о том, что вы пытаетесь сделать и что поддерживает язык.
Я слушал только первые 6-7 минут подкаста, который вызвал ваш вопрос. Если их намерение состоит в том, чтобы сказать, что C# не является чисто объектно-ориентированным языком, это действительно правильно. Все в C# не является объектом (по крайней мере, примитивы таковыми не являются, хотя бокс создает объект, содержащий то же значение). В Ruby все является объектом. Дарен и Бен, кажется, охватили все основы в своем обсуждении «утиного набора текста», поэтому я не буду повторять это.
Является ли это различие (все, что объект по сравнению со всем, что не объект) существенным / значительным - это вопрос, на который я не могу легко ответить, потому что у меня нет достаточной глубины в Ruby, чтобы сравнить его с C#. Те из вас, кто здесь знает Smalltalk (я не знаю, хотя мне хотелось бы знать), вероятно, смотрели на движение Ruby с некоторой забавой, так как это был первый чистый объектно-ориентированный язык 30 лет назад.
Это был действительно абстрактный подкаст! Но я понимаю, к чему они клонят - они просто ослеплены Руби Спаркл. Ruby позволяет делать вещи, о которых программисты на C и Java даже не думают + комбинации этих вещей позволяют достичь невероятных возможностей. Добавление новых методов во встроенный класс String, потому что вам это нравится, передача безымянных блоков кода для выполнения другими, миксины ... Обычные люди не привыкли к объектам, изменяющимся слишком далеко от шаблона класса. Это точно новый мир ...
Что касается тех, кто занимается C#, недостаточно OO ... не принимайте это близко к сердцу ... Просто примите это как то, что вы говорите, когда вас ошеломляют слова. Ruby делает это с большинством людей. Если бы мне пришлось рекомендовать людям один язык для изучения в текущем десятилетии ... это был бы Ruby. Я рад, что сделал .. Хотя некоторые люди могут требовать Python. Но это как мое мнение .. чувак! : D
«Добавление новых методов к встроенному классу String, если вы хотите». вздохнул, и MS прислушалась к этому и добавила методы расширения в C#.
Вам понравится C# 4.0 :) Теперь мутная вода между статическими и динамическими языками. Google из выступления Андерса PDC о будущем C#
Обновление: это новая волна ... которая предполагает, что все, что мы делали до сих пор, устарело ... Кажется, довольно много поддерживается в подкастах и книгах ... Может быть, это то, что вы слышали.
До сих пор нас интересовали статические классы, а не развязанный - мощь объектно-ориентированной разработки. Мы занимаемся разработкой на основе классов. Классы - это фиксированные / статические шаблоны для создания объектов. Все объекты класса созданы равными.
например Просто чтобы проиллюстрировать, о чем я болтаю ... позвольте мне позаимствовать фрагмент кода Ruby из скринкаста PragProg, который я имел честь смотреть. «Разработка на основе прототипов» стирает грань между объектами и классами ... нет никакой разницы.
animal = Object.new # create a new instance of base Object
def animal.number_of_feet=(feet) # adding new methods to an Object instance. What?
@number_of_feet = feet
end
def animal.number_of_feet
@number_of_feet
end
cat = animal.clone #inherits 'number_of_feet' behavior from animal
cat.number_of_feet = 4
felix = cat.clone #inherits state of '4' and behavior from cat
puts felix.number_of_feet # outputs 4
Идея заключается в том, что это более мощный способ наследования состояния и поведения, чем традиционное наследование на основе классов. Это дает вам больше гибкости и контроля в определенных «особых» сценариях (которые мне еще предстоит понять). Это позволяет использовать такие вещи, как Mix-ins (повторное использование поведения без наследования классов).
Бросая вызов базовым примитивам того, как мы думаем о проблемах, «истинное ООП» в некотором смысле похоже на «Матрицу» ... Вы продолжаете идти WTF в цикле. Как этот ... где базовый класс контейнера может быть либо массивом, либо хешем, в зависимости от того, на какой стороне 0,5 генерируется случайное число.
class Container < (rand < 0.5 ? Array : Hash)
end
Ruby, javascript и новая команда, кажется, первопроходцы в этом. Я все еще не в теме ... читаю и пытаюсь разобраться в этом новом явлении. Вроде мощно .. слишком мощно .. Полезно? Мне нужно, чтобы мои глаза открылись еще немного. Интересные времена .. эти.
Гишу, вместо того, чтобы пытаться «постичь» эту силу, почему бы не поучаствовать в расширенном проекте, который реализуется с помощью метапрограммирования? Это то, что помогло мне преодолеть мои собственные когнитивные ограничения, исходящие из мира C# (и Java до этого). Если бы у меня не было реального, осязаемого, практического и практического опыта, я, возможно, не осознал бы, что пытаюсь оценить качества данной парадигмы, не оставив позади предубеждений той, которая на меня больше всего влияет.
Я не думаю, что речь идет именно об утином наборе текста. Например, C# уже поддерживает ограниченную утиную типизацию - примером может быть использование foreach в классе любой, который реализует MoveNext и Current.
Концепция утиной печати совместима со статически типизированными языками, такими как Java и C#, в основном это расширение рефлексии.
Это действительно случай статической и динамической типизации. Оба являются собственно-ОО, поскольку такие вещи существуют. Вне академических кругов об этом действительно не стоит спорить.
Мусорный код можно писать и на том, и на другом. Отличный код можно написать и на том, и на другом. Нет абсолютно ничего функционального, что одна модель может сделать, чего не может другая.
Настоящая разница заключается в характере кодирования. Статические типы ограничивают свободу, но преимущество в том, что все знают, с чем имеют дело. Возможность менять экземпляры на лету очень мощная, но цена заключается в том, что становится трудно понять, с чем вы имеете дело.
Например, для Java или C# intellisense прост - IDE может быстро создать выпадающий список возможностей. Для Javascript или Ruby это становится намного сложнее.
Для некоторых вещей, например, для создания API, с помощью которого кто-то другой будет кодировать, статическая типизация дает реальное преимущество. Для других, например, для быстрого производства прототипов, преимущество заключается в динамике.
В вашем наборе навыков стоит понимать и то, и другое, но далеко не так важно, как глубоко понять тот, который вы уже используете.
OO иногда определяется как ориентированный на сообщения. Идея состоит в том, что вызов метода (или доступ к свойству) на самом деле является сообщением, отправленным другому объекту. То, как принимающий объект обрабатывает сообщение, полностью инкапсулировано. Часто сообщение соответствует методу, который затем выполняется, но это всего лишь деталь реализации. Вы можете, например, создать универсальный обработчик, который будет выполняться независимо от имени метода в сообщении.
Статический объектно-ориентированный объект, как в C#, не имеет такой инкапсуляции. Сообщение имеет соответствует существующему методу или свойству, иначе компилятор пожалуется. Однако динамические языки, такие как Smalltalk, Ruby или Python, поддерживают объектно-ориентированный объект, основанный на сообщениях.
Таким образом, в этом смысле C# и другие объектно-ориентированные языки со статической типизацией не являются истинными объектно-ориентированными языками, так как им не хватает «истинной» инкапсуляции.
Это интересная точка зрения. Но даже в python или ruby вы должны внедрять свои зависимости в конструктор. Так что, если у вас есть зависимость от CookieEatingService, вам придется что-то внедрить! Даже если интерпретатор каким-то образом позаботится об этом и введет nil, вызов service.EatCookie () вызовет ошибку. Это будет работать только в том случае, если конкретная реализация не будет найдена, и будет предоставлена заглушка. Это то, что может сделать и C# (хотя и с большим трудом)
Джордж, во всей ОО нет ничего, что предполагало бы - или даже должно - «вводить» зависимости через аргументы конструктора. Это предвзятость программирования на статическом языке в эпоху фреймворков DI. Это особая культурная предвзятость, которая не отражается в ценностях принципа инверсии зависимостей.
В объектно-ориентированном языке объекты определяются путем определения объектов, а не классов, хотя классы могут предоставлять некоторые полезные шаблоны для конкретных определений данной абстракции, предназначенных для вырезания файлов cookie. В классо-ориентированном языке, таком как, например, C#, объекты должны определяться классами, и эти шаблоны обычно сохраняются, упаковываются и становятся неизменяемыми до выполнения. Это произвольное ограничение, согласно которому объекты должны быть определены до времени выполнения и что определения объектов являются неизменяемыми, не является объектно-ориентированной концепцией; он ориентирован на классы.
Объектно-ориентированный - это концепция. Эта концепция основана на определенных идеях. Технические названия этих идей (на самом деле, скорее, принципы, которые развивались с течением времени и отсутствовали с первого часа) уже были даны выше, я не буду их повторять. Я объясняю это как можно проще и нетехнически.
Идея объектно-ориентированного программирования состоит в том, что существуют объекты. Объекты - это небольшие независимые сущности. Эти объекты могут иметь встроенную информацию, а могут и не иметь. Если у них есть такая информация, только сама сущность может получить к ней доступ или изменить. Сущности общаются друг с другом, отправляя сообщения друг другу. Сравните это с людьми. Люди - это независимые сущности, у которых в мозгу хранятся внутренние данные, и они взаимодействуют друг с другом посредством общения (например, разговаривают друг с другом). Если вам нужны знания из чужого мозга, вы не можете напрямую получить к ним доступ, вы должны задать ему вопрос, и он может ответить вам на него, рассказав то, что вы хотели знать.
И это в основном все. Это реальная идея объектно-ориентированного программирования. Написав эти сущности, определите связь между ними и заставьте их взаимодействовать друг с другом, чтобы сформировать приложение. Это понятие не привязано ни к какому языку. Это просто концепция, и если вы пишете код на C#, Java или Ruby, это не важно. После некоторой дополнительной работы эта концепция может быть реализована даже на чистом C, хотя это функциональный язык, но он предлагает все, что вам нужно для этой концепции.
Разные языки теперь приняли эту концепцию объектно-ориентированного программирования, и, конечно, концепции не всегда равны. Например, некоторые языки позволяют то, что запрещают другие языки. Теперь одна из задействованных концепций - это концепция классов. По некоторым языкам есть классы, по некоторым - нет. Класс - это схема того, как выглядит объект. Он определяет внутреннее хранилище данных объекта, он определяет сообщения, которые объект может понять, и если есть наследование (которое является не обязательно для объектно-ориентированного программирования!), Классы также определяют, из какого другого класса (или классов, если разрешено множественное наследование) это класс наследует (и какие свойства, если существует выборочное наследование). После того, как вы создали такой план, вы можете создавать неограниченное количество объектов, построенных в соответствии с этим планом.
Однако есть объектно-ориентированные языки, в которых нет классов. Как тогда строятся объекты? Ну обычно динамично. Например. вы можете создать новый пустой объект, а затем динамически добавлять к нему внутреннюю структуру, такую как переменные экземпляра или методы (сообщения). Или вы можете продублировать уже существующий объект со всеми его свойствами, а затем изменить его. Или, возможно, объединить два объекта в новый. В отличие от языков, основанных на классах, эти языки очень динамичны, поскольку вы можете динамически генерировать объекты во время выполнения способами, о которых даже разработчик не подумал, когда начал писать код.
Обычно эта динамика имеет свою цену: чем динамичнее язык, тем больше объектов памяти (ОЗУ) будет тратить впустую и тем медленнее все будет, поскольку поток программы также чрезвычайно динамичен, и компилятору сложно сгенерировать эффективный код, если у него нет шансов. для прогнозирования кода или потока данных. Компиляторы JIT могут оптимизировать некоторые части этого во время выполнения, как только они узнают поток программы, однако, поскольку эти языки настолько динамичны, поток программы может измениться в любое время, заставляя JIT отбрасывать все результаты компиляции и повторно компилировать тот же код. снова и снова.
Но это крошечная деталь реализации - она не имеет ничего общего с основным принципом объектно-ориентированного программирования. Нигде не сказано, что объекты должны быть динамическими или изменяемыми во время выполнения. В Википедии это хорошо сказано:
Programming techniques may include features such as information hiding, data abstraction, encapsulation, modularity, polymorphism, and inheritance.
http://en.wikipedia.org/wiki/Object-oriated_programming
Они май или они может нет. Все это не обязательно. Обязательным является только наличие объектов и то, что у них должны быть способы взаимодействия друг с другом (в противном случае объекты были бы бесполезны, если бы они не могли взаимодействовать друг с другом).
@Meckl: Я хотел бы отметить, что концепция объектов, общающихся посредством передачи сообщений, совершенно неактуальна в современном мире, за пределами академических кругов. Это была важная концепция во время разработки технологии, но больше не имеет значения как отдельная концепция.
Вы спросили: «Может ли кто-нибудь показать мне пример чудесной вещи, которую я могу сделать с Ruby, чего я не могу сделать с помощью C#, и который иллюстрирует этот другой подход к oop?»
Хороший пример - активная запись, ORM, встроенный в рельсы. Классы модели динамически создаются во время выполнения на основе схемы базы данных.
Не поймите меня неправильно, с тех пор я начал изучать Ruby, и мне он очень нравится, но как именно ActiveRecord является примером принципов ООП, которые невозможны в C#? Это похоже на пример возможностей динамических языков, а не объектно-ориентированного программирования. Кстати, существует несколько популярных реализаций ActiveRecord на C#, самая популярная из которых - Monorail.
Во-первых, я конкретно говорил об активной записи библиотеки, а не о шаблоне. Библиотека использует метапрограммирование Ruby для динамического определения типов, соответствующих схеме базы данных. Вы не можете сделать это с помощью класса-ориентированного языка, поскольку типы должны быть определены во время компиляции. Активная запись Castle требует, чтобы модель класса соответствовала модели базы данных (или было предоставлено отображение). Я использую определение OO, данное выше Скоттом Беллваром и Беном Шейрманом, которое возможно только в динамических языках.
ага - мы никогда не перестанем бороться из-за этого!