В моей модульной системе управления или точнее движке все построено исключительно на классах. В любой точке кода, в любом месте я могу запустить любой модуль, заставить модуль сделать нужно мне действия, получить какие-либо параметры, результат и т.п. без опасения, что где-то что-то может "наехать" или "изменить текущую работу модуля".
Плюс, конструкторы и наследования упрощают написание всех модулей. Нужно минимум писать "одинакового кода", обеспечивая еще и общую типизацию.
Основной класс - ядро, класс одиночка, запускает всю систему, классы и библиотеки.
Для работы с Отладкой - один класс (на всю систему).
Для работы с СУБД - один класс
Для работы с Шаблонизатором - один класс
Для работы с ЧПУ - свой класс, один.
Для управления модулями и запуска действий из других модулей - один управляющий класс.
Да еще и модули построены на классах. Если будет задача дать другому программисту написать что-то , то он будет делать как привык, ему нужно будет опеспечить лишь точку входа и выхода (а заставить можно абстрактными классами или интерфейсами. Это их одна цель - заставить и рассказать) .
Есть задача - существует один модуль и из него нужно запустить другой модуль (например, сделав какое-либо действие с товаром, нужно запустить модуль билинга и заставить его сделать действие по списанию средств, отослать письмо, уведомить админа и т.п.) достаточно в любой части кода модуля товаров запустить модуль билинга, и сказать ему "иди и спиши с пользователя ID 233 - 100 рублей", модуль билинга обработает данные, пошлет письмо, уведомит админа и так далее, сообщит лишь модулю товаров ответ - успешно или нет, или , код ошибки, например.
Такое построение приложения позволяет расширять, дополнять, удалять части кода без ущерба всей системы.
Каждый объект модуль можно декорировать, например, из класса ядра, путем вызова статического метода класса ядра из объекта модуля. Применяется такой подход для того, что бы можно было сразу во все модули вставить новую библиотеку (например для работы с почтой) или класс, обеспечив его "уникальность" и "независимость" изменив лишь конструктор класса родителя модулей (унаследованный класс) и добавив пару строчек в статический класс ядра.
Абстрактные классы и интерфейсы служат лишь для типизации программирования, что бы горе программист не забыл описать метод, например, не "засунул" в метод какой-нибудь параметр, который может нарушить целостность.
Как это реализовать без классов - ой не знаю.