Игнорирует ли функциональное программирование преимущества, полученные от «Критериев, которые будут использоваться при декомпозиции систем на модули» (скрытие данных)?


27

Есть классическая статья под названием «Критерии для использования при декомпозиции систем на модули», которую я только что прочитал впервые. Это имеет смысл для меня и, вероятно, является одной из тех статей, на которых основывается ООП. Его вывод:

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

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

  1. Сначала я хочу знать, правильна ли моя оценка. Парадигма FP и эта статья философски не согласны?
  2. Предполагая, что они не согласны, как FP "компенсирует" отсутствие скрытия данных? Возможно, они жертвуют сокрытием данных, но получают X, Y и Z. Я хотел бы знать причину, почему X, Y и Z считаются более выгодными, чем сокрытие данных.
  3. Или, если они не согласны, возможно, FP считает, что сокрытие данных - это плохо. Если так, почему он считает, что сокрытие данных плохо?
  4. Предполагая, что они согласны, я хотел бы знать, что такое реализация сокрытия данных в FP. Это очевидно в ООП. У вас может быть privateполе, к которому никто за пределами класса не может получить доступ. Там нет очевидной аналогии этого для меня в FP.
  5. Я чувствую, что есть другие вопросы, которые я должен задавать, но я не знаю, должен ли я задавать. Не стесняйтесь отвечать на них тоже.

Обновить

Я нашел этот разговор Нила Форда, в котором есть очень актуальный слайд. Я вставлю скриншот здесь:

введите описание изображения здесь


1
Я не могу ответить на полный вопрос, но что касается (4), на некоторых языках FP существуют модульные системы, которые могут обеспечить инкапсуляцию.
Андрес Ф.

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

6
То, что вы часто делаете, это делает ваши типы видимыми, но скрываете свои конструкторы. Эти абстрактные типы особенно хорошо выполняются модульной системой OCaml
Даниэль Гратцер,

6
В ML-подобном языке отсутствие доступа к конструкторам означает, что вы не можете сопоставить шаблон со значением этого типа, чтобы деконструировать его. Единственное, что вы можете сделать с этими значениями, это передать их любой доступной функции. Это такая же абстракция данных, как, например, в C, которая не имеет первоклассных представлений о том, что является публичным или частным.
Люк Дантон

