LINUX.ORG.RU

Паттерн «Компановщик». Как разным объектам добавлять разные свойства и обрабатывать их? Как выделить класс холст?


0

2

Есть базовый класс cObject

от него идут производные классы cCompositeObject cRectangle cProgressBar cLabel cEllipse ............

Реализовано всё это по паттерну Компановщик в cObject есть методы:

virtual void AddPrimitive( cObject* obj ) {}
virtual void Draw(GtkWidget *drawingarea) = 0;
а в cCompositeObject:
void Draw(GtkWidget *drawingarea);
void AddPrimitive( cObject* obj );

std::list<cObject*> m_elements;

У меня возникает два вопроса: 1) Если у каждого объекта есть свои свойства: например, у cRectangle: BorderColor, ForegroundColor у cLabel: Text, TextColor у cProgressBar: Value и т.д. как оптимальнее всё это организовать? Как сделать удобный доступ к ним? Что посоветуйте?

2) Мне говорили, что необхожимо выделить класс холст, т.к. объект не знает на ЧЁМ он рисует, но тут же паттерн компановщик и идёт грубо говоря рекурсивное рисование:

void cCompositeObject::Draw(GtkWidget *DrawingArea)
{
  for(CEitem_type it = begin(); it !=  end(); ++it)
    (*it)->Draw(DrawingArea);
}

как я могут избавить в объектах от прямого задания холста GtkWidget *DrawingArea) ?

Если можно приведите какие-нибудь примеры, будет понятнее, спасибо!


Ответ на: комментарий от shty

В этих примерах просто реализация паттерна компановщик. Меня интересует совсем другое, как уже к объектам организован по паттерну компановщик добавить нужные мне требования, которые я описал в вопросе

g-71
() автор топика

А почему не определить у каждого наследникай свой Draw? Для разношерстных данных так удобнее вроде бы.

Если у каждого объекта есть свои свойства: например, у cRectangle: BorderColor, ForegroundColor у cLabel: Text, TextColor у cProgressBar: Value и т.д. как оптимальнее всё это организовать? Как сделать удобный доступ к ним?

Я себе когда-то для этого написал макрос, периодически пользуюсь:

#define concat2(a,b) a##b
#define concat(a,b) concat2(a,b)

