Объектно-ориентированное программирование ( ООП ) — это парадигма программирования , основанная на концепции объектов , [1] которые могут содержать данные и код : данные в форме полей (часто называемых атрибутами или свойствами ) и код в форме процедур (часто называемых методами ). В ООП компьютерные программы разрабатываются путем создания их из объектов, которые взаимодействуют друг с другом. [2] [3]
Многие из наиболее широко используемых языков программирования (такие как C++ , Java [4] и Python ) являются многопарадигмальными и в большей или меньшей степени поддерживают объектно-ориентированное программирование, как правило, в сочетании с императивным программированием , процедурным программированием и функциональным программированием .
Значимые объектно-ориентированные языки включают Ada , ActionScript , C++ , Common Lisp , C# , Dart , Eiffel , Fortran 2003 , Haxe , Java , [4] JavaScript , Kotlin , Logo , MATLAB , Objective-C , Object Pascal , Perl , PHP , Python , R , Raku , Ruby , Scala , SIMSCRIPT , Simula , Smalltalk , Swift , Vala и Visual Basic.NET .
Терминология, ссылающаяся на «объекты» в современном смысле объектно-ориентированного программирования, впервые появилась в группе искусственного интеллекта в Массачусетском технологическом институте в конце 1950-х и начале 1960-х годов. «Объект» относился к атомам LISP с идентифицированными свойствами (атрибутами). [5] [6] Другим ранним примером MIT был Sketchpad, созданный Иваном Сазерлендом в 1960–1961 годах; в глоссарии технического отчета 1963 года, основанного на его диссертации о Sketchpad, Сазерленд определил понятия «объект» и «экземпляр» (с концепцией класса, охватываемой «мастером» или «определением»), хотя и специализированной для графического взаимодействия. [7] Кроме того, в 1968 году версия MIT ALGOL , AED-0, установила прямую связь между структурами данных («плексами» на этом диалекте) и процедурами, предвосхищая то, что позже было названо «сообщениями», «методами» и «функциями-членами». [8] [9] Такие темы, как абстракция данных и модульное программирование, были обычными темами для обсуждения в то время.
Независимо от более поздних работ MIT, таких как AED, Simula была разработана в 1961–1967 годах. [8] Simula ввела важные концепции, которые сегодня являются неотъемлемой частью объектно-ориентированного программирования, такие как класс и объект , наследование и динамическое связывание . [10] Объектно-ориентированный язык программирования Simula использовался в основном исследователями, занимающимися физическим моделированием , таким как модели для изучения и улучшения движения судов и их содержимого через грузовые порты. [10]
Я представлял себе объекты как биологические клетки и/или отдельные компьютеры в сети, способные общаться только с помощью сообщений (поэтому обмен сообщениями появился в самом начале — потребовалось некоторое время, чтобы понять, как осуществлять обмен сообщениями на языке программирования достаточно эффективно, чтобы быть полезным).
Алан Кей, [1]
Под влиянием работы в MIT и языка Simula в ноябре 1966 года Алан Кей начал работать над идеями, которые в конечном итоге были включены в язык программирования Smalltalk . Кей использовал термин «объектно-ориентированное программирование» в разговоре еще в 1967 году. [1] Хотя его иногда называют «отцом объектно-ориентированного программирования», [11] Алан Кей отделил свое понятие OO от более традиционного абстрактного понятия типа данных объекта и намекнул, что истеблишмент компьютерной науки не принял его понятие. [1] В меморандуме MIT 1976 года, соавтором которого была Барбара Лисков, Simula 67 , CLU и Alphard перечислены как объектно-ориентированные языки, но Smalltalk не упоминается. [12]
В 1970-х годах первая версия языка программирования Smalltalk была разработана в Xerox PARC Аланом Кеем , Дэном Ингаллсом и Адель Голдберг . Smalltalk-72 включал в себя среду программирования и был динамически типизирован , и поначалу был интерпретируемым , а не компилируемым . Smalltalk стал известен своим применением объектной ориентации на уровне языка и своей графической средой разработки. Smalltalk прошел через различные версии, и интерес к языку рос. [13] Хотя Smalltalk находился под влиянием идей, представленных в Simula 67, он был разработан как полностью динамическая система, в которой классы могли создаваться и изменяться динамически. [14]
В конце 1970-х и 1980-х годах объектно-ориентированное программирование приобрело известность. Объектно-ориентированный Lisp Flavors разрабатывался с 1979 года, представляя множественное наследование и миксины . [15] В 1981 году Голдберг отредактировал августовский выпуск журнала Byte Magazine , представив Smalltalk и объектно-ориентированное программирование широкой аудитории. [16] LOOPS, объектная система для Interlisp -D, находилась под влиянием Smalltalk и Flavors, и статья о ней была опубликована в 1982 году. [17] В 1986 году Ассоциация вычислительной техники организовала первую конференцию по объектно-ориентированному программированию, системам, языкам и приложениям (OOPSLA), в которой приняли участие 1000 человек. Среди других разработок была Common Lisp Object System , которая объединяет функциональное и объектно-ориентированное программирование и допускает расширение через протокол метаобъектов . В 1980-х годах было предпринято несколько попыток разработать архитектуры процессоров, которые включали аппаратную поддержку объектов в памяти, но они не увенчались успехом. Примерами могут служить Intel iAPX 432 и Linn Smart Rekursiv .
В середине 1980-х годов Objective-C был разработан Брэдом Коксом , который использовал Smalltalk в ITT Inc. Бьярне Страуструп , который использовал Simula для своей докторской диссертации, создал объектно-ориентированный C++ . [13] В 1985 году Бертран Мейер также создал первый проект языка Eiffel . Сосредоточенный на качестве программного обеспечения, Eiffel является чисто объектно-ориентированным языком программирования и нотацией, поддерживающей весь жизненный цикл программного обеспечения. Мейер описал метод разработки программного обеспечения Eiffel, основанный на небольшом количестве ключевых идей из программной инженерии и компьютерной науки, в работе « Объектно-ориентированное построение программного обеспечения» . [18] Важным для фокуса на качестве Eiffel является механизм надежности Мейера, проектирование по контракту , который является неотъемлемой частью как метода, так и языка.
В начале и середине 1990-х годов объектно-ориентированное программирование развивалось как доминирующая парадигма программирования , когда языки программирования, поддерживающие эти методы, стали широко доступны. К ним относятся Visual FoxPro 3.0, [19] [20] C++ , [21] и Delphi [ требуется ссылка ] . Его доминирование еще больше усилилось растущей популярностью графических пользовательских интерфейсов , которые в значительной степени опираются на методы объектно-ориентированного программирования. Пример тесно связанной динамической библиотеки GUI и языка ООП можно найти в фреймворках Cocoa на Mac OS X , написанных на Objective-C , объектно-ориентированном динамическом расширении обмена сообщениями для C на основе Smalltalk. Инструментарии ООП также повысили популярность событийно-управляемого программирования (хотя эта концепция не ограничивается ООП).
В ETH Zürich Никлаус Вирт и его коллеги исследовали концепцию проверки типов через границы модулей. Modula-2 (1978) включала эту концепцию, а их последующий проект, Oberon (1987), включал особый подход к объектной ориентации, классам и т. д. Наследование не очевидно в проекте Вирта, поскольку его номенклатура смотрит в противоположном направлении: это называется расширением типа, и точка зрения направлена от родителя вниз к наследнику.
Объектно-ориентированные возможности были добавлены во многие ранее существовавшие языки, включая Ada , BASIC , Fortran , Pascal и COBOL . Добавление этих возможностей в языки, которые изначально не были для них разработаны, часто приводило к проблемам с совместимостью и поддерживаемостью кода.
Совсем недавно появились некоторые языки, которые в первую очередь являются объектно-ориентированными, но также совместимы с процедурной методологией. Два таких языка — Python и Ruby . Вероятно, наиболее коммерчески важными недавними объектно-ориентированными языками являются Java , разработанный Sun Microsystems , а также C# и Visual Basic.NET (VB.NET), оба разработанные для платформы .NET от Microsoft . Каждая из этих двух фреймворков по-своему демонстрирует преимущество использования ООП, создавая абстракцию от реализации. VB.NET и C# поддерживают кросс-языковое наследование, позволяя классам, определенным на одном языке, создавать подклассы классов, определенных на другом языке.
Объектно-ориентированное программирование использует объекты, но не все связанные с ними методы и структуры поддерживаются напрямую в языках, которые заявляют о поддержке ООП. Перечисленные ниже функции являются общими для языков, которые считаются строго классовыми и объектно-ориентированными (или многопарадигмальными с поддержкой ООП), с упомянутыми заметными исключениями. [22] [23] [24] [25] Кристофер Дж. Дейт заявил, что критическое сравнение ООП с другими технологиями, в частности реляционными, затруднено из-за отсутствия согласованного и строгого определения ООП. [26]
Поддержка модульного программирования обеспечивает возможность группировать процедуры в файлы и модули для организационных целей. Модули имеют пространство имен , поэтому идентификаторы в одном модуле не будут конфликтовать с процедурой или переменной, имеющей то же имя в другом файле или модуле.
Объект — это структура данных или абстрактный тип данных, содержащий поля ( переменные состояния, содержащие данные) и методы ( подпрограммы или процедуры, определяющие поведение объекта в коде). Поля также могут быть известны как члены, атрибуты или свойства. Объекты обычно хранятся в виде непрерывных областей памяти . Доступ к объектам осуществляется как к переменным со сложными внутренними структурами, и во многих языках они фактически являются указателями , выступающими в качестве фактических ссылок на один экземпляр указанного объекта в памяти в куче или стеке.
Объекты иногда соответствуют вещам, встречающимся в реальном мире. [27] Например, графическая программа может иметь такие объекты, как «круг», «квадрат» и «меню». Система онлайн-покупок может иметь такие объекты, как «корзина», «клиент» и «продукт». Иногда объекты представляют более абстрактные сущности, например объект, представляющий открытый файл, или объект, предоставляющий услугу перевода измерений из общепринятой в США системы в метрическую.
Объекты могут содержать другие объекты в своих переменных экземпляра; это известно как композиция объектов . Например, объект в классе Employee может содержать (напрямую или через указатель) объект в классе Address, в дополнение к своим собственным переменным экземпляра, таким как «first_name» и «position». Композиция объектов используется для представления отношений «has-a»: у каждого сотрудника есть адрес, поэтому каждый объект Employee имеет доступ к месту для хранения объекта Address (либо непосредственно встроенного в себя, либо в отдельном месте, адресуемом через указатель). Дейт и Дарвен предложили теоретическую основу, которая использует ООП как своего рода настраиваемую систему типов для поддержки СУРБД , но она запрещает указатели на объекты. [28]
Парадигму ООП критиковали за чрезмерный акцент на использовании объектов для проектирования и моделирования программного обеспечения за счет других важных аспектов (вычислений/алгоритмов). [29] [30] Например, Роб Пайк сказал, что языки ООП часто смещают фокус со структур данных и алгоритмов на типы . [31] Стив Йегге отметил, что в отличие от функционального программирования : [32]
Объектно-ориентированное программирование ставит существительные на первое место. Зачем вам идти на такие меры, чтобы вознести одну часть речи на пьедестал? Почему одна концепция должна иметь приоритет над другой? Это не то, что ООП внезапно сделало глаголы менее важными в том, как мы на самом деле думаем. Это странно перекошенная перспектива.
Рич Хики , создатель Clojure , описал объектные системы как чрезмерно упрощенные модели реального мира. Он подчеркнул неспособность ООП правильно моделировать время, что становится все более проблематичным по мере того, как программные системы становятся более параллельными. [30]
Александр Степанов сравнивает объектную ориентацию с обобщенным программированием в невыгодном свете : [29]
Я считаю ООП технически несостоятельным. Он пытается разложить мир на интерфейсы, которые различаются по одному типу. Чтобы иметь дело с реальными проблемами, вам нужны многосортные алгебры — семейства интерфейсов, которые охватывают несколько типов. Я считаю ООП философски несостоятельным. Он утверждает, что все является объектом. Даже если это правда, это не очень интересно — сказать, что все является объектом, значит вообще ничего не сказать.
Языки ООП разнообразны, но обычно языки ООП допускают наследование для повторного использования кода и расширяемости в форме классов или прототипов . Эти формы наследования существенно различаются, но для определения понятий объекта и экземпляра используется аналогичная терминология .
В программировании на основе классов , самом популярном стиле, каждый объект должен быть экземпляром определенного класса . Класс определяет формат или тип данных (включая переменные-члены и их типы) и доступные процедуры (методы класса или функции-члены) для заданного типа или класса объекта. Объекты создаются путем вызова специального типа метода в классе, известного как конструктор . Классы могут наследоваться от других классов, поэтому они организованы в иерархию, которая представляет отношения «является-типом-из». Например, класс Employee может наследоваться от класса Person. Все данные и методы, доступные родительскому классу, также появляются в дочернем классе с теми же именами. Например, класс Person может определять переменные «first_name» и «last_name» с помощью метода «make_full_name()». Они также будут доступны в классе Employee, который может добавить переменные «position» и «salary». Гарантируется, что все экземпляры класса Employee будут иметь те же переменные, такие как имя, должность и зарплата. Процедуры и переменные могут быть специфичны либо для класса, либо для экземпляра; это приводит к следующим терминам:
В зависимости от определения языка подклассы могут или не могут переопределять методы, определенные суперклассами. Множественное наследование разрешено в некоторых языках, хотя это может усложнить разрешение переопределений. В некоторых языках есть специальная поддержка других концепций, таких как черты и миксины , хотя в любом языке с множественным наследованием миксин — это просто класс, который не представляет отношения is-a-type-of. Миксины обычно используются для добавления тех же методов в несколько классов. Например, класс UnicodeConversionMixin может предоставлять метод unicode_to_ascii() при включении в класс FileReader и класс WebPageScraper, которые не имеют общего родителя.
Абстрактные классы не могут быть инстанциированы в объекты; они существуют только для наследования в другие «конкретные» классы, которые могут быть инстанциированы. В Java final
ключевое слово может использоваться для предотвращения подклассификации класса. [33]
Напротив, в прототипном программировании объекты являются первичными сущностями. Как правило, концепция «класса» даже не существует. Скорее, прототип или родитель объекта — это просто другой объект, с которым связан объект. В Self объект может иметь несколько или ни одного родителя, [34] но в самом популярном прототипном языке, Javascript, каждый объект имеет одну прототипную ссылку (и только одну). Новые объекты могут быть созданы на основе уже существующих объектов, выбранных в качестве их прототипа. Вы можете назвать два разных объекта apple и orange фруктом, если объект fruit существует, и оба apple и orange имеют fruit в качестве своего прототипа. Идея класса fruit не существует явно, но может быть смоделирована как класс эквивалентности объектов, разделяющих один и тот же прототип, или как набор объектов, удовлетворяющих определенному интерфейсу ( утиная типизация ). В отличие от программирования на основе классов, в прототипных языках обычно можно определять атрибуты и методы, не используемые совместно с другими объектами; например, атрибут sugar_content может быть определен в apple , но не в orange .
Некоторые языки, такие как Go, вообще не поддерживают наследование. Go заявляет, что он объектно-ориентированный, [35] а Бьярне Страуструп, автор C++, заявил, что ООП возможно реализовать без наследования. [36] Доктрина композиции вместо наследования выступает за реализацию отношений has-a с использованием композиции вместо наследования. Например, вместо наследования от класса Person класс Employee может дать каждому объекту Employee внутренний объект Person, который затем имеет возможность скрыть от внешнего кода, даже если у класса Person много открытых атрибутов или методов. Делегирование — еще одна языковая функция, которая может использоваться как альтернатива наследованию.
Роб Пайк критиковал ОО-мышление за предпочтение многоуровневой иерархии типов с многоуровневыми абстракциями трехстрочной таблице поиска . [37] Он назвал объектно-ориентированное программирование « римскими цифрами вычислений». [38]
Боб Мартин утверждает, что, поскольку они являются программным обеспечением, связанные классы не обязательно разделяют отношения вещей, которые они представляют. [39]
Ответственность за выбор процедурного кода для выполнения в ответ на вызов метода лежит на объекте, а не на каком-либо внешнем коде, обычно путем поиска метода во время выполнения в таблице, связанной с объектом. Эта функция известна как динамическая диспетчеризация . Если изменчивость вызова зависит от более чем одного типа объекта, для которого он вызывается (т. е. в выборе метода участвует по крайней мере один другой объект параметра), говорят о множественной диспетчеризации . Вызов метода также известен как передача сообщений . Он концептуализируется как сообщение (имя метода и его входные параметры), передаваемое объекту для диспетчеризации.
Диспетчеризация взаимодействует с наследованием: если метод отсутствует в данном объекте или классе, диспетчеризация делегируется его родительскому объекту или классу и так далее, поднимаясь по цепочке наследования.
Абстракция данных — это шаблон проектирования, в котором данные видны только семантически связанным функциям, чтобы предотвратить неправильное использование. Успех абстракции данных приводит к частому включению сокрытия данных в качестве принципа проектирования в объектно-ориентированное и чисто функциональное программирование. Аналогично, инкапсуляция не позволяет внешнему коду быть связанным с внутренней работой объекта. Это облегчает рефакторинг кода , например, позволяя автору класса изменять то, как объекты этого класса представляют свои данные внутри, не изменяя какой-либо внешний код (при условии, что вызовы «публичных» методов работают одинаково). Это также побуждает программистов помещать весь код, который связан с определенным набором данных, в один класс, что организует его для легкого понимания другими программистами. Инкапсуляция — это метод, который поощряет разъединение .
В объектно-ориентированном программировании объекты предоставляют слой, который может использоваться для разделения внутреннего и внешнего кода и реализации абстракции и инкапсуляции. Внешний код может использовать объект только путем вызова определенного метода экземпляра с определенным набором входных параметров, чтения переменной экземпляра или записи в переменную экземпляра. Программа может создавать много экземпляров объектов во время работы, которые работают независимо. Утверждается, что этот метод позволяет легко повторно использовать те же процедуры и определения данных для разных наборов данных, в дополнение к потенциальному интуитивному отражению реальных отношений. Вместо того, чтобы использовать таблицы базы данных и подпрограммы программирования, разработчик использует объекты, с которыми пользователь может быть более знаком: объекты из своей области применения. [40] Эти утверждения о том, что парадигма ООП повышает возможность повторного использования и модульность, были подвергнуты критике. [41] [42]
Первоначальный дизайн поощряется использовать максимально ограниченную видимость в порядке локальных (или методических) переменных, частных переменных (в объектно-ориентированном программировании) и глобальных (или публичных) переменных, и расширяться только тогда и настолько, насколько это необходимо. Это предотвращает недействительность существующего кода из-за изменений видимости. [43]
Если класс не позволяет вызывающему коду получать доступ к внутренним данным объекта и разрешает доступ только через методы, это также является формой сокрытия информации. Некоторые языки (например, Java) позволяют классам явно применять ограничения доступа, например, обозначая внутренние данные ключевым словом private
и обозначая методы, предназначенные для использования кодом вне класса, public
ключевым словом . [44] Методы также могут быть разработаны как публичные, приватные или промежуточные уровни, такие как protected
(что позволяет получить доступ из того же класса и его подклассов, но не объектов другого класса). [44] В других языках (например, Python) это обеспечивается только соглашением (например, private
методы могут иметь имена, начинающиеся с подчеркивания ). В языках C#, Swift и Kotlin internal
ключевое слово разрешает доступ только к файлам, присутствующим в той же сборке, пакете или модуле, что и класс. [45]
В языках программирования, особенно объектно-ориентированных, акцент на абстракции имеет жизненно важное значение. Объектно-ориентированные языки расширяют понятие типа, чтобы включить абстракцию данных, подчеркивая важность ограничения доступа к внутренним данным с помощью методов. [46] Эрик С. Рэймонд написал, что объектно-ориентированные языки программирования, как правило, поощряют программы с толстыми слоями, которые разрушают прозрачность. [47] Рэймонд сравнивает это не в пользу подхода, принятого в Unix и языке программирования C. [ 47]
« Принцип открытости/закрытости » утверждает, что классы и функции «должны быть открыты для расширения, но закрыты для модификации». Лука Карделли утверждал, что языки ООП имеют «чрезвычайно плохие свойства модульности в отношении расширения и модификации классов» и, как правило, чрезвычайно сложны. [41] Последний пункт повторяет Джо Армстронг , главный изобретатель Erlang , которого цитируют: [42]
Проблема объектно-ориентированных языков в том, что у них есть вся эта неявная среда, которую они несут с собой. Вы хотели банан, а получили гориллу, держащую банан и все джунгли.
Лео Броди предположил связь между автономной природой объектов и тенденцией к дублированию кода [48] , что является нарушением принципа «не повторяйся» [49] при разработке программного обеспечения.
Подтипирование – форма полиморфизма – это когда вызывающий код может быть независимым от того, с каким классом в поддерживаемой иерархии он работает – родительским классом или одним из его потомков. Между тем, одно и то же имя операции среди объектов в иерархии наследования может вести себя по-разному.
Например, объекты типа Circle и Square являются производными от общего класса Shape. Функция Draw для каждого типа Shape реализует то, что необходимо для рисования самой себя, в то время как вызывающий код может оставаться безразличным к конкретному типу рисуемой Shape.
Это еще один тип абстракции, который упрощает код, внешний по отношению к иерархии классов, и обеспечивает строгое разделение интересов .
Общей чертой объектов является то, что методы прикреплены к ним и могут получать доступ к полям данных объекта и изменять их. В этой разновидности ООП обычно есть специальное имя, такое как thisили self
используемое для ссылки на текущий объект. В языках, поддерживающих открытую рекурсию , методы объекта могут вызывать другие методы того же объекта (включая себя), используя это имя. Эта переменная имеет позднее связывание ; она позволяет методу, определенному в одном классе, вызывать другой метод, который определен позже, в некотором его подклассе.
Simula (1967) обычно считается первым языком с основными чертами объектно-ориентированного языка. Он был создан для создания программ моделирования , в которых то, что стало называться объектами, было наиболее важным представлением информации. Smalltalk (1972–1980) — еще один ранний пример, с которым была разработана большая часть теории ООП. Что касается степени объектной ориентации, можно выделить следующие различия:
Многие широко используемые языки, такие как C++, Java и Python, предоставляют объектно-ориентированные возможности. Хотя в прошлом объектно-ориентированное программирование было широко принято, [51] в последнее время эссе, критикующие объектно-ориентированное программирование и рекомендующие избегать этих возможностей (обычно в пользу функционального программирования ), стали очень популярны в сообществе разработчиков. [52] Пол Грэм предположил, что популярность ООП в крупных компаниях обусловлена «большими (и часто меняющимися) группами посредственных программистов». По словам Грэма, дисциплина, налагаемая ООП, не позволяет ни одному программисту «нанести слишком много вреда». [53] Эрик С. Рэймонд , программист Unix и сторонник программного обеспечения с открытым исходным кодом , критиковал заявления, которые представляют объектно-ориентированное программирование как «Единственное Верное Решение». [47]
Ричард Фельдман утверждает, что эти языки могли улучшить свою модульность, добавив функции ОО, но они стали популярными по причинам, отличным от объектно-ориентированных. [54] В своей статье Лоуренс Крубнер утверждал, что по сравнению с другими языками (диалекты LISP, функциональные языки и т. д.) языки ООП не имеют уникальных сильных сторон и налагают тяжелое бремя ненужной сложности. [55] Исследование Потока и др. не показало существенной разницы в производительности между ООП и процедурными подходами. [56] Лука Карделли утверждал, что код ООП «по сути менее эффективен», чем процедурный код, и что ООП может компилироваться дольше. [41]
В последние годы объектно-ориентированное программирование стало особенно популярным в динамических языках программирования . Python , PowerShell , Ruby и Groovy — это динамические языки, построенные на принципах ООП, в то время как Perl и PHP добавляют объектно-ориентированные функции начиная с Perl 5 и PHP 4, а ColdFusion — с версии 6.
Объектная модель документа документов HTML , XHTML и XML в Интернете имеет привязки к популярному языку JavaScript / ECMAScript . JavaScript, пожалуй, самый известный язык программирования на основе прототипов , который использует клонирование прототипов, а не наследование от класса (в отличие от программирования на основе классов ). Другой язык сценариев, который использует этот подход, — Lua .
Сообщения, которые передаются между компьютерами для запроса услуг в клиент-серверной среде, могут быть спроектированы как линеаризации объектов, определенных объектами класса, известными как клиенту, так и серверу. Например, простой линеаризованный объект будет состоять из поля длины, кодовой точки, идентифицирующей класс, и значения данных. Более сложным примером будет команда, состоящая из длины и кодовой точки команды и значений, состоящих из линеаризованных объектов, представляющих параметры команды. Каждая такая команда должна быть направлена сервером объекту, класс (или суперкласс) которого распознает команду и может предоставить запрошенную услугу. Клиенты и серверы лучше всего моделировать как сложные объектно-ориентированные структуры. Распределенная архитектура управления данными (DDM) приняла этот подход и использовала объекты класса для определения объектов на четырех уровнях формальной иерархии:
Первоначальная версия DDM определяла распределенные файловые службы. Позднее она была расширена и стала основой архитектуры распределенной реляционной базы данных (DRDA).
Один из способов решения проблем объектно-ориентированного проектирования — это шаблоны проектирования , которые являются шаблонами решения часто встречающихся проблем в разработке программного обеспечения. Некоторые из этих часто встречающихся проблем имеют последствия и решения, характерные для объектно-ориентированной разработки.
Ниже приведены известные шаблоны проектирования программного обеспечения для объектов ООП. [57]
operator()
) он действует во многом как функцияПримером анти-паттерна объекта может служить объект «Бог», который знает или делает слишком много.
Интуитивно понятно, что наследование создает семантическое отношение « является », и, таким образом, можно сделать вывод, что объекты, созданные из подклассов, всегда можно безопасно использовать вместо объектов, созданных из суперкласса. К сожалению, эта интуиция неверна в большинстве языков ООП, в частности, во всех тех, которые допускают изменяемые объекты. Полиморфизм подтипов , обеспечиваемый проверкой типов в языках ООП (с изменяемыми объектами), не может гарантировать поведенческое подтипирование в любом контексте. Поведенческое подтипирование в общем случае неразрешимо, поэтому его нельзя реализовать программой (компилятором). Иерархии классов или объектов должны быть тщательно спроектированы, учитывая возможные некорректные использования, которые невозможно обнаружить синтаксически. Эта проблема известна как принцип подстановки Лисков .
Design Patterns: Elements of Reusable Object-Oriented Software — влиятельная книга, опубликованная в 1994 году Эрихом Гаммой , Ричардом Хелмом , Ральфом Джонсоном и Джоном Влиссидесом , которых часто в шутку называют «Бандой четырех». Наряду с исследованием возможностей и подводных камней объектно-ориентированного программирования в ней описываются 23 распространенные проблемы программирования и шаблоны для их решения.
В книге описаны следующие закономерности:
И объектно-ориентированное программирование, и реляционные системы управления базами данных (СУБД) чрезвычайно распространены в программном обеспечении сегодня [update]. Поскольку реляционные базы данных не хранят объекты напрямую (хотя некоторые СУБД имеют объектно-ориентированные функции, приближающие это), существует общая потребность в соединении двух миров. Проблема соединения объектно-ориентированного программирования и шаблонов данных с реляционными базами данных известна как несоответствие объектно-реляционного импеданса . Существуют некоторые подходы к решению этой проблемы, но нет общего решения без недостатков. [58] Одним из наиболее распространенных подходов является объектно-реляционное отображение , которое встречается в языках IDE , таких как Visual FoxPro , и библиотеках, таких как Java Data Objects и Ruby on Rails ' ActiveRecord.
Существуют также объектные базы данных , которые можно использовать для замены СУРБД, но они не столь успешны в техническом и коммерческом плане, как СУРБД.
ООП можно использовать для связывания объектов и процессов реального мира с цифровыми аналогами. Однако не все согласны с тем, что ООП облегчает прямое отображение реального мира или что отображение реального мира является даже достойной целью; Бертран Мейер в Object-Oriented Software Construction утверждает , что программа не является моделью мира, а моделью некоторой части мира; «Реальность — это дважды удаленная кузина». [59] В то же время были отмечены некоторые принципиальные ограничения ООП. [60] Например, проблема круга-эллипса трудно решается с использованием концепции наследования ООП .
Однако Никлаус Вирт (который популяризировал поговорку, ныне известную как закон Вирта : «Программное обеспечение становится медленнее быстрее, чем оборудование становится быстрее») сказал об ООП в своей статье «Хорошие идеи через зеркало»: «Эта парадигма точно отражает структуру систем в реальном мире и поэтому хорошо подходит для моделирования сложных систем со сложным поведением» [61] (противопоставьте принципу KISS ).
Стив Йегге и другие отметили, что естественным языкам не хватает подхода ООП, который строго расставляет приоритеты между вещами (объектами/ существительными ) и действиями (методами/ глаголами ). [62] Эта проблема может привести к тому, что ООП будет страдать от более запутанных решений, чем процедурное программирование. [63]
ООП был разработан для повышения возможности повторного использования и удобства обслуживания исходного кода. [64] Прозрачное представление потока управления не имело приоритета и должно было обрабатываться компилятором. С ростом значимости параллельного оборудования и многопоточного кодирования разработка прозрачного потока управления становится все более важной, чего трудно достичь с помощью ООП. [65] [66] [67] [68]
Responsibility-driven design определяет классы в терминах контракта, то есть класс должен быть определен вокруг ответственности и информации, которой он делится. Это противопоставляется Wirfs-Brock и Wilkerson data-driven design , где классы определяются вокруг структур данных, которые должны храниться. Авторы считают, что responsibility-driven design предпочтительнее.
SOLID — это мнемоника, придуманная Майклом Физерсом, которая описывает пять принципов проектирования программного обеспечения:
GRASP (шаблоны программного обеспечения для распределения общей ответственности) — это еще один набор рекомендаций, предлагаемых Крейгом Ларманом .
Объекты — это сущности времени выполнения в объектно-ориентированной системе. Они могут представлять человека, место, банковский счет, таблицу данных или любой элемент, который программа должна обрабатывать.
Было предпринято несколько попыток формализовать концепции, используемые в объектно-ориентированном программировании. Следующие концепции и конструкции были использованы в качестве интерпретаций концепций ООП:
Попытки найти консенсусное определение или теорию, лежащую в основе объектов, оказались не очень успешными (однако см. Abadi & Cardelli, A Theory of Objects [70] для получения формальных определений многих концепций и конструкций ООП) и часто сильно расходятся. Например, некоторые определения фокусируются на умственной деятельности, а некоторые на структурировании программ. Одно из самых простых определений заключается в том, что ООП — это действие по использованию структур данных «карт» или массивов, которые могут содержать функции и указатели на другие карты, все с некоторым синтаксическим и областным сахаром сверху. Наследование может быть выполнено путем клонирования карт (иногда называемого «прототипированием»).
В местном жаргоне MIT списки ассоциаций [атомарных символов] также называются "списками свойств", а атомарные символы иногда называются "объектами".
Объект — синоним атомарного символа .
Возможно, самая сильная сторона объектно-ориентированного подхода к разработке заключается в том, что он предлагает механизм, который фиксирует модель реального мира.
Хотя в Go есть типы и методы, а также допускается объектно-ориентированный стиль программирования, иерархии типов нет.
{{cite book}}
: CS1 maint: date and year (link)объектно-ориентированное программирование — широко распространенная парадигма программирования.