Объектно-ориентированное программирование, наверное, самая популярная парадигма из всех ныне существующих. В топах популярных языков лидируют именно объектно-ориентированные языки, то есть Java, C#, Python, C++. Всё вроде бы классно, объекты есть, классы есть, да и жизнь цветёт другими красками. Однако, почему иногда складывается ощущение, что мы просто привязываем процедуру к какому-то классу? Мы что-то делаем не так?
Суть проблемы
Допустим, была у нас процедура print(String arg)
, которая выводила на экран переданное ей значение. А мы взяли, да создали класс InputOutput
и сделали нашу процедуру методом. Есть кардинальные отличия? Нет. И даже известно почему.
Причины проблемы
Отношение к объектам
С этого и стоит начать. Чем для начинающего программиста в ООП являются объекты? Тем же, чем и для Википедии, набором именованных свойств, которые можно удалять, добавлять, изменять, или вообще ничего с ними не делать. В большинстве своём из этого и вытекают следующие далее причины. Объект — не просто набор каких-то там свойств. Точнее, так и есть, но к объекту нужно относиться как к "живой" сущности. Мы не вызываем метод, мы "вежливо просим объект сделать это". Мы не можем просто так взять и начать выполнять манипуляции со свойствами объекта, так как это только его свойства, мы не можем узнать, что у него "внутри", ибо это его личное дело. Если мы изменим какое-то свойство у объекта, он уже перестанет быть тем, чем был раньше. Разве это можно хотя бы приблизительно назвать "живой" сущностью? Скорее, какой-то конструктор LEGO.
Getters, setters, публичные свойства
Вот это именно то, о чём я и говорил.
// C#
class Person {
public string Name {
get {
return name;
}
set {
name = value;
}
}
}
Свойства объекты концептуально не могут быть публичными, это нарушает правило инкапсуляции. Если свойства публичны, то мы имеем не "мыслящий" объект, а глупую структуру данных, которая может только сохранять в себе информацию. Объект должен в себе что-то инкапсулировать. Если он задумался каким-то — пусть он таким и остаётся, это его личное пространство и распоряжаться им может только он в своих методах.
В некоторых языках программирования эту проблему попытались решить, введя data objects, дабы отделить "правильные" объекты от глупых структур данных. Иногда приходится делать и такое. К примеру, Kotlin:
// Kotlin
data class Person(val name: String) {
var age: Int = 0
}
Помимо сахара в виде ключевого слова data
такие объекты имеют некоторые ограничения и специфичные им методы.
Static методы
Это то, о чём я говорил в начале.
Статические методы это методы, которые не привязаны к конкретному экземпляру объекта.
Мы просто вставили нашу процедуру в объект, и всё. Эта функция не использует свойства объекта, можно даже экземпляр не создавать. Должен сказать, что такое бывает полезно, если нужно вынести функции в модули. Однако это модули, а не объекты. Мы же хотим ООП, а не процедурное программирование?
// Java
class Program {
public static void main(){
/* Точка входа main() вынуждена являться статической */
System.out.println("hello");
}
}
NULL
Тоже своего рода проблема. Язык Kotlin, к примеру, пытается с ней бороться. Но полностью, этого, конечно, не сделаешь, поэтому тип Null
в этом языке тоже есть. Однако его следует избегать в ООП. Метод не должен быть процедурой. Если он ничего не возвращает, то он должен хотя бы что-то инкапсулировать. К примеру:
# Python
# Метод достаёт из БД имя и обновляет его в соответствующем свойстве.
# ВАЖНО: НЕ МЫ ОБНОВЛЯЕМ, А САМ МЕТОД!
# Мы не передаем параметр, а объект сам понимает, что ему делать.
class User:
def update_name(self):
# ... some code ... #
self.name = name
И ещё не нужно пытаться возвращать свойства объекта, так как свойства нельзя использовать извне.
Надеюсь, что я объяснил хоть немного приемлемо, потому что тема специфичная, в самый раз для каверзных вопросов мне и хорошего такого холивара. Подводя итог, выделю самое важное:
- Объект должен быть похож на "живую" сущность;
- Мы "обращаемся, просим" объект сделать что-то;
- Свойства объекта — исключительно его собственность;
- Статические методы — зло;
Ну и цель у этого действа тоже должна быть. Наверняка уже у некоторых был вопрос, мол, мне и так нормально живётся с публичными свойствами и статическими методами, зачем мне это вообще нужно?
Проектировать архитектуру объектов нужно так, чтобы не брать всю обязанность на себя, как в процедурном программировании. Мы должны доверять объекту, знать, что если он сейчас "Вася", то он и в будущем будет "Васей"; если его метод сейчас возвращает "привет", то и в будущем он будет возвращать "привет".
Почти на пальцах объяснил. Спасибо за то, что дочитали =)
Комментарии (11)
Drag13
29.10.2018 23:11Погодите, как насчет тонких моделей и сервисов которые производят над ними операции, но не имеют внутреннего состояния? Тоже зло?
sentyaev
30.10.2018 02:54как насчет тонких моделей и сервисов которые производят над ними операции
Ну так это и называется «процедурное программирование».
vintage
30.10.2018 00:16+1Поднимемся же на борьбу с объективацией!
А если серьёзно, то вы безапелляционно заявляете довольно сомнительные вещи. О чём тут спорить?
evocatus
30.10.2018 00:22Если объект состоит только из свойств, у которых, к тому же прописаны setters и getters, то объект здесь, как мне кажется (и не только мне), вообще не нужен. Просто передавайте данные между функциями.
И вообще: посмотрите, хорошее видео.dopusteam
30.10.2018 08:09Если слишком много параметров, то иногда лучше всё же сделать объект
Другой вопрос, что много параметров — это не есть хорошо, но случаи разные бывают
garex
30.10.2018 03:14Автор, я так и не увидел в статье ничего про элегантные объекты. Как их проектировать?
G1yyK
30.10.2018 07:12И что делать теперь с этой информацией?
Хорошо, сделали мы «элегантные обекты» — а с остальным как жить, выкидывать их, как жить дальше!
Есть мечты, что мир будет идеальным, а есть задачи реального мира.
babylon
30.10.2018 08:42Ещё вопросы.
Если вы можете построить из компонентов объект или, наоборот, разобрать объект на составные части это ооп?
Сколько компонент в таком объекте?
o: { a: { d: 0 }, b: { d: 0 }, c: { d: 0 } }
Влияние пропсов друг на друга и способы изоляции такого влияния.
Свойства объекта — исключительно его собственность;
Вы отказываете пропсам в возможности менять владельца?
Видео как и ваша статья ни о чём.
dididididi
30.10.2018 09:47Никогда не понимал, зачем писать пустые геттеры и сеттеры, а не просто сделать поле публичным.
Djaler
И зачем публиковать избранные тезисы из книги Егора Буганко в виде отдельной статьи?