Примечание : этот вопрос является отредактированной выдержкой из блога, который я написал несколько месяцев назад. После размещения ссылки на блог в комментарии к Programmers.SE кто-то попросил меня разместить здесь вопрос, чтобы они могли на него ответить. Это сообщение мой самый популярный, так как люди , кажется, типа «я не получаю объектно-ориентированное программирование» в Google много . Не стесняйтесь ответить здесь или в комментарии на Wordpress.
Что такое объектно-ориентированное программирование? Никто не дал мне удовлетворительного ответа. Я чувствую, что вы не получите хорошего определения от того, кто говорит «объект» и «объектно-ориентированный» с носом в воздухе. Также вы не получите хорошего определения от того, кто ничего не делал, кроме объектно-ориентированного программирования. Никто из тех, кто понимает как процедурное, так и объектно-ориентированное программирование, никогда не давал мне последовательного представления о том, что на самом деле делает объектно-ориентированная программа.
Может кто-нибудь дать мне свои идеи о преимуществах объектно-ориентированного программирования?
источник
Ответы:
Думайте о программном обеспечении как о машине или сборочной линии, которая существует внутри компьютера. Некоторое сырье и компоненты подаются в машину, и для ее обработки в какой-то конечный продукт следует ряд процедур. Процедуры настроены для выполнения определенной операции с некоторым сырьем или компонентом с определенным набором параметров (например, время, температура, расстояние и т. Д.) В определенном порядке. Если детали выполняемой операции были неправильными, или датчики машины не откалиброваны правильно, или если какое-либо сырье или компонент не соответствует ожидаемым стандартам качества, это может изменить результат операции, и продукт не получится как и ожидалось.
Такая машина очень жесткая в работе и приемлемых затратах. Машины не подвергают сомнению интеллект дизайнеров и его текущую рабочую среду. Он будет продолжать следовать процедурам, пока он направлен на. Даже если изменение в сырье или компонентах может оказать существенное влияние на то, что произошло в последующих операциях, машина все равно будет выполнять свои процедуры. Процесс необходимо будет пересмотреть, чтобы увидеть, какие изменения в процедурах необходимы для компенсации и получения желаемого результата. Изменение дизайна или конфигурации продукта может также потребовать существенного изменения выполненных операций или их заказа. Хотя те, кто отвечал за производство, быстро поняли важность операций по изоляции, чтобы уменьшить нежелательные эффекты между ними, сделано много предположений о компонентах состояния, которые находятся в процессе обработки; предположения, которые могут быть не обнаружены, пока конечный продукт не окажется в руках пользователя в другой операционной среде.
Вот на что похоже процедурное программирование.
То, что обеспечивает объектная ориентация, это способ удалить предположения о состоянии компонентов; Таким образом, операции, которые должны быть выполнены с этим компонентом и как интегрировать его в конечный продукт. Другими словами, ООП - это все равно, что брать подробности процесса для работы с каким-то конкретным компонентом и передавать его на меньшую машину. Более крупный компьютер, отвечающий за процесс, сообщает конкретному компонентному компьютеру, какую операцию он ожидает выполнить, но оставляет подробности для этапов конкретному компонентному компьютеру для обработки.
Что касается преимуществ объектной ориентации перед не объектно-ориентированным программным обеспечением:
источник
Из вашего блога кажется, что вы знакомы как с императивным, так и с функциональным программированием, и что вы знакомы с основными понятиями, связанными с объектно-ориентированным программированием, но у вас просто никогда не было этого «щелчка» относительно того, что делает это полезным. Я постараюсь объяснить с точки зрения этих знаний, и надеюсь, что это полезно для вас.
По своей сути ООП - это способ использования императивной парадигмы для лучшего управления высокой степенью сложности путем создания «умных» структур данных, которые моделируют проблемную область. В (стандартной процедурной не объектно-ориентированной) программе у вас есть две основные вещи: переменные и код, который знает, что с ними делать. Код принимает входные данные от пользователя и различных других источников, сохраняет их в переменных, обрабатывает их и создает выходные данные, которые отправляются пользователю или в различные другие местоположения.
Объектно-ориентированное программирование - это способ упростить вашу программу, взяв этот базовый шаблон и повторяя его в меньшем масштабе. Так же, как программа представляет собой большой набор данных с кодом, который знает, что с ним делать, каждый объект представляет собой небольшой фрагмент данных, привязанный к коду, который знает, что с ним делать.
Разбивая проблемную область на более мелкие части и следя за тем, чтобы как можно больше данных было напрямую связано с кодом, который знает, что с ним делать, вы значительно облегчаете рассуждения о процессе в целом, а также о подзадаче. вопросы, которые составляют процесс.
Группируя данные в классы объектов, вы можете централизовать код, связанный с этими данными, упрощая поиск и отладку соответствующего кода. А инкапсулируя данные за спецификаторами доступа и обращаясь к ним только через методы (или свойства, если ваш язык их поддерживает), вы значительно уменьшаете вероятность повреждения данных или нарушения инвариантов.
А используя наследование и полиморфизм, вы можете повторно использовать существующие классы, настраивая их в соответствии с вашими потребностями, без необходимости изменять оригиналы или переписывать все с нуля. (Это то, что вы никогда не должны делать , если можете избежать этого.) Просто будьте осторожны, вы понимаете свой базовый объект, иначе вы можете получить убийственные кенгуру .
Для меня это фундаментальные принципы объектно-ориентированного программирования: управление сложностью, централизация кода и улучшенное моделирование проблемной области посредством создания классов объектов, наследования и полиморфизма, а также повышение безопасности без ущерба для мощности или контроля за счет использования инкапсуляции и свойства. Я надеюсь, что это поможет вам понять, почему так много программистов считают это полезным.
РЕДАКТИРОВАТЬ: В ответ на вопрос Джоэля в комментариях,
Небольшой отказ от ответственности здесь. Моя модель «объектно-ориентированной программы» - это в основном модель Delphi, которая очень похожа на модель C # / .NET, так как они были созданы бывшими членами команды Delphi. То, что я здесь говорю, может не применяться или не применяться так же на других ОО-языках.
Объектно-ориентированная программа - это программа, в которой вся логика структурирована вокруг объектов. Конечно, это должно быть где-то загружено. Ваша типичная Delphi-программа содержит код инициализации, который создает одноэлементный объект с именем
Application
. В начале программы она вызываетApplication.Initialize
, затем вызываетApplication.CreateForm
для каждой формы, которую вы хотите загрузить в память с самого начала, а затемApplication.Run,
которая отображает основную форму на экране и запускает цикл ввода-вывода, который формирует ядро любого интерактивные компьютерные программы.Приложение и ваши формы опрашивают входящие события из ОС и переводят их в вызовы методов вашего объекта. Одна вещь, которая очень распространена, - это использование обработчиков событий или «делегатов» в .NET-говорящих. У объекта есть метод, который говорит: «делайте X и Y, но также проверяйте, назначен ли этот конкретный обработчик события, и вызывайте его, если он есть». Обработчик событий - это указатель на метод - очень простое замыкание, которое содержит ссылку на метод и ссылку на экземпляр объекта - которое используется для расширения поведения объектов. Например, если у меня есть объект кнопки в моей форме, я настраиваю его поведение, подключая обработчик события OnClick, который заставляет некоторый другой объект выполнять метод при нажатии кнопки.
Таким образом, в объектно-ориентированной программе большая часть работы выполняется путем определения объектов с определенными обязанностями и связывания их вместе либо с помощью указателей на методы, либо с помощью одного объекта, напрямую вызывающего метод, определенный в открытом интерфейсе другого объекта. (И теперь мы вернулись к инкапсуляции.) Это идея, о которой я понятия не имел до того, как начал посещать уроки ООП в колледже.
источник
Я думаю, что ООП - это просто имя, данное тому, что вы, возможно, испытали на этом пути, как и я.
Когда я был еще маленьким программистом, даже в Фортране, была такая вещь, как указатель на подпрограмму. Действительно полезно иметь возможность передавать указатель на подпрограмму в качестве аргумента другой подпрограмме.
Тогда следующее, что было бы действительно полезно, - это сохранить указатель на подпрограмму внутри записи структуры данных. Таким образом, вы можете сказать, что запись «знает», как выполнять операции над собой.
Я не уверен, что они когда-либо встроили это в Фортран, но это легко сделать в Си и его потомках.
Таким образом, это простая и полезная идея, что вы, возможно, испытали искушение сделать это самостоятельно, и ее легче сделать на более поздних языках, даже если некоторые люди превратили ее в гигантскую команду, полную страшных модных слов.
источник
Существуют различные виды ОО-систем, и трудно получить определение, с которым все согласятся. Вместо того, чтобы пытаться показать, как ОО Java похож на Common Lisp Object System, я начну с чего-то более обычного, шаг за шагом.
Предположим, у вас есть много объектов, существующих как разбросанные данные. Точки, например, могут быть элементами в массиве X, Y и Z. Для того , чтобы рассмотреть саму точку, это имеет смысл , чтобы вытащить все данные вместе в нечто вроде C
struct
.Теперь для любого объекта данных у нас есть все данные вместе. Однако в процедурной программе код разбросан. Предположим, мы имеем дело с геометрическими фигурами. Существует большая функция для рисования фигур, и она должна знать обо всех формах. Есть большая функция для поиска области, а другая для периметра. Код для круга разбросан по нескольким функциям, и для добавления другого типа фигуры нам нужно знать, какие функции нужно изменить. В объектно-ориентированной системе мы собираем функции в одну и ту же вещь (
class
) с данными. Поэтому, если мы хотим посмотреть на весь код круга, он есть вCircle
определении, и если мы хотим добавить a,Quartercircle
мы просто напишем его класс и у нас есть код.Одной из преимуществ этого является то, что мы можем поддерживать инварианты класса, что верно для каждого члена класса. Ограничив код за пределами класса напрямую связываться с членами класса, мы получили весь код, который может изменять данные класса в одном месте, и мы можем подтвердить, что он ничего не делает (например, треугольник с одной ногой) дольше двух других вместе взятых). Это означает, что мы можем рассчитывать на некоторые свойства каждого члена класса, и нам не нужно проверять, является ли объект нормальным каждый раз, когда мы его используем.
Основное преимущество заключается в наследовании и полиморфизме. Определив все эти различные фигуры как подклассы вызываемого класса
Shape
, мы можем заставить наш код манипулироватьShape
s, и подобъекты фигур должны выполнять все, что требуется для манипуляций. Это означает, что нам не нужно трогать старый проверенный код, когда мы добавляем новые формы или улучшаем поведение старых. У нас автоматически есть старый код, который может напрямую использовать новый код. Вместо того чтобы информировать управляющий код обо всех возможных формах и поддерживать функции, которые знают обо всех возможных формах, мы просто имеем дело с формами и их свойствами, сохраняяShape
подклассы. Это упрощает управляющий код.У нас есть несколько преимуществ здесь. Поскольку у нас есть инварианты классов, мы можем рассуждать о больших объектах данных так же, как мы рассуждаем о встроенных типах, то есть мы можем часто разбивать сложные концепции на более простые. Поскольку код круга в основном содержится
Circle
, мы увеличили локальность. Поскольку не существует концепций окружности, разбросанной по нескольким различным функциям в разных местах, мы получаем меньшую связь между подпрограммами, и нам не нужно беспокоиться о их синхронизации. Поскольку классы, по сути, являются типами, мы можем использовать преимущества существующей системы типов для выявления несовместимого использования наших классов.источник
У ОО есть много разных определений, да. Я уверен, что вы можете найти много из них самостоятельно. Мне лично нравится Rees Re: OO , чтобы понять их. Я предполагаю, что вы уже читали это, так как цитируете Пола Грэма. (Я рекомендую его всем, кто интересуется ОО.) Я собираюсь более или менее принять определение Java здесь {1,2,3,7,8,9}.
Вопрос о полезности ОО, особенно о том, как я к нему подхожу, заслуживает более широкого ответа с несколькими тысячами строк кода (частично, чтобы не быть просто набором утверждений). Тем не менее, вот краткое изложение этого гипотетического документа.
Я не думаю, что ОО ужасно полезен в небольшом масштабе, скажем, около нескольких сотен строк. В частности, ОО-языки без хороших функциональных влияний, как правило, затрудняют выполнение простых задач с любым типом коллекций или чем-то, что требует много типов данных. Это где большинство шаблонов дизайна вступают в игру; они бинты на малой мощности основного языка .
Приблизительно в тысяче строк становится все труднее отслеживать все операции и структуры данных и их взаимосвязь. На этом этапе полезно иметь способ явной организации структур данных и операций, рисовать границы модулей и определять обязанности, а также иметь удобный способ понять эти определения, когда вы пытаетесь программировать против них.
Java-iso OO - наполовину решение этих проблем, которое, как оказалось, выиграло конкурс популярности. Поскольку это тот же механизм, который люди Java применяют к мелкомасштабным задачам, создаваемым слабым языком, он начинает больше походить на волшебное решение всего, чем просто способ оставаться организованным. Люди, знакомые с функциональным программированием, склонны предпочитать другие решения, такие как классы типов CLOS или Haskell, или метапрограммирование шаблонов, когда застряли в C ++, или же (как я, ежедневно работающий в C #) использовать OO, но просто не волнуйтесь об этом ,
источник
ООП пытается моделировать концепции реального мира с точки зрения объектов и взаимодействий между ними. Как люди, мы склонны обрабатывать мир с точки зрения объектов. Мир полон объектов, которые имеют определенные свойства и могут делать что-то вроде взаимодействия с другими объектами. ООП позволяет моделировать мир в аналогичных терминах. Например,
Но автомобиль не может двигаться сам по себе, ему нужен человек, который управляет им - взаимодействие между объектами.
источник
ООП = структуры данных + передача сообщений + наследование, все из которых являются логическим развитием в моделях программирования.
ООП может быть понят (программистами) примерно за 90 секунд (см. Мой профиль для ссылки). Концепции очень просты.
Как применять это другое дело. То, что вы умеете раскачивать молоток, не означает, что вы знаете, как спроектировать и построить дом. ;-)
источник
Некоторое время назад я написал сообщение в блоге, которое может оказаться полезным: объяснение процедурного и ООП .
источник
То, как я впервые понял это:
До объектно-ориентированного программирования у вас было структурированное программирование . Все сосредоточено вокруг процесса. Первый вопрос, который вам нужно задать себе: « Что я хочу сделать с информацией? ».
С объектно-ориентированным программированием, оно сосредоточено вокруг данных. Первый вопрос, который вам нужно задать себе, - « Информация о ведьмах, с которой мне нужно иметь дело? ». Это делает абстракцию проще.
источник
Поскольку вы понимаете структуры, и вы понимаете указатели на функции, и вы понимаете структуры с помощью указателей на функции, с вашей точки зрения я бы определил объектно-ориентированное программирование как просто «программирование с интенсивным использованием структур, которые имеют указатели на функции». Это все еще программирование в традиционном смысле - это все данные и код, которые воздействуют на данные. Разница лишь в том, как определяется вся эта информация и как вы подходите к ее определению.
Возможно, чрезмерное упрощение заключается в том, что традиционное программирование - это «код с некоторыми структурами данных», а объектно-ориентированное программирование - это «структуры данных с некоторым кодом». У обоих все еще есть структуры данных, и у обоих все еще есть код. Таким образом, объектно-ориентированное программирование - это не что иное, как предварительное определение типов данных и заключение договоров о том, как они взаимодействуют с помощью наборов функций.
Как вы заметили, существует огромный класс приложений, для которых это не очень хороший способ реализовать решение. Вы, кажется, живете в мире, состоящем преимущественно из таких приложений. В своем сообщении в блоге вы упомянули о реализации проблемы «99 бутылок пива» (ваша «любимая витрина программирования»). 99 бутылок пива, безусловно, являются частью этой категории. Попытка понять объектно-ориентированное программирование, взглянув на реализацию 99 бутылок пива, - все равно, что попытаться понять высотную архитектуру, взглянув на домик на дереве. Даже очень хорошо построенный дом на дереве может научить вас только многому.
TL; DR: ОО-программирование похоже на традиционное программирование, за исключением того, что вы сосредотачиваете больше усилий на определении структур данных заранее, и эти структуры данных взаимодействуют друг с другом через указатели функций.
источник
Я думаю, что страница Википедии - хорошее место, чтобы получить основы:
http://en.wikipedia.org/wiki/Object-oriented_programming
По сути, идея заключается в том, что процедурное программирование, которое ООП пыталось улучшить, сфокусировано на моделируемых процессах. ООП переходит к модели, в которой основное внимание уделяется «вещам», которые вы моделируете, а процессы и данные этих вещей содержатся в этих вещах.
Итак, в качестве примера предположим, что вы разрабатывали приложение для отслеживания списка задач. В процедурном программировании объектами высшего уровня в модели будут происходящие процессы, такие как создание задачи, удаление задачи, изменение информации о задаче и т. Д. В модели ООП вместо этого вы бы сосредоточились на создании задачи и подумайте, за какие данные и процессы должна отвечать эта задача. А затем сфокусируйтесь на том, с какими другими объектами должна взаимодействовать задача, например, на заметке или чем-то еще, если вы хотите вести заметки о задачах.
Надеюсь, это поможет. Просто продолжайте читать об этом и смотреть на код, и он внезапно "щелкнет". Это был мой опыт.
источник