Сила ОО дизайна в семантике или инкапсуляции? - PullRequest
19 голосов
/ 21 марта 2009

Объектно-ориентированное проектирование (OOD) объединяет данные и их методы. Это, насколько я вижу, позволяет достичь двух замечательных вещей: обеспечивает инкапсуляцию (поэтому мне все равно, какие данные есть, только как я получаю нужные значения) и семантику (она связывает данные вместе с именами и методы последовательно используют данные, как первоначально предполагалось).

Так в чем же сила OOD? В противоположность этому функциональное программирование приписывает богатство глаголам, а не существительным, и поэтому инкапсуляция и семантика обеспечиваются методами, а не структурами данных.

Я работаю с системой, которая находится на функциональном конце спектра и постоянно жаждет семантики и инкапсуляции ОО. Но я вижу, что инкапсуляция ОО может быть препятствием для гибкого расширения объекта. Так что на данный момент я вижу семантику как большую силу.

Или инкапсуляция является ключом ко всему стоящему коду?

Редактировать: я имею в виду именно тот тип инкапсуляции, который ОО предоставляет здесь. changeColor(door,blue) становится door.changeColor(blue).

Ответы [ 11 ]

30 голосов
/ 23 марта 2009

Вы, похоже, используете довольно узкое определение «Инкапсуляция». Буду ли я прав, предполагая, что вы определяете инкапсуляцию как «Объединение данных с методами?»

Если я ошибаюсь, игнорируйте оставшуюся часть этого поста.

Инкапсуляция не является свободным термином; фактически, это определено Международной организацией по стандартизации. Эталонная модель ISO открытой распределенной обработки - определяет следующие пять концепций:

Сущность: любая конкретная или абстрактная вещь, представляющая интерес.

Объект: модель объекта. Объект характеризуется своим поведением и, вдвойне, своим состоянием.

Поведение (объекта): набор действий с набором ограничений относительно того, когда они могут происходить.

Интерфейс: абстракция поведения объекта, которая состоит из подмножества взаимодействий этого объекта вместе с набором ограничений на то, когда они могут произойти.

Инкапсуляция: свойство, заключающееся в том, что информация, содержащаяся в объекте, доступна только через взаимодействия на интерфейсах, поддерживаемых объектом.

Кроме того, мы можем сделать самоочевидное предложение: поскольку некоторая информация доступна через эти интерфейсы, некоторая информация должна быть скрыта и недоступна внутри объекта. Свойство, которое демонстрирует такая информация, называется скрытием информации, которое Парнас определил, утверждая, что модули должны быть спроектированы так, чтобы скрывать как сложные решения, так и решения, которые могут измениться, см. Одну из замечательных компьютерных статей:

http://www.cs.umd.edu/class/spring2003/cmsc838p/Design/criteria.pdf

Важно отметить, что не только данные скрыты в информации: это некоторая подгруппа поведения, связанная с объектом, которую трудно или вероятно изменить.

В своем посте вы, кажется, говорите, что разница между инкапсуляцией в ОО и в функциональном программировании связана с управлением данными, но, по крайней мере, согласно ISO и Parnas, управление данными не является ключом к инкапсуляции. Поэтому я не понимаю, почему инкапсуляция в функциональном программировании должна отличаться от инкапсуляции в ОО.

Кроме того, в своем посте вы упоминаете, что функциональное программирование обеспечивает инкапсуляцию «… методами, а не структурами данных». Я думаю, что это разница масштаба, а не абсолюта. Если я использую слово «Объект», а не «Структура данных» (опять же, пожалуйста, дайте мне знать, если я неправильно истолковываю), тогда вы, кажется, найдете значение в инкапсуляции ОО с помощью метода объектного и функционального программирования.

Тем не менее, согласно приведенному выше определению ISO, объект - это все, что я хочу моделировать. Таким образом, классы могут быть инкапсулированы в пакет, при условии, что некоторые из этих классов вносят вклад в интерфейс пакета (т. Е. Открытые классы пакета), а некоторые скрыты для информации (частные классы в пакете).

