RealChat architecture
RealChat - архитектура
описание внутренней архитектуры программы
Автор: Hunter
Дата: 14.06.2009 21:18
Немного истории
Программа писалась в несколько этапов. Сначала это был любительский проект, попытка написать чат, внешне похожий на Intranet Chat. По мере совершенствования возникали новые сложности и приходилось менять архитектуру программы.
Раньше ядра как такового не было - была основная форма, на которой лежали все визуальные и невизуальные объекты (кроме отдельных окошек). При создании новой страницы чата эта страница программно собиралась из составляющих объектов. Страницы идентифицировались по заголовку, т.е. две страницы с одинаковыми заголовками уже не работали. Обращение к объектам на странице происходило напрямую. Т.е. для добавления юзера в список юзеров нужно было найти нужную страницу, и обратиться прямо к визуальному списку, который на ней лежит.
Со временем добавились новые типы страниц - список каналов, список файлов. Обращение к их элементам усложнилось, нужно было проверять тип страницы. При всяком изменении страницы приходилось искать по всей программе обращения к элементам страницы и исправлять их. И вообще структура была запутана, но все это как-то работало.. Но расширять функционал и добавлять новые фичи было очень сложно.
Сейчас функционал поделен на несколько основных частей:
- Ядро, которое является центром программы. Все обращения между компонентами идут через ядро. Для добавления чего-то нового теперь не нужно рыться по всей программе, а достаточно добавить в ядро вызов этого функционала. Можно даже добавлять «пустые» функции, которые в данный момент не реализованы, но могут быть реализованы позже. Достаточно «прицепить» реализацию функции к ядру в виде плагина или отдельного модуля.
- Интерфейсная часть, т.е. то, что видит и с чем работает пользователь. Окошки, кнопки, менюшки, поля, галочки, картинки, итд.. Теперь при клике на кнопку не выполняется некий предопределенный кусок программы, а вызывается соответсвующая команда ядра. И ядро может само обрабатать нажатие кнопки, а может передать его модулям. Обращение к интерфейсу из модулей программы тоже идет через ядро. Поскольку элементы интерфейса не имеют жесткой привязки к структуре программы (только к ядру), ими можно манипулировать как угодно - перемещать между окнами, вкладывать друг в друга, создавать и убивать «на лету», по необходимости. Лишь бы не терялась привязка к ядру, а ядро доступно отовсюду.
- Программные компоненты (модули), которые подключаются к ядру. Это как бы отдельные программы, которые, к примеру, устанавливают связь с сервером и работают как клиенты чата. Тот же клиент IRC не имеет своего визуального интерфейса, а сообщает ядру, что надо создать новую закладку, надо на такую-то закладку вывести такой-то текст. И наоборот, при вводе текста в закладке чата этот текст через ядро приходит к клиету IRC, обрабатывается и отправляется на сервер. Можно включить сразу два клиента с разными настройками. Можно запустить клиентов для разных протоколов.. Модуль может содержать свои собственные визуальные формы, которые может использовать сам, а может через ядро подключать к общему интерфейсу. В принципе, даже само ядро может быть программным компонентом и подключаться к другому ядру или самому себе.
- Конфиг. Это некое подобие виндового реестра. У каждого модуля есть свой конфиг. Есть еще главный конфиг, в нем общие настройки программы. И есть еще глобальный конфиг, который объединяет в себе все прочие конфиги. Конфиг имеет древовидную структуру, но может быть представлен и в виде списка. В принципе, конфиг может использоваться и как простая база данных.
В начале все страницы настроек создавались программно, сами настройки хранились прямо в визуальных элементах (контролах) формы. Просто, относительно удобно, но нельзя реализовать, к примеру, отмену изменений конфига.
Потом настройки были реализованы как свойства отдельного автономного объекта (конфига), а их визуальное представление в виде отдельных панелей было создано заранее и свалено в одну кучу. Стало удобнее, но такой конфиг прописан в коде программы, его нельзя расширить во время работы программы.
Сейчас конфиг реализован по образу и подобию виндового реестра (то есть позволяет хранить одинаковые наборы данных в разных ветках), веткам можно назначать страницу визуальных элементов (контролов), сами страницы настроек не валяются как попало, а сидят на невидимых закладках. Есть универсальная страница настроек, в виде списка настроект данной ветки. Можно подключать ветки настроек из других модулей, копировать их, сохранять все сразу или по отдельности, итд… Кроме того, обращение к элементу конфига идет не по программной ссылке, а по идентификатору или имени - можно легко обращаться к настройкам из плагинов. То есть конфиг получился очень гибким и независимым хранилищем настроек. Но поскольку конфиг используется в каждом кусочке программы, то пришлось переписать почти всю программу.
Состав модулей программы
Основные модули программы:
- Core.pas (ядро)
- Main.pas (главная форма)
- Configs.pas (конфиг)
Интерфейсные модули:
- OptionsForm.pas (форма настроек)
- MainOptions.pas (основные настройки)
- ClientsFrame.pas (форма списка компонентов)
- InfoFrame.pas (форма справочной информации)
- ChatPage.pas (страница чата)
- FilesFrame.pas (страница файлов)
Вспомогательные модули:
- Misc.pas (вспомогательные функции)
- Plugins.pas (модуль работы с плагинами)
- PluginsFunc.pas (реализация командного языка плагинов)
- AsyncSock.pas (асинхронные сокеты)
- Timer.pas (расписание событий)
- Sounds.pas (звуки)
Модули компонентов:
- IRC.pas (компонент клиента IRC)
- IRC_Options.pas (настройки IRC)
- DCC.pas (компонент DCC)
- DCC_FileAccept.pas (форма принятия файла)
- ChanListFrame.pas (форма списка каналов)
- iChatUnit.pas (компонент клиента iChat)
- iChatOptions.pas (настройки iChat)
Есть и другие модули, часть из них устаревшие.
Подробности устройства программы
Ядро состоит из базовых классов, менеджеров и функций:
- TPageInfo - подробная информация о странице и ее свойствах
- TChatClient - базовый класс для протоколов клиентов чата. Содержит набор свойств и методов, которые обязательно должны быть у потомков.
- TChatPage - Класс, описывающий произвольную страницу. Это может быть страница чата, файлов, состояния, настроек, итд..
- PagesManager - Менеджер страниц чата. Содержит список всех страниц чата и методы для управления страницами.
- ClientsManager - Менеджер клиентов чата. Содержит список всех клиентов и методы для управления клиентами, рассылки сообщений.
- Набор глобальных функций - содержит глобальные функции и процедуры, позволяющие выполнять некоторые действия - проиграть звук, показать записку, показать окно ввода, записать отладочное сообщение, сменить язык или стиль, итд..
Кроме того, в ядре есть такие глобальные объекты, как:
- MainForm - главная форма содержит набор основных визуальных и невизуальных элементов - менюшек, значков, кнопок, итд.. Доступ к ним должен выполняться только из функций и классов ядра. Только в особых случаях, когда нецелесообразно использование отдельных элементов (например, списка значков и стилей), допустимо использование списков значков и стилей с главной формы. В дальнейшем это должно быть устранено или стандартизировано.
- MainConf - главный конфиг программы. Содержит общие настройки. Доступ к значениям производится по имени значения, например MainConf['UserName']. Конфиг динамический, можно свободно добавлять и использовать новые значения во время работы. Но следует добавлять только глобальные параметры, которые используются за пределами отдельного компонента. Компоненты должны использовать свои конфиги.
- LangIni - языковый конфиг. Содержит языковые переменные. Все надписи должны браться из этого конфига. Отличается от других конфигов тем, что не имеет визуальной формы, не имеет древовидной структуры и является обычным ini-файлом.
Создание нового компонента:
- Интерфейсные компоненты - формы.
Новые формы можно создавать обычным образом. Но нельзя оставлять их в RealChat.dpr. Во время работы программы создайте новую форму, Parent:=MainForm, при закрытии делайте Release().
- Интерфейсные компоненты - страницы
Форму страницы создавайте в виде фрейма TFrame. Конструктор переопределите так, чтобы он принимал параметр Page: TChatPage, который описывает свойства страницы и позволяет установить обработчики событий страницы. Основные события - смена языка, стиля и статуса активности страницы. Страница не должна обращаться напрямую к другим страницам и компонентам - только к ядру. Для создания страницы используйте PagesManager.CreatePage.
- Программные компоненты - клиенты
Клиент должен быть наследником Core.TChatClient и реализовывать все его методы и свойства. Это методы обработки сообщений пользователя, работы с настройками, подключение-отключение, итд.. Клиент в свою очередь должен иметь свой конфиг (даже пустой), может создавать новые формы, регистрировать страницы. Доступ у клиента только к ядру и вспомогательным модулям. Если у клиента есть конфиг, то у конфига может быть визуальная форма с набором панелей. Панели содержат интерактивные контролы и привязаны к узлам конфига.