Russian Qt Forum

Qt => Общие вопросы => Тема начата: xintrea от Ноябрь 06, 2015, 20:11



Название: Разделяю один объект на два. Как правильно сделать их взаимодействие?
Отправлено: xintrea от Ноябрь 06, 2015, 20:11
Дошли у меня руки поковыряться с застаревшим кодом. Надо его потихоньку приводить в более удобоваримое состояние. Проект - это простой WYSIWING редактор, используемый в составе программы MyTetra.

Основной файл - editor.cpp (класс Editor).

https://github.com/xintrea/mytetra_dev/tree/editorModification/src/libraries/wyedit

Сий редактор был сделан на скорую руку на основе стандартного примера из Qt. И все объекты кнопок управления ранее находились прямо в классе Editor.

Сейчас я выделяю из класса Editor класс панели с кнопками, называемый EditorToolBar. И вот вопрос. После выделения кнопок в отдельный класс, внутри этого нового класса нужны обращения к вышестоящему виджету (т. е. к классу Editor) для следующих действий:

1. Получение конфига редактора (от нескольких переменных конфига зависит расположение кнопок и прочих элементов управления, размещенных на EditorToolBar)

2. Текущий режим отображения редактора (от режима зависит видимость и действия кнопок и прочих элементов EditorToolBar)

3. Enum допустимых режимов редактора (чтобы было с чем сравнивать при действиях в пункте 2)

Я бы мог обращаться к родительскому виджету для получения всех этих данных. Но я недавно прочитал статью Чистая архитектура (http://habrahabr.ru/post/269589/) и там написано, что обращения к вышестоящим по иерархии объектам должны быть совершенно исключены.

А я не могу придумать, как же мне не обращаться к parent-виджету для получения нужных мне данных. Как поступить в случае, когда есть главный объект редактора, и второстепенный объект тулбара? Как сделать такой тулбар, чтобы он не требовал данных от редактора? Да и нужно ли такой делать?


Название: Re: Разделяю один объект на два. Как правильно сделать их взаимодействие?
Отправлено: Old от Ноябрь 06, 2015, 20:23
1. Получение конфига редактора (от нескольких переменных конфига зависит расположение кнопок и прочих элементов управления, размещенных на EditorToolBar)
Эти конфиги можно передать тулбару при конструировании, но лучше что-бы редактор сам его настраивал вызывая его методы.

2. Текущий режим отображения редактора (от режима зависит видимость и действия кнопок и прочих элементов EditorToolBar)
Сделайте слот у тулбара, например, setMode, и свяжите его с сигналом редактора, который испускается при смене режима.

3. Enum допустимых режимов редактора (чтобы было с чем сравнивать при действиях в пункте 2)
Тулбару должно быть все равно, какой режим ему устанавливают, это забота родительского редактора.


Название: Re: Разделяю один объект на два. Как правильно сделать их взаимодействие?
Отправлено: Racheengel от Ноябрь 07, 2015, 01:08
По моему, почти классический mvc. Editor  это модель и вью в одном целом, тулбар это контроллер. Тулбар должен обсервировать модель данных редактора и в соответствии с ней менять себя (включать и выключать кнопки и т.д.). Когда юзером нажата какая либо кнопка тулбара, должен вызываться соответствущий метод редактора. Он в свою очередь поменяет модель данных, что отразится на тулбаре.


Название: Re: Разделяю один объект на два. Как правильно сделать их взаимодействие?
Отправлено: Igors от Ноябрь 07, 2015, 13:36
Напрашивается "интерфейс", т.е. методы нужные тулбару выделяются в отдельный класс, и указатель на него дается тулбару. Сам класс включается в Editor наследованием или агрегированием. Можно "замылить" это слот/сигналами, но суть от этого не изменится.

Порадовали статейкой :)
Цитировать
1. Независимость от фреймворка. Архитектура не зависит от существования какой-либо библиотеки. Это позволяет использовать фреймворк в качестве инструмента, вместо того, чтобы втискивать свою систему в рамки его ограничений.
Хммм... а что же будет если вот "отнимут" Qt? (или дуст и др) Останется ли "хоть что-нибудь"?  :)