#define ifT(var,T)                                             \
 if(T* concat(tmp__##var,__LINE__)=dynamic_cast<T*>(var))      \
  for(int __keep=0;__keep!=1;)                                 \
   for(T *var=concat(tmp__##var,__LINE__);__keep!=1;__keep=1)

...

class T;
class T1,T2:public T;

...


T *t=...;
if(...)
 ...
else ifT(t,T1){
 /*тут работаем с t как с указателем на T1*/ }
else ifT(t,T2){
 /*тут как с T2*/}
else ...

staseg ★★★★★
()
Ответ на: комментарий от staseg

у каждого наследника и есть свой Draw, только в фишка в том, что туда передаётся указатель на холст и объект сам пользуяюсь указатель на холст берёт и рисуется ребя

насчёт макроса спасибо, пока правда не понял как он работаетЮ буду раз разбирается

а если у каждого объект ввести map на <названия свойства : string, значение свойства : string> и уже внутри объекта парсить свойство

нужно будет ввести еще один map для указания того какого типа это свойство, чтобы в окне свойств объекта (которое не знает о том сколько свойств у объекта) выводить их например: одно свойство в ComboBox, другое в Color Pallete, другое в обычный Edit. Т.е. каждое свойство имеет свой тип представления и это хранится в объекте.

Как Вам?

g-71
() автор топика
Ответ на: комментарий от g-71

Ой, да. Не заметил, что Draw есть везде. Ну тогда проблем с рисованием вообще нет.

А мап строк в значения свойств это как-то уж совсем не по-плюсовому имхо :)

staseg ★★★★★
()
Ответ на: комментарий от staseg

не, проблем-то нет, всё нормально работает, просто мне все твердят, что хреново когда объект рисует сам себя и когда ему передаётся холст. Но я пока не вижу никаких выходов из этой ситуации

я понимаю что не по плюсовому, только как выйти из такой ситуацию? Буду разбираться с Вашим макросом

g-71
() автор топика
Ответ на: комментарий от anonymous

никакого борланд делфи здесь нет, создаётся специализированный векторный редактор с использованием GTK+

g-71
() автор топика
Ответ на: комментарий от g-71

Хм. А по-моему Draw это один из классических примеров, как надо делать. В Qt сделано также. Тут может быть только одна загвоздка: если ты вдруг захочешь рисовать не только на гтк-что-то-там, но и на других холстах. Тогда может быть полезным сразу сделать прослойку myPainter_t, через который и рисовать. А разные его инстансы с единым АПИ смогут траслировать вызовы в другие рисовалки. Но тут нужно сразу прикинуть, нужно ли оно вообще.

А макрос мой - это тоже не очень по-плюсовому. В идеале никому кроме членов и пользователей наследного класса не нужно знать специфику его устройства. Так что ifT - это тоже костыль, просто, как по мне, более элегантный, чем список отображений строка->свойство.

staseg ★★★★★
()
Ответ на: комментарий от slackwarrior

>>Компановщик

лицорука-Розенталь.пцх

Вы имеете что-то против тех, кто орагинизует компашки по интересам?

staseg ★★★★★
()
Ответ на: комментарий от staseg

ну вроде как планируется только на GtkDrawingArea рисовать, а нет никакого примерчика где-нить в инете с реализацией такой прослойки? полезно будет посмотреть, если разберусь, то можно будет и реализовать

g-71
() автор топика

> cCompositeObject cRectangle cProgressBar cLabel cEllipse

выкинь венгерскую нотацию

классы как SomeClass, методы как someMethod, переменные как some_var (при этом поля класса как m_some_var).

Obey-Kun ★★★★★
()
Ответ на: комментарий от g-71

>а нет никакого примерчика где-нить в инете с реализацией такой прослойки?

Не знаю. Просто выбираешь общие нужные тебе примитивы вроде drawline, drowarc, etc. делаешь их pure virtual и засовываешь в class painterIface, в class gtkPainter:public painterIface реализуешь их для гтк.

а чем эта нотация плоха?

Это все вкусовщина, забей. Пиши, как удобно или как принято в твоем проекте/компании.

staseg ★★★★★
()
Ответ на: комментарий от staseg

спасибо большое! Реально очень помогли!

g-71
() автор топика
Ответ на: комментарий от staseg

> Вы имеете что-то против тех, кто орагинизует компашки по интересам?

Компоновщик

Obey-Kun ★★★★★
()
Ответ на: комментарий от staseg

>Вы имеете что-то против тех, кто орагинизует компашки по интересам?

Тему перечитай и найди там про «компашки по интересам». Не найдешь - «орагинизуй» (какой красивый южный акцент, вах!)

slackwarrior ★★★★★
()
Ответ на: комментарий от slackwarrior

>Тему перечитай и найди там про «компашки по интересам».

Перечитал. Там про компашки фигурок, которые любят рисоать.

какой красивый южный акцент, вах!

:)

staseg ★★★★★
()
Ответ на: комментарий от staseg

Ох уж этот акцент, непонятный рюсськем

s/рисоать/рисовать/

staseg ★★★★★
()
Ответ на: комментарий от Obey-Kun

при этом поля класса как m_some_var

Бить за такое по рукам. префикс «m» не несет никакой смысловой нагрузки, но при этом *всегда* требует, чтобы его прочитали, а потом уже и остальное имя переменной. Поля класса лучше именовать как someVar_, anotherSomeVar_ etc.

anonymous
()

В который раз убеждаюсь, что паттерны только мешают людям думать.

vasilenko ★★
()
Ответ на: комментарий от Obey-Kun

>Информация о точном типе переменной в ее имени

И где это у топикстартера?

zombiegrinder_6000
()
Ответ на: комментарий от anonymous

>префикс «m» не несет никакой смысловой нагрузки

Обосновать сможешь?

Поля класса лучше именовать как someVar_

Пистоновский PEP-8 идет лесом.

zombiegrinder_6000
()
Ответ на: комментарий от zombiegrinder_6000

>префикс «m» не несет никакой смысловой нагрузки

Тащемта, это сокр. от member

slackwarrior ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.