1
@ SK-logic: С точки зрения «проблемы с выражением», раскрытие данных хорошо, когда вы хотите расширить с помощью новой функции в будущем (и все в порядке с сохранением фиксированных данных), и скрытие данных хорошо, когда вы хотите дополнить новыми типами данных в будущем (за счет сохранения
исправного

Ответы:


23

Упомянутая вами статья посвящена модульности в целом и в равной степени относится к структурированным, функциональным и объектно-ориентированным программам. Ранее я слышал об этой статье от кого-то, кто был большим парнем из ООП, но я прочитал ее как статью о программировании в целом, а не как оОП-специфичную. Есть известная статья о функциональном программировании, Почему функциональное программирование имеет значение , и первое предложение заключения гласит: «В этой статье мы утверждали, что модульность является ключом к успешному программированию». Таким образом, ответ на (1) - нет.

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

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

Изменить: я нашел соответствующую цитату из интервью с Рич Хикки .

Fogus: Следуя этой идее, некоторые люди удивляются тому факту, что Clojure не занимается скрытием данных в своих типах. Почему вы решили отказаться от сокрытия данных?

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


2
ОО программисты не хотят, чтобы все было объектом. Но некоторые вещи (многие вещи) выигрывают от инкапсуляции. У меня проблемы с пониманием того, как или где ваш ответ действительно отвечает на вопрос. Кажется, просто утверждается, что концепция не является специфичной для ООП, и что у ООП есть другие проблемы и так далее, и так далее - можете ли вы привести четкий пример, даже если это всего лишь несколько строк псевдокода? Или описание дизайна доски, которое учитывает это? Или что-нибудь, что обосновало бы утверждения здесь?
Aaronaught

2
@Aaronaught: я обратился ко многим (хотя и не ко всем) вопросам, поднятым в вопросе, и сослался на статью о функциональном программировании, которая рассматривает модульность аналогично статье в вопросе. В значительной степени тот факт, что концепция не является специфической для ООП, является ответом на его вопрос (если я не понял вопрос полностью). Я действительно не говорил о том, что у ООП есть другие проблемы здесь. У вас есть хорошая точка зрения о предоставлении примера; Я посмотрю, смогу ли я найти хороший.
Майкл Шоу

2
«Иногда простая структура данных - это все, что вам нужно». +1 Что-то ООП имеет смысл, иногда это FP.
Лоран Бурго-Рой

1
@Aaronaught Этот ответ указывает на то, что модульность (которая является как инкапсуляцией, так и повторным использованием) является одной из целей FP (как обсуждалось в разделе «Почему имеет значение функциональное программирование»), что делает ответ на пункт (1) вопроса « нет».
Андрес Ф.

2
@JimmyHoffa сокрытие информации - нормальный принцип даже вне ОО. В haskell я все еще хочу, чтобы пользователям было разрешено работать с минимальным количеством знаний о любой структуре данных. Конечно, доступ к внутренним объектам менее опасен, потому что ничто не изменчиво. Но чем меньше пользователь видит один модуль / структуру данных / любую абстрактную концепцию, тем больше у вас возможностей для рефакторинга. Меня не волнует, является ли Карта сбалансированным бинарным деревом или мышью в небольшом окне на моем компьютере. Это основная мотивация сокрытия данных, и она действительна вне ОО.
Саймон Бергот

12

... и, вероятно, одна из тех статей, на которых основывалось ООП.

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

Сначала я хочу знать, правильна ли моя оценка. Парадигма FP и эта статья философски не согласны?

Нет. Более того, на мой взгляд, ваше описание того, как выглядит FP-программа, ничем не отличается от любого другого, использующего процедуры или функции:

Данные передаются от функции к функции, каждая функция тщательно осведомлена о данных и «меняет их» на своем пути.

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

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

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

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

РЕДАКТИРОВАТЬ

Растет число утверждений о том, что «сокрытие данных» в контексте FP не так полезно (или ООП-иш (?)). Итак, позвольте мне напечатать здесь очень простой и понятный пример из SICP:

Предположим, что ваша система должна работать с рациональными числами. Один из способов их представления - это пара или список из двух целых чисел: числителя и знаменателя. Таким образом:

(define my-rat (cons 1 2)) ; here is my 1/2 

Если вы игнорируете абстракцию данных, скорее всего вы получите числитель и знаменатель, используя carи cdr:

(... (car my-rat)) ; do something with the numerator

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

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

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

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

  • (make-rat <n> <d>)возвращает рациональное число, числитель которого является целым числом, <n>а знаменатель - целым числом <d>.

  • (numer <x>)возвращает числитель рационального числа <x>.

  • (denom <x>)возвращает знаменатель рационального числа <x>.

и система больше не будет (и не должна) знать, из чего сделаны рациональные решения. Это происходит потому cons, carи cdrне присущи рациональные числа, но make-rat, numerи denom это . Конечно, это может быть система FP. Таким образом, «сокрытие данных» (в данном случае более известное как абстракция данных или попытка инкапсулировать представления и конкретные структуры) представляет собой актуальную концепцию и метод, широко используемый и исследуемый, будь то в контексте ОО, функционального программирования или без разницы.

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

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

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


Я согласен, что сокрытие данных имеет отношение к FP. И, как вы говорите, есть способы достичь этого.
Андрес Ф.

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

8

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

map :: (a -> b) -> [a] -> [b]
map _ [] = []
map f (x:xs) = f x : map f xs

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

Функция, переданная в качестве аргумента, аналогична общедоступному методу для типа данных, который содержится в списке. Он предоставляет ограниченный способ работы с данными, но не раскрывает внутреннюю работу типа данных.


5

Я собираюсь нанести удар по конечности и сказать, что концепция в ФП не так важна, как в ОО.

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


По моему опыту с FP; которые, по общему признанию, незначительны, я склонен находить резкий контраст с ОО в том, что обозначает хорошее / общее моделирование данных.

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

OO

  • У вас есть автомобильный объект, который правильно скрывает детали об автомобиле, такие как реализация переменного тока (с ременным приводом или с пневматическим приводом? Потребителям не нужно знать, поэтому скрывайте это).
  • Этот автомобильный объект имеет множество свойств и методов, которые разграничивают все факты об автомобиле, а также способы, которыми вы можете работать с автомобилем.
  • Этот автомобильный объект обладает свойствами, которые являются компонентами автомобиля, которые в дальнейшем скрывают от всего автомобиля свои конкретные реализации и фактические данные, позволяющие компонентам автомобиля быть взаимозаменяемыми.

Здесь следует обратить внимание на то, что когда вы моделируете вещи в формате ОО, все сводится к представлению вещей как данных. У вас есть объекты со свойствами, многие из которых являются объектами с большим количеством свойств. У вас есть несколько методов, привязанных к этим объектам, но все, что они на самом деле делают, - это обычно изменяют свойства объектов таким образом, и это опять-таки очень ориентированное на данные моделирование; то есть вы моделируете свои данные для взаимодействия с ориентацией на их структурирование, чтобы сделать доступными все точки ваших данных, чтобы потребители могли так или иначе изменять данные.

FP

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

Большая разница между OO и FP, которая постоянно поражает меня, заключается в том, как я говорил выше, как вы моделируете данные. В ОО, как упоминалось выше, вы моделируете данные как данные, в ФП вы моделируете данные в виде вычислений, выражений, алгоритмов, это больше о моделировании действий ваших данных, чем о фактах. Подумайте о базовом моделировании данных в математике, это всегда о получении уравнения, которое может генерировать ваши данные, которое моделирует ваши данные как деятельность, которая их вызывает, в отличие от ОО, моделирование предлагает способ представления данных, которые у вас есть. Это большая часть различия между FP и OO.

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

Когда я начинаю писать некоторый код на FP, я начинаю с написания кода, который что-то делает, тогда как, когда я начинаю писать код в ОО, я начинаю с написания моделей, которые что-то описывают. Действие вещей скрыто в ФП как выражение, а действие дел раскрывается в ОО путем описания с данными, скрывая эти данные, ограничивая указанную экспозицию.


Возвращаясь к рассматриваемому вопросу, что FP говорит о сокрытии данных, оценивает это или не соглашается с этим или нет?

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


это великолепно, мне очень понравилось это читать. Спасибо за ваш вклад
Крис Макколл

5

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

Как это так? Подумайте о хорошем интерфейсе OO, который скрывает лежащие в основе данные - возможно, коллекции (я пытаюсь выбрать что-то почти вездесущее). Вам может не потребоваться знать базовый тип объектов в коллекции или тип объекта, реализующего коллекцию, если вы знаете, что коллекция реализует, скажем, IEnumerable. Итак, у вас есть данные, скрывающиеся.

В функциональном программировании вы можете написать функцию, которая эффективно работает с интерфейсом IEnumerable, но работает с примитивным типом данных (или с любым типом данных). Но что, если тип никогда не реализует методы IEnumerable? Вот ключ, вы всегда можете иметь «методы», которые формируют необходимые части «интерфейса», которые будут передаваться в вашу функцию. Или вы можете объединить функции с данными и сделать что-то вроде OO.

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

Итак, что касается вашего пункта 1, я не думаю, что FP и статья действительно не согласны. Я не думаю, что ваша характеристика FP, не скрывающая данные, верна. Конечно, можно реализовать дизайн, который автор предпочел в FP.

Что касается пункта 4 (2 и 3 не имеет смысла отвечать, учитывая то, что я сказал для пункта 1), то это меняется. Это также варьируется в ОО-языках, и во многих частных полях, согласно соглашению, является закрытым, а не обязательным для языка.


Другими словами: в функциональном программировании гораздо больше «скрыто» по умолчанию просто потому, что его даже не существует! Единственное, что вы явно вводите в сферу действия, является «скрытым»
оставлено около

3

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

Сначала я хочу знать, правильна ли моя оценка. Парадигма FP и эта статья философски не согласны?

Проектирование FP очень сильно фокусируется на потоке данных (что, на мой взгляд, не так плохо, как может подразумеваться в статье). Если это полное «разногласие», то можно поспорить.

Предполагая, что они не согласны, как FP "компенсирует" отсутствие скрытия данных? Возможно, они жертвуют сокрытием данных, но получают X, Y и Z. Я хотел бы знать причину, почему X, Y и Z считаются более выгодными, чем сокрытие данных.

ИМХО это не компенсирует. Увидеть ниже.

Или, если они не согласны, возможно, FP считает, что сокрытие данных - это плохо. Если так, почему он считает, что сокрытие данных плохо?

Я не думаю, что большинство пользователей или дизайнеров FP чувствуют или думают таким образом, см. Ниже.

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

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

Таким образом, для создания больших систем, IMHO, вы можете создавать модули, классы и объекты, используя концепции ОО, точно так же, как описано в разделе «Модуляризация 2» в статье, не выходя из «пути FP». Вы будете использовать концепцию модуля вашего любимого языка FP, сделайте неизменными все ваши объекты и используйте «лучшее из обоих миров».


3

TL; DR : нет

Парадигма FP и эта статья философски не согласны?

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

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

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

Скрытие данных

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

3
«Функциональное программирование не имеет мутирующих данных, поэтому ему не нужно столько скрывать данные». - это очень вводящее в заблуждение утверждение. Вы сами сказали (и я согласен), что одной из причин инкапсуляции поведения является контроль над мутацией данных. Но сделать вывод о том, что отсутствие мутации практически делает инкапсуляцию бесполезной, - это огромный шаг. ADT и абстракция данных в целом широко распространены в литературе и системах FP.
Тьяго Силва

Я никогда не говорил, что «это делает инкапсуляцию практически бесполезной». Это твои мысли и твои одни. Я сказал, что вам не нужно так много скрывать данные из-за отсутствия мутирующих переменных. Это не делает бесполезным инкапсуляцию или сокрытие данных, а только сокращает их использование, потому что такие случаи не существуют. Все остальные случаи, в которых сокрытие данных и инкапсуляция полезны, остаются в силе.
dietbuddha
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.