Точно так же методы инкапсулированы в классе - некоторые методы являются открытыми, а некоторые - закрытыми. Вы даже можете взять это на ступеньку ниже и сказать, что последовательные последовательности кода Маккабиана инкапсулированы в методы. Каждый формирует граф узлов, инкапсулированных в инкапсулированных областях; и все эти графы образуют стек графов. Таким образом, функциональное программирование может быть хорошо инкапсулировано на уровне функции / файла, но это ничем не отличается от метода / графа классов ОО и, по сути, также не отличается от графа класса / пакета ОО.

Также обратите внимание, что слово Парнас используется выше: изменить. Сокрытие информации касается потенциальных событий, таких как изменение сложных проектных решений в будущем. Вы спрашиваете, в чем сила ОО? Что ж, инкапсуляция, безусловно, является сильной стороной ОО, но тогда возникает вопрос: «В чем заключается сила инкапсуляции?», и ответ на этот вопрос один из потрясающей ясности: управление изменениями. В частности, инкапсуляция уменьшает максимальное потенциальное бремя изменений.

Понятие «Потенциальная связь» полезноЯ здесь.

«Соединение» само по себе определяется как «мера силы ассоциации, установленной соединением от одного модуля к другому» в другой из выдающихся работ вычислительной техники:

http://www.research.ibm.com/journal/sj/382/stevens.pdf

И, как говорится в документе, словами, которые с тех пор никогда не улучшались, «Минимизация соединений между модулями также сводит к минимуму пути, по которым изменения и ошибки распространяются в другие части системы, таким образом устраняя катастрофические эффекты« пульсации », когда изменения в одна часть вызывает ошибки в другой, что требует дополнительных изменений в другом месте, порождает новые ошибки и т. д. »

Однако, как здесь определено, есть два ограничения, которые можно легко снять. Во-первых, связывание не измеряет внутримодульные соединения, и эти внутримодульные соединения могут вызывать столько же эффектов «пульсации», сколько и межмодульных соединений (в документе определено «единство» для связи внутримодульных соединений). элементы, но это не определяется с точки зрения связей между элементами (т. е. ссылки на метки или адреса), с которыми была определена связь). Во-вторых, соединение любой компьютерной программы является заданным, в котором модули связаны или; в определении связи мало возможностей для управления потенциальными изменениями, о которых говорит Парнас.

Обе эти проблемы в некоторой степени решены с помощью концепции потенциальной связи: максимально возможного числа соединений, формируемых между всеми элементами программы. Например, в Java класс, который является частным для пакета (метод доступа по умолчанию) в пакете, не может иметь соединения, сформированные на нем (то есть никакие внешние классы не могут зависеть от него, несмотря на отражение), но открытый класс в пакете может есть зависимости от этого. Этот открытый класс будет способствовать потенциальной связи, даже если другие классы не зависят от него в данный момент - классы могут зависеть от него в будущем, когда дизайн изменится.

Чтобы увидеть силу инкапсуляции, рассмотрим принцип бремени. Принцип Бремени принимает две формы.

Сильная форма утверждает, что бремя преобразования набора сущностей является функцией количества преобразованных сущностей. Слабая форма утверждает, что максимальное потенциальное бремя преобразования набора сущностей является функцией максимального потенциального числа преобразованных сущностей.

Бремя создания или изменения любой программной системы является функцией количества созданных или измененных классов (здесь мы используем «Классы», предполагающие систему ОО, и занимаемся инкапсуляцией на уровне класса / пакета; мы мог бы в равной степени заботиться о функциональном / файловом уровне функционального программирования). (Обратите внимание, что «Бремя» - это современная разработка программного обеспечения, как правило, стоимость, или время, или оба.) Классы, которые зависят от конкретного модифицированного класса, имеют более высокую вероятность воздействия, чем классы, которые не зависят от модифицированного класса.

Максимальное потенциальное бремя, которое может создать модифицированный класс, - это воздействие на все классы, которые зависят от него.

