Страницы

Поиск по вопросам

суббота, 30 ноября 2019 г.

А существует ли инкапсуляция, если есть рефлексия?

#java #cpp #ооп #рефлексия


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


Ответы

Ответ 1



Цель инкапсуляции — подсказка разработчику, чем можно, а чем не стоит пользоваться. Какие данные предназначены для чтения или изменения, а какие вовсе нет. Какие данные являются «контрактом», гарантированы, а какие нет. Что нужно знать об объекте, а на что не тратить серые клетки. Цель инкапсуляции — вовсе не безопасность. Вы не можете защититься таким образом от злонамеренного программиста, который может воспользоваться декомпилятором Java-кода, узнать бинарный layout вашего объекта, и сделать что угодно с ним из нативного кода. Или выполнить reinterpret_cast в C++, и проанализировать, а то и поменять байты вашего объекта. Для защиты от враждебного кода существуют другие средства. В .NET это, например, загрузка его в AppDomain с урезанными правами, в котором запрещена рефлексия, вызов нативного кода и функции наподобие Marshal.Copy.

Ответ 2



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

Ответ 3



Не знаю как в джаве, но в C# для обращения к приватным сущностям, код, использующий рефлексию, должен выполняться с полным доверием (FullTrust). Не разбирался, как оно детально работает, но есть возможность убрать полное доверие для потенциально зловредного кода (например, плагинов). У Эрика Липерта есть несколько постов, касающихся предотвращения злонамеренного воздействия из кода, однако, в тех, которые я читал, уже предполагалось, что тот код не обладает FullTrust-возможностями и пытается "навредить" штатными средствами.

Ответ 4



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

Ответ 5



Про инкапсуляцию и рефлексию ответили достаточно полно, единственное, хотелось бы добавить, что рефлексия - не единственное, чем можно нарушить/обойти инкапсуляцию. Достаточно вспомнить передачу объекта "по ссылке" и "по значению". Давайте рассмотрим простой блок кода: Пусть есть класс A: public class A { private List privateList; public A(List privateList) { this.privateList = privateList; } public List getPrivateList() { return privateList; } } Казалось, бы, все вполне стандартно, но что тут не так? List myList = new ArrayList<>(); myList.add("Меня передадут в коструктор"); A myObj = new A(myList); myList.add("Так мы изменили состояние приватного поля экземпляра класса A"); myList.add("И даже не использовали рефлексию"); myObg.getPrivateList().add("Так тоже меняется приватное поле"); С одной стороны - мы не нарушили принципов инкапсуляции (вызывали только публичные - видимые для нас методы), с другой - состояние приватного поля изменилось. Таким образом, делаем вывод, в полной мере "из коробки" в привычном для нас виде инкапсуляция в Java работает только для неизменяемых (immutable) объектов, таких как примитивы (byte, short, int), строки и т.п. Для изменяемых (mutable) объектов необходимо возвращать их копии. public class A { private List privateList; public A(List privateList) { this.privateList = new ArrayList<>(privateList); } public List getPrivateList() { return new ArrayList<>(privateList); } } Статья по этой теме на DZone: https://dzone.com/articles/encapsulation-i-dont-think-it-means-what-you-think

Комментариев нет:

Отправить комментарий