Название: Re: Разделяю один объект на два. Как правильно сделать их взаимодействие?
Отправлено: Racheengel от Ноябрь 07, 2015, 14:16
Как то так,да. Едитор ведь и без тулбара существовать может, а тулбар без едитора смысла не имеет. Пусть тулбар сам и цепляется к модели редактора.


Название: Re: Разделяю один объект на два. Как правильно сделать их взаимодействие?
Отправлено: ssoft от Ноябрь 09, 2015, 08:17
EditorToolBar - это панель с кнопками и ничего более.
Для наличия вышеперечисленной функциональности необходима дополнительная внешняя сущность(ти), которая управляет состояниями EditorToolBar.

Каким образом предполагалось обращение EditorToolBar к вышестоящему виджету для изменения его состояния, по таймеру?
Иначе это всегда внешнее воздействие на EditorToolBar - через метод update, сигнал слот.

Управляющей сущностью может быть сам Editior в случае, если очень лень писать, но по-хорошему это должен быть отдельный тип.
При проектировании архитектуры всегда необходимо руководствоваться необходимостью дальнейшего сопровождения - в том числе легкого изменения поведения программы (например, настройки передаются по сети или добавились новые режимы работы) и возможности повторного использования ее компонентов без необходимости их модификации.


Название: Re: Разделяю один объект на два. Как правильно сделать их взаимодействие?
Отправлено: Racheengel от Ноябрь 09, 2015, 19:57
Для наличия вышеперечисленной функциональности необходима дополнительная внешняя сущность(ти), которая управляет состояниями EditorToolBar.

Состояние EditorToolBar зависит от модели редактируемого докуметна. Это может быть позиция курсора, текущее выделение и т.д. Поскольку интерфейс данной модели, как правило, экспортируется редактором с помощью сигналов и слотов, то EditorToolBar здесь выступает в роли контроллера, присоединенного к этим сигналам и слотов. Он реагирует на сигналы изменения модели и имплементирует обратную связь посредством соединения своих сигналов и слотов редактора. Зачем тут еще одна сущность?


Название: Re: Разделяю один объект на два. Как правильно сделать их взаимодействие?
Отправлено: ssoft от Ноябрь 10, 2015, 09:29
Чаще всего так и делают (я не исключение), если не хотят заморачиваться - весь функционал реализуют в EditorToolBar, назначая ему кроме других ролей и роль контроллера. Помещают туда и загрузку из конфига, и реакцию на мышь, и др.
Количество кода EditorToolBar разрастается, повторное использование затрудняется.
По хорошему, если рассмотреть EditorToolBar, как автономный объект, который может просто переключаться в разные состояния, тем более что они перечислены в enum, то вызвать метод (слот) изменения состояния у EditorToolBar должен внешний(е) объект(ы), например, EditorToolBarConfig - загрузчик состояния из конфига, EditorToolBarMousePosition - изменяет состояние EditorToolBar по мышиным событиям, EditorToolBarDocumentModel - изменяет состояние EditorToolBar в зависимости от модели документа и т.п.


Название: Re: Разделяю один объект на два. Как правильно сделать их взаимодействие?
Отправлено: Racheengel от Ноябрь 10, 2015, 11:56
весь функционал реализуют в EditorToolBar, назначая ему кроме других ролей и роль контроллера. Помещают туда и загрузку из конфига, и реакцию на мышь, и др.

Тулбар загружает данные из конфига - это, конечно, высокое мастерство индокодерства :) Но обычно быдлокодеры не так делают, они все в редахтор лепят, и тулбары, и загрузку, и все остальное :)

Но вещи типа EditorToolBarConfig и EditorToolBarMousePosition тоже не должны ничего знать о тулбаре. Загрузка из конфига изменяет модель данных редактора. Тулбар же по сути туп - он вообще может рассматриваться как некий набор экшенов. А вот экшены уже должны быть связаны с редактором. Т.е. тулбар не должен обладать знаниями о том, КТО модифицирует модель. Ему только надо знать, ЧТО было модифицировано. Этим сильно упрощается архитектура.