Следовательно, уменьшение зависимостей от модифицированного класса снижает вероятность того, что его обновление повлияет на другие классы, и, таким образом, уменьшает максимальную потенциальную нагрузку, которую может наложить этот класс. (Это немного больше, чем переосмысление статьи «Структурированный дизайн».)

Уменьшение максимального потенциального числа зависимостей между всеми классами в системе, следовательно, снижает вероятность того, что воздействие на определенный класс вызовет обновления для других классов, и, таким образом, уменьшает максимальную потенциальную нагрузку всех обновлений.

Инкапсуляция за счет уменьшения максимального потенциального числа зависимостей между всеми классами, следовательно, смягчает слабую форму Принципа нагрузки. Все это покрывается «Теорией инкапсуляции», которая пытается математически доказать такие утверждения, используя потенциальную связь в качестве логического средства структурирования программы.

Заметьте, однако, что когда вы спрашиваете:капсулирование - ключ ко всему стоящему коду? »Ответ наверняка будет: нет. Нет единого ключа ко всему стоящему коду. В некоторых случаях инкапсуляция - это всего лишь инструмент, помогающий улучшить качество кода и сделать его «стоящим».

Вы также пишете, что «… инкапсуляция может быть препятствием для гибкого расширения объекта». Да, это, безусловно, может: она действительно предназначена для того, чтобы препятствовать расширению проектных решений объекта, которые являются трудными или вероятными изменить. Это, однако, не считается плохой вещью. Альтернативный подход состоял бы в том, чтобы все классы были общедоступными и чтобы программа выражала свою максимальную потенциальную связь; но тогда слабая форма Принципа Бремени утверждает, что обновления будут становиться все более дорогостоящими; это затраты, против которых должны измеряться барьеры для расширения.

Наконец, вы проводите интересное сравнение между инкапсуляцией и семантикой, и, по вашему мнению, семантика ОО является ее большей силой. Я тоже не семантик (я даже не знал, что такое слово существовало до того, как добрый мистер Рэмси упомянул об этом в своем комментарии), но я предполагаю, что вы имеете в виду «семантика» в смысле «значение или интерпретация значения слова », и, по сути, класс с методом woof () должен называться Dog.

В этой семантике действительно есть большая сила.

Что мне любопытно, так это то, что вы противопоставляете семантику инкапсуляции и ищете победителя; Я сомневаюсь, что вы найдете один.

По моему мнению, есть две силы, которые мотивируют инкапсуляцию: семантическая и логическая.

Семантическая инкапсуляция просто означает инкапсуляцию, основанную на значении инкапсулированных узлов (если использовать общий термин). Поэтому, если я скажу вам, что у меня есть два пакета, один называется «животное», а другой - «минерал», а затем предоставлю вам три класса Dog, Cat и Goat и спросите, в какие пакеты эти классы следует инкапсулировать, тогда никакой другой информации, вы были бы совершенно правы, утверждая, что семантика системы предполагает инкапсуляцию трех классов в пакете «животное», а не в «минерал».

Другой мотивацией для инкапсуляции, однако, является логика и, в частности, исследование потенциальной связи, упомянутое выше. Теория инкапсуляции фактически обеспечивает уравнения для числа пакетов, которые должны использоваться для инкапсуляции ряда классов, чтобы минимизировать потенциальную связь.

Для меня инкапсуляция в целом - это компромисс между этим семантическим и логическим подходом: я позволю потенциальному соединению моих программ подняться выше минимума, если это сделает семантически легче понять программу; но огромные и расточительные уровни потенциальной связи будут предупреждением о том, что мою программу необходимо реструктурировать независимо от того, насколько она семантически очевидна.

(И если хороший мистер Рэмси все еще читает, не могли бы вы или ваши друзья-семантисты дать мне лучшее слово для фазы «семантики», которую я здесь использую? Было бы хорошо использовать более подходящий термин. )

С уважением, Ed.

9 голосов
/ 21 марта 2009

Инкапсуляция и полученная абстракция являются основными преимуществами ОО. «Вещи» предопределяют, какие «действия» могут быть вызваны для них, поэтому существительные приобретают более высокий смысловой смысл, чем глаголы.

