Когда я, так сказать, прошёлся по Интернету, я заметил одну интересную особенность. Все парадигмы программирования, где-либо обсуждаемые, воспринимаются людьми совершенно спокойно. Если, например, говорят про процедурное программирование, то говорят про него абсолютно спокойно. То же самое — про модульное программирование. Декларативное программирование — никаких бурь, волнений или холиваров. Функциональное программирование — то же самое.

И только вокруг ООП не утихают бури. Одни визжат от него в восторге, другие, наоборот, хаят на чём свет зиждется. И мне, честно сказать, совершенно непонятно, почему на ООП весь мир клином сошёлся.

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

Я же хочу именно привнести третий элемент. Спокойно, без хайпа и ругани рассказать, почему ООП — не эликсир от всех болезней, но также, как и ПП, ФП или ЛП имеет право на существование.

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

1. Всё, что есть в ООП, уже давно есть в других парадигмах


Почти все языки программирования являются тьюринг-полными, за исключением языков разметок, как то: HTML, XML, CSS и т.д. Если говорить крестьянским языком, тьюринг-полный язык — язык, на котором можно написать абсолютно любую мыслимую программу. Из этого следует довольно-таки всеобщий тезис: то, что есть в любом наудачу выбранном языке, есть во всех остальных языках. То же можно сказать и про парадигмы. Все отличия языков (и парадигм) — это разные способы реализации тех или иных команд, не считая отдельных лексических особенностей.

Кстати, этот же тезис (всё, что есть в N, есть и в M, и в K, и в R и т.д.) можно сформулировать так: молоток уже состоит из железа да дерева, зачем же нам ещё и пассатижи? Но ведь так никто не станет утверждать.

2. ООП смешивает данные и действия над ними. Это плохо


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

3. Наследование закрепощает программу, делает трудным внесение изменений


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

Если не предполагается расширять родительский класс третьим классом — такое наследование попросту бессмысленно. Если вы создаёте магазин спиртных напитков, то классы Beer, Vodka и Vine можно унаследовать от класса Alcohol, но совершенно не нужно создавать ещё и класс Drinks, если только вы не хотите продавать ещё и, скажем, парагвайский чай.

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

4. Инкапсуляция не имеет смысла


Вот тут я частично согласен. С точки зрения работы программы инкапсуляция действительно ни на что не влияет. Если я закрою переменную с помощью private — ну и что, я всё равно смогу её открыть, просто убрав private, а потом менять там всё, что душе заблагорассудится.

Но это верно лишь чисто технически. Философия ООП гласит: правильно организованный и инкапсулированный класс можно рассматривать как чёрный ящик. Представьте себе коробку, на одной стороне которой разнообразные кнопки, слоты для подачи данных, а на другой — выходной слот, который возвращает информацию. Возьмём, к примеру, стек. Представьте коробку, на одной стороне которой есть один слот для вставки данных и кнопка push рядышком. На обратной стороне — кнопка pop. Вы подаёте туда записку с числом 8 и давите кнопку push. Затем подаёте ещё бумажку и второй раз давите push. И так N раз, а затем жмёте pop. Из ящика вылетает бумажка с числом 76 (или другое, в общем, то, которое вы подали). Нужно ещё число? Второй раз давите pop. И так до морковкина заговенья тех пор, пока ящик не опустеет. А если вы продолжите давить pop, механизм из ящика завоет: стек пуст! Именно так и выглядит объект.

Но пос��е того, как вы создали и настроили класс, вам уже фиолетово, как он там работает — он просто правильно работает, а большего и желать не нужно. А инкапсулируя все эти структуры, вы не держите всё подряд в памяти. Они (множество ящиков) просто общаются между собой так, как вы настроите.

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

Хотя, вряд ли это «увы» здесь вообще уместно.

5. В реальном мире нет иерархий отношения, повсюду лишь иерархии включения


Да разве? Но ведь никто не мешает создать, например, иерархию, где все реки мира (Конго, Сена, Темза, Амазонка, Колыма и т.д.) являются объектами одной всеобъемлющей «Реки», которой присущи свойства (например, состоит из воды) и действия (например, течёт), а уже она будет наследоваться от «Водоёма», который тоже состоит из воды, а от «Водоёма» можно унаследовать ещё и «Озеро», объектами которого будут отдельные озёра (Байкал, Каспийское море, Титикака и т.д.). Схема довольно грубая. Но иерархии отношения — это тоже абстракция. Что-то а-ля платоновской идеи, если хотите. В реальном мире их нет, они существуют только в уме, это обобщение, и не более того. Но ведь именно так человек очень часто мыслит. Мы ведь можем сказать «носок», без уточнения, каков у него цвет, из какого материала соткан и т.д., но существует ли этот «носок» в действительности?

И всё же нас не должно смущать, что нет ни «объекта», ни «носка».

6. Методоло��ия ООП изначально ошибочна


Абсолютно необоснованный аргумент. ООП создавалось для того, чтобы моделировать своеобразный виртуальный мир, состоящий из объектов, как и наш мир. Например: человек — объект из реального мира. Он может ходить, бегать, кушать, срать спать, играть в футбол, смотреть футбол, но, к сожалению, я тут не могу всё перечислить, да и, честно сказать, всё перечислять было бы противно. Этот же самый человек обладает свойствами: наличие/отсутствие волос, цвет волос, если они есть, цвет глаз, если они есть цвет кожи, количество пальцев на руках и т.д. Если правильно сконструировать все поля и методы, как я уже писал выше, то программный объект сможет моделировать те или иные свойства реального объекта. Человек очень даже хорошо мыслит в таких категориях — именно поэтому ООП и стало распространённым. Оно очень помогает при написании больших проектов, так как привносит модульность и позволяет разбивать программный пакет на отдельные компоненты, взаимодействующие друг с другом.

7. Но даже миллионы мух не убедят нас, что навоз — это вкусно


Самый популярный аргумент против ООП. Мол, массы в большинстве своём глупы (всё же я не думаю, что это относится и к программистам), бегают по «модным шмоткам» и восхищаются ими.
Но задумайтесь, а если бы на пьедестал взошло не ООП, а, скажем, ЛП? Думаете, было бы всё по-другому? Ничего подобного! Нашлись бы и фанаты, и злостные противники, а на ООП смотрели бы как на инструмент (к этому я, вообще-то, и призываю), а не как на таблетку, сотворённую самим Богом и потому незаменимую.



Почему эта статья — в защиту ООП?


Все современные разговоры про парадигмы программирования, как мне видится, сводятся к двум диаметральным посылкам: оставим ООП и выкинем всё остальное, или же выкинем ООП и… ну, вы поняли меня.

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

Если вам не нравится ООП


Кому — ООП, кому — ФП, кому — ПП. А кому-нибудь, может быть, вообще более всего мил свиной хрящик. Если вы не любите кошек — наверное, вы просто не умеете их готовить.