Введение
Доброго времени суток, читатели.
Данная публикация является средством предоставления доводов в пользу применения такого мощного инструмента в ООП как инкапсуляция. Я знаю, что все нижеописанное уже многокоратно обсуждалось в книгах и интернет-ресурсах. Я просто захотел дополнить эти обсуждения примерами, а также извлечь личную выгоду – систематизация знаний.
Довод 1
Инкапсуляция позволяет предотвратить данные абстракции от нежелательного использования
Иными словами, инкапсуляция ограничивает область видимости данных. Вы можете подумать: “О чем он? Какая еще порча”. Дело в том, что скрывая то, что характеризует/составляет абстракцию мы предотвращаем неправильное использование этих составляющих, что, в свою очередь, помогает избежать окончательной поломки абстракции. А поломка абстракции повлечет за собой неправильную работу системы, в целом.
Пример
Представьте, что у Вас есть устройство под названием “детектор лжи”. Не секрет, что это устройство считывает данные о частоте работы сердца человека, на основани которых можно определить лжет человек или говорит правду. Я не случайно употребил слово “секрет”. Лучше бы факт, того, что детектор лжи использует данные о частоте сердца был скрыт и никогда не разглашался. Зачем? Да потому что “подопытный” может использовать этот факт для того, чтобы подстроиться под работу детектора лжи и манипулировать им так, как ему вздумается. Т.е теперь “подопытный” может натренировать свою частоту сердца так, чтобы она была одинаковой независимо от того лжет он или нет. Как видите система работы дектектора лжи рушиться и теперь абстракция “детектор лжи” бесполезна, потому что неспособна дать ответ лжет человек или нет.
Стив МакКоннел (Steve McConnel) в своей книге “Совершенный код” говорил, что если разрушить инкапсуляцию, то вскоре к ней присоединится и абстракция. Я понимаю, что пример не так хорош как хотелось бы (мир не идеален, что уж), но я надеюсь, что он дает общее представление о том, что может случиться если разрушить абстракцию. Хорошо, двигаемся дальше.
Довод 2
Инкапсуляция формирует абстракцию
Абстракция состоит из связанных между собой низкоуровневых компонент. Они же и характеризуют абстракцию. К примеру, граф – это набор вершин и связей между ними. В данном высказывании фигурируют следующие абстракции:
- Граф
- Вершина
- Связь (т.е ребра)
В данном примере Вершина и Связь образуют низкоуровневую реализацию абстракции Граф. Без инкапсуляции нет смысла создавать абстракцию Граф, состоящую из Вершин и Связей, потому что можно тогда и просто работать с Вершинами и Связями. Можно было бы просто создать коллекцию вершин, задать связи между вершинами и думать об этом наборе как о Графе. Но тогда сложность повысится: придется думать о, если хотите, массиве вершин (или о матрице смежности), о нюансах работы непосредственно с массивом, о возможных ошибках при работе с массивом (выход за пределы массива, например). Этим должны заниматься не мы, разработчики, а абстракция. Не мы должны, в каждый момент времени, думать о массиве. Абстракция пусть делает это за нас.
“Пусть лошадь думает – у нее голова большая”
Применив инкапсуляцию мы не думаем о наборе вершин и связей, мы думаем о Графе.
Пример
Предположим, что Вы, в предновогодней феерии, зашли в супермаркет и накупили множество товаров. Теперь Вам нужно каким-то образом донести эти товары до машины. Конечно, вы могли бы просто взять товары в охапку и просто потащить их к машине, но так вы рискуете уронить на землю шампанское и разбить его, а это недопустимо. Решение заключается в покупке пакета, который вмещал бы себя товары. Теперь Вы понесете в машину не товары, а пакет. Точнее, понесете Вы, конечно, товары, но находятся они в пакете. Купив пакет Вам не нужно опасаться падения шампанского. Этим занимается пакет – он не дает товарам выпасть и разбиться. Вы взяли и инкапсулировали (скрыли) товары в пакете, тем самым абстрагировавшись от способа их хранения и обеспечения безопасности.
Довод 3
Ограничение области предстоящих изменений
На самом деле, этот довод более применим к задачам абстракции, но достигается это путем применения инкапсуляции. Инкапсулировав низкоуровневую реализацию абстракции мы обеспечиваем себе возможность быстрого и безболезненного изменения представляения абстракции.
Пример
Предположим у Вас есть абстракция Граф, которая инкапсулирует структуру данных для хранения вершин и связей между ними. На начальном этапе разработке данной абстракции Вы решили, что для ее представления подойдет матрица смежности. Вы уже реализовали часть интерфейса Графа, протестировали его и поняли, что операции над Графом выполняются медленно, что не соответсвует требованию Вашей системы. Вы решаете поискать другой способ представления и находите таковой – список ребер. Хорошо, а теперь Вам нужно внедрить эту структуру данных в реализацю Графа. И делаете это без проблем – буквально заменяете матрицу смежности на список ребер, меняете детали реализации интерйеса и все работает как и прежде, только лучше. А теперь представьте чтобы было, если бы матрица смежности не была инкапсулирована! Без инкапсуляции матрицу смежности использовал бы не только Граф, а и, например, клиент Графа. Вам пришлось бы блуждать по всему коду приложения и изменять каждую строку кода, которая использует матрицу смежности, а это ненужная потеря времени и денег, а также трата умственных ресурсов.
Итоги:
Инкапсуляция доволняет абстракцию, делая ее более надежной, гибкой, работоспособной, предсказуемой. Я еще неопытный разработчик, поэтому надеюсь на то, что если читатель найдет ошибку в таком описании инкапсуляции, то сообщит о ней и натолкнет на путь исправления этой ошибки. Email: igorastvorov@gmail.com.
Автор: IgorRastvorov