В конечном счете, трудно представить проект сложной системы в согласованной и поддерживаемой форме без некоторого уровня инкапсуляции.

6 голосов
/ 22 марта 2009

Как программист на Лиспе, чья объектная система, вероятно, не предоставляет ни одного из них, я говорю: ничего из вышеперечисленного.

jwz: «объектная модель псевдо-Smalltalk проигрывает, и универсальные функции (соответственно ограниченные правилом отсутствия внешних переопределений) побеждают».

Я думаю, что желательные атрибуты, которые вы и другие перечисляете здесь (инкапсуляция, модульность и т. Д.), Не настолько присущи ОО, как вы думаете. Они часто предоставляются вместе с ОО в стиле Java, но не просто следствием этого.

4 голосов
/ 22 марта 2009

Некоторая форма модульности является ключом к любому масштабируемому дизайну. Ограниченность человеческих существ не позволяет людям «впитывать» слишком много информации одновременно, поэтому мы должны разделить проблемы на управляемые, сплоченные куски, чтобы обеспечить основу для понимания крупного проекта, а также способ поделить рабочие задания крупного проекта среди множества людей.

Как выбрать наиболее эффективное «разделение» / «разбиение» большого проекта для достижения вышеуказанных целей? Опыт показал, что ОО является большим победителем, и я думаю, что многие согласятся с тем, что два ключевых атрибута ОО, которые делают это хорошо:

  • Инкапсулировано : каждый класс инкапсулирует «секрет» - набор специфических для реализации предположений, которые, вероятно, будут со временем меняться относительно его реализации - и предоставляет интерфейс, который не зависит от этих предположений; Расслоение таких инкапсулированных абстракций позволяет создать надежную конструкцию, в которой компоненты / реализации могут быть легко заменены перед лицом ожидаемых изменений.
  • Ориентированность на существительное : в большинстве доменов люди кажутся лучше сначала разложить модель домена, думая о существительных / данных домена, а затем идентифицируя вспомогательные глаголы, связанные с каждым существительным.

Что касается функционального программирования (FP) и ОО, у меня есть в блоге об этом, но вкратце я думаю, что FP больше о методах реализации, тогда как ОО больше о структуре и дизайне программы, и поэтому дополняют друг друга: ОО является более доминирующим на «большом» конце шкалы, а ФП - более доминирующим на «маленьком» конце. То есть в большом проекте структура высокого уровня лучше всего описывается с помощью дизайна класса ОО, но многие детали уровня модуля (реализации и детали форм интерфейсов модулей) лучше всего формируются FP влияния.

4 голосов
/ 21 марта 2009

Изолирующая сложность - это главная цель любой конструкции IMO: инкапсуляция функциональности за интерфейсом, который проще в использовании , чем сама функциональность.

ОО предоставляет различные механизмы для этого - два упоминания:

Инкапсуляция позволяет проектировать пользовательскую поверхность, которая не зависит от фактической реализации. (перефразируя, «проще значит другое»).

Семантика позволяет моделировать сущности, которые представляют элементы проблемной области, поэтому их легче понять.


Любой проект, достигающий определенного размера, становится упражнением в управлении сложностью. Я бы сделал ставку на то, что за эти годы программирование сместилось в пределах сложности, которой мы научились управлять.

Я не баловался функциональным программированием в течение многих лет, но, насколько я понимаю, это лучше всего можно описать с помощью математического значения слов «мощный, элегантный, красивый». «Красивый» и «элегантный» в этом контексте пытаются описать блестящее понимание истинной или релевантной структуры сложной системы, рассматривая ее с точки зрения, где она удивительно проста. он принимает сложность как данность и пытается ориентироваться в ней.

Упомянутая вами гибкость заключается в том, что в моем понимании есть возможность изменять POV в соответствии с вашими потребностями, но это противоречит инкапсуляции: какая бессмысленная деталь из одной позиции может быть единственной релевантной в другой.

OO, OTOH, это редукционистский подход: мы меняем POV, переходя на более высокий уровень. В «старой ОО» существует единая иерархия POV, интерфейсы - в этой модели - способ моделирования различных POV.

