Блуждая по интернету, можно заметить одну интересную особенность. Все парадигмы программирования воспринимаются людьми совершенно спокойно. Про процедурное программирование говорят спокойно и про модульное. Декларативное программирование — никаких бурь, волнений или холиваров. Функциональное — то же самое. И только вокруг ООП не утихают бури. Одни визжат от него в восторге, другие, наоборот, хаят.
И, честно сказать, совершенно непонятно, почему на ООП весь мир клином сошелся.
Если показалось, что я — скорее противник, чем сторонник ООП, то это не так (впрочем, это можно понять по заголовку). Я скорее противник «серебряных пуль», хайпа, возведения какой-либо методологии или человека на престол и всяческого вождения хороводов.
Вы же не водите хороводы вокруг, скажем, гаечного ключа или газонокосилки. И не пишете, я надеюсь, публикаций, почему дрель или молоток — отстой.
Но сегодня день весь интернет кишит именно напыщенными, гиперэмоциональными, радикалистскими статьями по поводу ООП. Если один говорит, что ООП — «зер гут» и вообще всем гутам гут — то другой обязательно вещает, что ООП необходимо срочно выкинуть на помойку. Третьего не дано.
Я же хочу именно привнести третий элемент. Спокойно, без хайпа и ругани рассказать, почему ООП — не эликсир от всех болезней, но также, как и ПП, ФП или ЛП имеет право на существование.
Итак, спокойная статья про ООП рабоче-крестьянским языком. В ней я попытаюсь рассмотреть основные доводы противников ООП и обосновать их несостоятельность.
Почти все языки программирования— тьюринг-полные, за исключением языков разметок: HTML, XML, CSS и т.д.
Если говорить крестьянским языком, тьюринг-полный язык — на котором можно написать абсолютно любую программу. Из этого следует довольно-таки всеобщий тезис: то, что есть в любом выбранном языке, есть во всех остальных языках.
То же можно сказать и про парадигмы. Все отличия языков (и парадигм) — это разные способы реализации тех или иных команд, не считая отдельных лексических особенностей.
Кстати, этот же тезис (все, что есть в N, есть и в M, и в K, и в R и т.д.) можно сформулировать так: молоток уже состоит из железа и дерева, зачем же нам еще и пассатижи? Но ведь так никто не станет утверждать.
Аргумент высосан из пальца. Во-первых, где ООП смешивает данные и функции? Во-вторых, утверждение, что это плохо, тоже взято от фонаря. Из бочки «настоящий мужик так не делает», а почему — да потому, что гладиолус.
ООП в каком-то роде моделирует реальный мир, где данные присущи объекту — никто ведь не станет утверждать, что у стула отсутствует цвет, и у него не четыре ноги.
И никаких смешений данных и операций здесь не происходит, объект — это не функция и не оператор. Это абстракция.
Тут нужно немного притормозить. Наследование вовсе не предполагает выстраивание километровых деревьев с целью замедлять разработку. Наследование придумано для того, чтобы выделять общие свойства и методы в суперкласс, причем делать это нужно с классами, представляющими однотипные объекты. Ошибкой будет создавать, например, два класса, один из которых — наследник другого, ибо здесь нет выделения общего кода в суперкласс просто потому, что здесь нет ничего общего.
Если не предполагается расширять родительский класс третьим классом — такое наследование попросту бессмысленно. Если вы создаете магазин спиртных напитков, то классы Beer, Vodka и Vine можно унаследовать от класса Alcohol, но совершенно не нужно создавать еще и класс Drinks, если только вы не хотите продавать еще, скажем, парагвайский чай.
Также ошибкой будет создание иерархий, в которых классы никак не относятся друг к другу.
Ну зачем, расскажите мне, городить башню, где классы «Муха» и «Котлета» наследуются от суперкласса «Сыр», который, в свою очередь, наследуется от суперкласса «Пятница»?! Но это уже не недостаток ООП, а кривые руки того, кто такое сочиняет.
Вот тут я частично согласен. С точки зрения работы программы инкапсуляция действительно ни на что не влияет. Если я закрою переменную с помощью private
— ну и что, я все равно смогу ее открыть, просто убрав private
, а потом менять там все, что душе заблагорассудится.
Но это верно лишь чисто технически.
Философия ООП гласит: правильно организованный и инкапсулированный класс можно рассматривать как черный ящик.
Представьте себе коробку, на одной стороне которой разнообразные кнопки, слоты для подачи данных, а на другой — выходной слот, который возвращает информацию. Возьмем, к примеру, стек. Представьте коробку, на одной стороне которой есть один слот для вставки данных и кнопка push рядышком. На обратной стороне — кнопка pop. Вы подаете туда записку с числом 8 и давите кнопку push. Затем подаете еще бумажку и второй раз давите push. И так N раз, а затем жмете pop. Из ящика вылетает бумажка с числом 76 (или другое, в общем, то, которое вы подали). Нужно еще число? Второй раз давите pop. И так до тех пор, пока ящик не опустеет. А если вы продолжите давить pop, механизм из ящика завоет: стек пуст! Именно так и выглядит объект.
Но после того, как вы создали и настроили класс, вам уже фиолетово, как он там работает — он просто правильно работает, а большего и желать не нужно. А инкапсулируя все эти структуры, вы не держите все подряд в памяти. Они (множество ящиков) просто общаются между собой так, как вы настроите.
Инкапсуляция — своеобразный костыль, поддерживающий сотню столпов вашей программы в то время, пока вы конструируете сто первый. В крупных проектах (а именно для их создания и придумали ООП) без этого, увы, никак.
Хотя вряд ли это «увы» здесь вообще уместно.
Да разве? Но ведь никто не мешает создать, например, иерархию, где все реки мира (Конго, Сена, Темза, Амазонка, Колыма и т.д.) — объекты одной всеобъемлющей «Реки», которой присущи свойства (например, состоит из воды) и действия (например, течет), а уже она будет наследоваться от «Водоема», который тоже состоит из воды, а от «Водоема» можно унаследовать еще и «Озеро», объектами которого будут отдельные озера (Байкал, Каспийское море, Титикака и т.д.).
Схема довольно грубая. Но иерархии отношения — это тоже абстракция. Что-то вроде платоновской идеи, если хотите. В реальном мире их нет, они существуют только в уме, это обобщение, и не более того. Но ведь именно так человек очень часто мыслит. Мы ведь можем сказать «носок», без уточнения, каков у него цвет, из какого материала соткан и т.д., но существует ли этот «носок» в действительности?
И, все же, нас не должно смущать, что нет ни «объекта», ни «носка».
Абсолютно необоснованный аргумент. ООП создавалось для того, чтобы моделировать своеобразный виртуальный мир, состоящий из объектов, как и наш мир. Например: человек — объект из реального мира. Он может ходить, бегать, кушать, спать, играть в футбол, смотреть футбол, но, к сожалению, я тут не могу все перечислить, да и, честно сказать, все перечислять было бы противно.
Тот же самый человек обладает свойствами: наличие/отсутствие волос, цвет волос, если они есть, цвет глаз, цвет кожи, количество пальцев на руках и т.д. Если правильно сконструировать все поля и методы, как я уже писал выше, то программный объект сможет моделировать те или иные свойства реального объекта.
Человек очень даже хорошо мыслит в таких категориях — именно поэтому ООП и стало распространенным. Оно очень помогает при написании больших проектов, так как привносит модульность и позволяет разбивать программный пакет на отдельные компоненты, взаимодействующие друг с другом.
Самый популярный аргумент против ООП. Мол, массы в большинстве своем глупы (все же, я не думаю, что это относится и к программистам), бегают по «модным шмоткам» и восхищаются ими.
Но задумайтесь, а если бы на пьедестал взошло не ООП, а, скажем, ЛП? Думаете, было бы все по-другому? Ничего подобного! Нашлись бы и фанаты, и злостные противники, а на ООП смотрели бы как на инструмент (к этому я, вообще-то, и призываю), а не как на таблетку, сотворенную самим Богом и потому незаменимую.
Все современные разговоры про парадигмы программирования, как мне видится, сводятся к двум диаметральным посылкам: оставим ООП и выкинем все остальное, или же выкинем ООП и… ну, вы поняли меня.
Я не хочу, чтобы вполне годную парадигму посчитали достойной свалки, но я и не хочу, чтобы вокруг нее водили хороводы, а все остальное забыли. Я думаю, что второе сделать проще, а против первого и направлена эта статья.
Кому — ООП, кому — ФП, кому — ПП. А кому-нибудь, может быть, вообще более всего мил свиной хрящик. Если вы не любите кошек — наверное, вы просто не умеете их готовить.
Читайте также: Некоторые языки уродуют разум: как программирование на самом деле влияет на ваш мозг
Это текст из личного блога, опубликованный с разрешения автора.
В благословенные офисные времена, когда не было большой войны и коронавируса, люди гораздо больше общались…
Вот две истории из собственного опыта, с тех пор, когда только начинал делать свою карьеру…
«Ты же программист». За свою жизнь я много раз слышал эту фразу. От всех. Кто…
Отличные новости! Если вы пропустили, GitHub Copilot — это уже не отдельный продукт, а набор…
Несколько месяцев назад мы с командой Promodo (агентство инвестировало в продукт более $100 000) запустили…
Пару дней назад прочитал сообщение о том, что хорошие курсы могут стать альтернативой классическому образованию.…