Задача ООП: 1) Локализовать изменения состояния объекта (инкапсуляция); 2) связывать разные кирпичики данных через стандартные интерфейсы (полиморфизм).
Простейший тетрис не слишком велик, чтобы его писать на чистом ООП.
Но представьте себе, мы начинаем налаживать настраиваемое управление джойстиком или клавиатурой. И тогда у нас появляется такой код.
enum {
BT_LEFT = 1,
BT_RIGHT = 2,
BT_ROTATE = 4,
BT_SOFTDROP = 8,
BT_HARDDROP = 16,
BT_PAUSE = 32,
BT_CONNECTED = 32768, // бит, указывающий, что контроллер подключён
};
class Controller { // интерфейс
public:
virtual unsigned poll() const = 0; // сочетание битов BT_XXX
virtual ~Controller = default;
};
Классы Keyboard и Joystick поддерживают интерфейс Controller, и подмена клавиатуры на джойстик и наоборот ничего не изменит.
Вот вам полиморфизм.
Текстовый редактор превращаем в многооконный — берём класс Editor и пристраиваем его не к программе в целом, а к MDI-окошку. Вот вам инкапсуляция — локализованное изменение состояния.
Я как-то мучил движок Doom. Он написан в самом настоящем объектном стиле на чистом Си! Хотя и там были проблемы: сетевой код был куда хуже по качеству, чем сам движок. Писали разделённый экран, глобальную переменную netgame разделили на две, multiplayer и netgame и долго-долго правили баги, где multiplayer, где netgame (было дело, участник десматча ввёл IDKFA, это сработало и вызвало рассинхронизацию). А код пользовательского интерфейса — вообще медвежуть!