Если можно так выразиться, сила ОО лучше подходит "нормальным людям".

3 голосов
/ 01 апреля 2009

Сила объектно-ориентированного дизайна пропорциональна количеству позднего связывания в проекте. Это понятие Кей ОО, а не понятие Нигорда. Алан Кей написал :

ООП для меня означает только обмен сообщениями, локальный удержание и защита и сокрытие государственного процесса и экстрима поздняя привязка всех вещей. Может быть сделано в Smalltalk и в LISP. Там возможно, другие системы, в которых это возможно, но я не в курсе их.

Большая часть литературы игнорирует позднюю привязку в пользу идеи C ++ об объектной ориентации.

2 голосов
/ 02 апреля 2009

Давайте сделаем шаг назад и посмотрим на это с более высокого уровня. Преимущества любой языковой функции заключаются в возможности более краткого выражения проблемы / решения более естественным образом в отношении предметной области.

Механика ООП легко реализуется в простом С со структурами и указателями на функции. Вы даже можете почувствовать, что ООП чувствует себя так. Тем не менее, ООП идиомы не так скоро в такой среде. При наличии реальной языковой поддержки ООП проявляется выразительность парадигмы, и то, как язык реализует идею, оказывает реальное влияние на то, что «сказано» и как. Например, посмотрите различия в коде с использованием замыканий / лямбд в lisp, python, ruby ​​и т. Д.

Итак, в конце концов, речь идет не о компонентах и ​​основополагающих концепциях, а о том, как они соединяются и используются, что делает ОО в C ++ тем, чем оно является.

1 голос
/ 06 апреля 2009

ИМХО, ОО просто означает объекты, взаимодействующие с другими объектами. Инкапсуляция просто означает абстрагирование концепции. Итак, вы создаете Socket и .Connect () для чего-то. Как это связано, вам все равно (это в основном мое определение инкапсуляции).

И, чисто функциональное программирование может использовать объект для общения ... но эти объекты должны быть неизменными. Итак, опять же ИМХО, FP может легко использовать концепцию ОО; Императивный язык, такой как C, все еще может использовать концепцию OO .. например, файл для каждого «Класса» с закрытым разделом, который не должен использоваться.

1 голос
/ 03 апреля 2009

Инкапсуляция в сочетании с полиморфизмом. Способность классов в большинстве языков ООП реализовывать один или несколько интерфейсов оказала наибольшее влияние на разработку моего программного обеспечения. Эта особенность позволяет мне точно определить взаимодействие между двумя объектами.

Не только определите взаимодействия, но и задокументируйте их, чтобы спустя годы я мог вернуться к этому разделу кода и ясно увидеть, что происходит.

Эта функция является основной причиной, по которой я предпочитаю использовать ООП языки вместо функциональных языков. Несмотря на то, что программное обеспечение, написанное на функциональных языках, было очень мощным, его было трудно поддерживать, когда цикл обслуживания измеряется десятилетиями. (Программное обеспечение AutoLisp найдено в AutoCAD)

0 голосов
/ 29 мая 2010

Реальная сила ОО заключается в полиморфизме, а не в инкапсуляции. Инкапсуляция, в определенной степени, достижима и используется в функциональных языках, но полиморфизм будет очень неудобным, если реализован в функциональном языке.

(Прочтите "шаблон проектирования" по банде из четырех , чтобы понять силу ОО.)

@ Phil, Разница, которую вы упомянули, если я правильно вас понимаю, заключается в том, как программа вызывает данные / метод: в oo сначала появляется объект / экземпляр, а затем вызывается данные / метод объекта через объект; в функционале метод вызывается напрямую.

Однако, глядя на реализацию функциональной программы, мы видим, что данные и метод упакованы (в файл, но не в класс). Например, программа на C имеет заголовочный файл, который объявляет функции, доступные для другого файла, и данные являются частными данными, если они доступны только через эти объявленные функции. Пока программист достаточно осторожен, большая часть инкапсуляции в ОО может быть реализована в функциональных программах. (Даже наследование доступно при использовании некоторых приемов указателя.)

...