Абстракция против инкапсуляции в Java

Возможный дубликат:
Абстракция VS Скрытие информации VS Инкапсуляция

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

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

Что я понял из приведенного выше определения, так это то, что создаем переменные, помечаем их как частные и генерируем getter-setter для этих переменных и используем объект для доступа к этим getter и setter. Таким образом, данные скрыты внутри объекта и доступны только через объект. Надеюсь, я прав.


Абстракция - это процесс в Java, который используется, чтобы скрыть определенные детали и показать только основные свойства объекта. Другими словами, это касается внешнего вида объекта (интерфейса).

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

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

Ответ 1

OO Abstraction возникает во время разработки уровня класса с целью скрывать сложность реализациинасколько понятны функции, предлагаемые API/дизайном/системой, в некотором смысле упрощая "интерфейс" для доступа к базовой реализации.

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

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

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

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

Например, по умолчанию поля классов могут быть сделаны private, и только если требуется внешний доступ к ним, будет ли отображаться get() и/или set() (или Property) из класс. (В современных языках OO поля могут быть помечены как readonly/final/immutable, что дополнительно ограничивает изменение даже внутри класса).

Пример, где НЕТ скрытия информации было применено (Плохая Практика):

class Foo {
   // BAD - NOT Encapsulated - code external to the class can change this field directly
   // Class Foo has no control over the range of values which could be set.
   public int notEncapsulated;
}

Пример применения инкапсуляции полей:

class Bar {
   // Improvement - access restricted only to this class
   private int encapsulated;

   // The state of Bar (and its fields) can now be changed in a controlled manner
   public void setEncapsulatedField(int newValue) {
      if (newValue < 100) {
          encapsulated = newValue;
      }
      // else throw ... out of range
   }
}

Пример инициализации неизменяемого/конструкторного поля:

class Baz {
   private final int onlyValue;

   public void Baz(int immutableValue) {
      // ... can check that immutableValue is valid
      onlyValue = immutableValue;
   }
   // Further change of `onlyValue` outside of the constructor is NOT permitted
    // even within the same class 
}

Re: Абстракция против абстрактного класса

Абстрактные классы - это классы, которые способствуют повторному использованию общности между классами, но которые сами не могут быть непосредственно созданы с помощью new() - абстрактные классы должны быть подклассы, и могут быть созданы только concrete (не абстрактные) подклассы. Вероятно, одним из источников путаницы между Abstraction и abstract class было то, что в первые дни OO наследование было более активно использовано для повторного использования кода (например, с ассоциированными абстрактными базовыми классами). В настоящее время композиция encapsulation обычно используется в более общем смысле при определении того, какие методы, поля, свойства, события и др. bundle в класс.

Цитата из Википедии:

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

Например, в заявлении "Я инкапсулировал код доступа к данным в свой собственный класс", интерпретация инкапсуляции примерно эквивалентна Разделение Обеспокоенность (S в SOLID) и, возможно, может использоваться как синоним рефакторинга.


[1] Как только вы увидите Booch инкапсулирование изображения кошки, вы никогда не сможете забыть инкапсуляцию - p46 объектно-ориентированного анализа и проектирования с приложениями,  2nd Ed

Ответ 2

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

Ответ 3

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

например. У меня может быть класс Vehicle. A Car будет выводиться из a Vehicle, как и a Motorbike. Я могу задать каждый Vehicle количество колес, пассажиров и т.д., И эта информация была абстрагирована и идентифицирована как обычная от Cars и Motorbikes.

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