Russian Qt Forum
Апрель 27, 2024, 22:23 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: 1 2 [3] 4 5   Вниз
  Печать  
Автор Тема: Переходничок  (Прочитано 43480 раз)
lit-uriy
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 3880


Просмотр профиля WWW
« Ответ #30 : Сентябрь 10, 2010, 13:27 »

всё равно я нифига не понял. Например, зачем эта строка:
Код
C++ (Qt)
CMeshProgress::SetIndicator("Calculating Normals", mNormals.size());
Где должен появится текст "Calculating Normals"?

Если CMeshProgress должен всякий раз наследоваться, то почему методы не истинно виртуальные? Если должен всякий раз допиливаться, то вообще глупо.
Записан

Юра.
lit-uriy
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 3880


Просмотр профиля WWW
« Ответ #31 : Сентябрь 10, 2010, 13:28 »

нет определённо тему в помойку. Или создать раздел "угадайки", по аналогии с программистскими задачами
Записан

Юра.
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #32 : Сентябрь 11, 2010, 15:53 »

Где должен появится текст "Calculating Normals"?

Если CMeshProgress должен всякий раз наследоваться, то почему методы не истинно виртуальные? Если должен всякий раз допиливаться, то вообще глупо.
Текст появится там где решит наследник CMeshProgress. Если такового нет - то нигде. Можно сделать методы и pure virtual, тогда надо объявить/иметь наследника - дело вкуса. Смысл не в переливании static-virtual а в том что расчетная часть изолирована от UI.

Код
C++ (Qt)
func1(); // <<<<<< Вот после выхода из func1 индикатор определенный в func2 отключиться.
// Так не надо было писать? Ну извините, я забыл про это ограничение. :)
 
Это дело класса-индикатора организовать push-pop, клиент (расчетная часть) здесь ни при чем.

Сейчас мы "побороли" задачу индикации прогресса выполнения функции. Мы добавили этот код в разные классы и вроде все хорошо, но...
Теперь нам понадобилось вести статистику всех расчетов, что делать? Полезть во все функции и добавить аналогичную приблуду.
Я правильно понял что static ф-ция "приблуда" (все что не класс - плохо и.т.п) ?  Улыбающийся Но так или иначе лезть в расчеты и добавлять придется, потому что только там известно какие операции выполняются.

Код
C++ (Qt)
Statistica st;
 
...
 
CMeshCalculator calc;
calc.reg( new TextProgressIndicatorObserver ); // Регистрируем наблюдателя для вывода прогресса
if( useStatistica )
calc.reg( ?st ); // Если нужно - регистрируем наблюдателя для ведения статистики
 
Более мощный класс индикатора - дело хорошее. Но с чего Вы взяли что CMeshCalculator умеет делать reg и.т.п? Да CMeshCalculator может быть вообще не Ваш код. Его пишет Саша, для которого все UI начинается и заканчивается printf. Но предметную часть он знает прекрасно и алгоритмы кладет как надо. Я со своим простеньким классом скажу ему:
Цитировать
Санек, прицепи вот этот хедер, повтыкай оте 2 ф-ции где надо, установи на глазок "step" чтобы не дергать индикатор зря - и занимайся спокойно своим делом.
А Вы что скажете?
Цитировать
Ну ты это...Изучи буст/дуст, паттерны, зарегистрируй обсервера...(ну зная Сашу я думаю больше ничего сказать не успеете  Улыбающийся)
Я показал простейший пример "развязки" и ничего не имею против более сложных. Важен принцип изоляции, а реализация всегда зависит от конкретики.
Записан
m_ax
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2094



Просмотр профиля
« Ответ #33 : Сентябрь 11, 2010, 17:14 »

Интриги, скандалы, расследования!  Смеющийся

Почитал я на досуге про патерн Observe  Улыбающийся и это реально более изящное и правильное решение на мой взгляд.    
Используя этот патерн, Ваш пример с CMeshCalculator выглядел бы следующим образом:
Код
C++ (Qt)
#ifndef CMESHCALCULATOR_H
#define CMESHCALCULATOR_H
 
#include <list>
 
class CMeshCalculator;
 
class IObserver {
public:
   virtual void handleEvent(const CMeshCalculator &) = 0;
};
 
class CMeshCalculator {
public:
   CMeshCalculator()
       :_someParam(0) {}
 
   int someParam() const { return _someParam; }
 
   void calculate() {
   // Possible here _someParam is changed.
   // for example: _someParam++;
       notify();
   // ...
   }
   void reg(IObserver &ref) {
       _observers.push_back(&ref);
   }
 
   void unreg(IObserver &ref) {
       _observers.remove(&ref);
   }
 
private:
   std::list<IObserver*> _observers;
   typedef std::list<IObserver*>::iterator _iterator;
 
   void notify() {
       for(_iterator it = _observers.begin(); it != _observers.end(); it++)
           (*it)->handleEvent(*this);
   }
 
   int _someParam;
};
 
#endif // CMESHCALCULATOR_H
 
Где мы сотворили чисто виртуальный класс IObserve. Функция calculate() - это то, где производятся громоздкие расчёты и т.п. И в ней мы вызываем notify(), которая перебирает список всех зарегистрированных наблюдателей и вызывает у каждого переопределённый метод handleEvent.

Теперь пример класса TextProgressIndicatorObserver:
Код
C++ (Qt)
#ifndef TEXTPROGRESSINDICATOROBSERVER_H
#define TEXTPROGRESSINDICATOROBSERVER_H
 
#include <iostream>
#include "CMeshCalculator.h"
 
class TextProgressIndicatorObserver : public IObserver {
public:
   void handleEvent(const CMeshCalculator &calc) {
       std::cout << "processing..." << std::endl;
       std::cout << calc.someParam() << std::endl;
   }
};
 
#endif // TEXTPROGRESSINDICATOROBSERVER_H
 
 

Разумеется, информацию мы можем выводить не только в cout но в гуй и куда угодно. И это решение - как раз и отделяет интерфейсную часть от расчётной -> переходничок)

А используется это так:
Код
C++ (Qt)
#include <iostream>
#include "CMeshCalculator.h"
#include "TextProgressIndicatorObserver.h"
 
using namespace std;
 
 
int main()
{
   TextProgressIndicatorObserver tpiObserver;
   CMeshCalculator calc;
   calc.reg(tpiObserver);
   calc.calculate();
 
   return 0;
}
 
 

Поправьте, если чего то не того написал))

References:
http://en.wikipedia.org/wiki/Observer_pattern

« Последнее редактирование: Сентябрь 11, 2010, 17:16 от m_ax » Записан

Над водой луна двурога. Сяду выпью за Ван Гога. Хорошо, что кот не пьет, Он и так меня поймет..

Arch Linux Plasma 5
BRE
Гость
« Ответ #34 : Сентябрь 11, 2010, 17:38 »

А Вы что скажете?
Я скажу:
Санек, прицепи этот хеадер, добавь к своему классу еще один базовый класс с именем Subject и повтыкай где надо одну функцию. Все!
Больше Саньку никуда лезть не понадобиться никогда, все остальное можно будет сделать не глядя в его код, и индикацию, и статистику, и все что понадобиться.  Улыбающийся
В отличие от...
Записан
spectre71
Гость
« Ответ #35 : Сентябрь 11, 2010, 21:00 »

Все это достаточно весело. Грустный
Как правильно заметил Igors, один фиг необходимо делать вызовы в местах для подсчета. Этого никак не избежать.
А кого вызывать, это уже вторично: непосредственно метод некоторого объекта, обзервер, сигнал, ...
Все зависит от удобства, истории проекта, конкретной ситуации итд.
Надо поменьше битья себя кулаком в грудь - побольше дела.
Записан
Denjs
Гость
« Ответ #36 : Сентябрь 11, 2010, 21:12 »

Господа))))) что бы уж разобрать тему по косточкам - а информирование мира о прогрессе вычислений с помощью сигнал/слотов - это уже не модно или это рассматривается как частный случай одного из шаблонов?
Spectre конечно сказал что "надо вызывать в местах подсчета" - но , исхо он слегка не прав - что бы мы не делали, какую задачу мы бы не решали - всегда надо "все равно делать какой-либо вызов" , но шаблоны таки существуют - а значит разница есть.

Вопрос мой вот в чем. Почему не использовать станартный (читай реализованный) механизм QT (мы тут типа все-таки троллеводы здесь собрались? не?) , и не городить кучу классов самим? есть мысть сделать свое лучше чем тролли? гм.. тогда объясните "профит" - в чем и когда лучше....
« Последнее редактирование: Сентябрь 11, 2010, 21:17 от Denjs » Записан
BRE
Гость
« Ответ #37 : Сентябрь 11, 2010, 21:28 »

Вопрос мой вот в чем. Почему не использовать станартный (читай реализованный) механизм QT (мы тут типа все-таки троллеводы здесь собрались? не?) , и не городить кучу классов самим? есть мысть сделать свое лучше чем тролли? гм.. тогда объясните "профит" - в чем и когда лучше....
Смысл в следующем...
Если использовать Qt систему сигнал-слот, то мы получаем полную зависимость от Qt, а это далеко не всегда нужно.
Например, очень не плохо написать ядро системы вообще не привязанное к какому либо GUI. Дальше мы можем писать frontend для этого ядра на Qt/GTK/WinAPI или сделать консольную версию программы.

Но помимо Qt сигналов, есть еще свои реализации в boost или отдельной библиотеке sigc++, их так же можно использовать и удобств это только прибавит (ну я выше это уже писал).
« Последнее редактирование: Сентябрь 11, 2010, 21:31 от BRE » Записан
BRE
Гость
« Ответ #38 : Сентябрь 11, 2010, 21:35 »

какую задачу мы бы не решали - всегда надо "все равно делать какой-либо вызов" , но шаблоны таки существуют - а значит разница есть.
Все упирается в профит, который мы получим от этого самого вызова.
Записан
ufna
Гость
« Ответ #39 : Сентябрь 11, 2010, 21:37 »

BRE, а смысл тогда в этой теме на Qt-шном форуме? Для "не-Qt" есть куча мест где лежат алгоритмы и готовые решения, знать бы как их назвать. Вот тема данная за одно название уже бесполезна, к примеру )

Сигнал/слот - зависимость от QObject, это не GUI и актуально для форума. Кутэ - это не только интерфейс, не нужно об этом забывать.
Записан
BRE
Гость
« Ответ #40 : Сентябрь 11, 2010, 21:44 »

BRE, а смысл тогда в этой теме на Qt-шном форуме? Для "не-Qt" есть куча мест где лежат алгоритмы и готовые решения, знать бы как их назвать. Вот тема данная за одно название уже бесполезна, к примеру )

Сигнал/слот - зависимость от QObject, это не GUI и актуально для форума. Кутэ - это не только интерфейс, не нужно об этом забывать.
Да я не забываю, но Igors четко описал, что этот прием создавался что-бы разорвать зависимости от сторонних библиотек и дать возможность разработчику выбирать метод индикации (GUI/консоль/что-то еще).
Это и обсуждаем.  Улыбающийся
А зависимость от QObject это автоматическая зависимость от Qt.  Подмигивающий
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #41 : Сентябрь 12, 2010, 14:50 »

Если использовать Qt систему сигнал-слот, то мы получаем полную зависимость от Qt, а это далеко не всегда нужно.
Это конечно верно. Но не только это. Я не вижу как удобно сделать с помощью слот/сигнал. Ну то есть сделать я могу, но мне не нравится  Улыбающийся Чтобы разговаривать предметно, давайте конкретную реализацию на слот/сигнал, а я попробую объяснить почему.

Больше Саньку никуда лезть не понадобиться никогда,
Улыбающийся Ну иногда можно и "поступиться принципами". Напр появляется "этажерка" индикаторов (верхний - обрабатываемый элемент, нижний - прогресс самого элемента и.т.п.). В принципе даже в том интерфейсном классе что я предложил - это можно сделать на автопилоте (ведь известно когда индикатор закончится). Но мне кажется это не очень рационально. Лучше расширить интерфейсный класс, явно предоставив ф-цию напр PushIndicator. Да, так мы имеем переделки на расчетной части, но зато куда проще с реализацией UI - разумный баланс.

Почитал я на досуге про патерн Observe  Улыбающийся и это реально более изящное и правильное решение на мой взгляд.   
Используя этот патерн, Ваш пример с CMeshCalculator выглядел бы следующим образом:
...
Код
C++ (Qt)
 void handleEvent(const CMeshCalculator &calc)
 
А почему handleEvent осведомлен о классе CMeshCalculator вообще? Откуда handleEvent знает какой текст нужно написать и какой прогресс показать? И если у Вас 2 или более обсерверов, откуда они знают кому чего показать? Я так вижу что ресурсы-то уже тратятся (STL и.т.п) а хотя бы минимальной ф-циональности еще нет.

..а смысл тогда в этой теме на Qt-шном форуме? Для "не-Qt" есть куча мест ..
Форум должен быть углубленным изучением Assistant!  Улыбающийся Увы, это во многом так и есть  Плачущий
Записан
BRE
Гость
« Ответ #42 : Сентябрь 12, 2010, 15:03 »

А почему handleEvent осведомлен о классе CMeshCalculator вообще? Откуда handleEvent знает какой текст нужно написать и какой прогресс показать? И если у Вас 2 или более обсерверов, откуда они знают кому чего показать? Я так вижу что ресурсы-то уже тратятся (STL и.т.п) а хотя бы минимальной ф-циональности еще нет.
А почему все классы типа CMeshCalculator и их методы должны знать про CMeshProgress?  Улыбающийся
Потому, что нельзя заставить взаимодействовать два объекта, которые ничего не знают друг о друге (без дополнительных телодвижений).
Поэтому, все классы-наблюдатели знают о классе субъекте за которым они наблюдают, а вот класс-субъект ничего не знает о своих наблюдателях, кроме одной функции, которую он вызывает.
Разница в том, что CMeshProgress может делать только одну вещь (при попытке расширить функционал придется лезть в класс-субъект и добавлять код руками), а при использовании наблюдателей они могут делать совершенно разные действия и никаких изменений в классе-субъекте делать не придется.
« Последнее редактирование: Сентябрь 12, 2010, 15:05 от BRE » Записан
m_ax
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2094



Просмотр профиля
« Ответ #43 : Сентябрь 12, 2010, 15:31 »

Цитировать
А почему handleEvent осведомлен о классе CMeshCalculator вообще? Откуда handleEvent знает какой текст нужно написать и какой прогресс показать? И если у Вас 2 или более обсерверов, откуда они знают кому чего показать?
Ну тут меня опередили (см. выше)

Цитировать
Я так вижу что ресурсы-то уже тратятся (STL и.т.п) а хотя бы минимальной ф-циональности еще нет.
Igors, это уже жадность)) Что там такого тратиться? Не думаю, что кто то вообще почувствует разницу по съеданию ресурсов в этом месте.. Короче это смешно)

А по-поводу минимальной функциональности это Вы не правы. В данном конкретном примере, целью которого было лишь продемонстрировать идею этого патерна, реальной функциональности нет) Эт ж пример))
Но, если смотреть глубже то здесь большой потенциал, для Вашей задумки с переходником.
Причём реализуется он без лишних беспокойств Санька, (того, который так хорошо кладёт код)
   
Чем по функциональности приведённый пример с патерном уступает вашему переходнику? 


Записан

Над водой луна двурога. Сяду выпью за Ван Гога. Хорошо, что кот не пьет, Он и так меня поймет..

Arch Linux Plasma 5
BRE
Гость
« Ответ #44 : Сентябрь 12, 2010, 17:20 »

Набросал шаблон реализующий паттерн Observer:
Код
C++ (Qt)
#include <list>
#include <cassert>
 
template<typename Subject, typename Observer, void (Observer::*func)( Subject & )>
class ObserverSubject
{
typedef Observer* Pointer;
typedef std::list<Pointer> List;
 
public:
void regObserver( Pointer o )
{
assert( o );
m_listObservers.push_back( o );
}
 
void unregObserver( Pointer o )
{
assert( o );
m_listObservers.remove( o );
}
 
void notifyObserver()
{
for( typename List::iterator i = m_listObservers.begin(); i != m_listObservers.end(); ++i )
((*i)->*func)( static_cast<Subject&>( *this ) );
}
 
private:
List m_listObservers;
};
 

Использование:
Код
C++ (Qt)
class CMeshCalculator;
 
// Определяем абстрактный базовый класс наблюдателей.
// Имя функции может быть любой (указывается в параметрах шаблона)
class Observer
{
public:
virtual void update( CMeshCalculator &obj ) = 0;
};
 
// Добавляем к базовым классам ObserverSubject.
class CMeshCalculator : public ObserverSubject<CMeshCalculator, Observer, &Observer::update>
{
public:
CMeshCalculator() : m_index( -1 ) {}
 
void func()
{
for( m_index = 0; m_index < 20; ++m_index )
{
// В точках, где необходимо позвать наблюдателей добавляем:
notifyObserver();
}
}
 
inline int index() const { return m_index; }
 
private:
int m_index;
};
 
// Описываем наблюдателя для индикации
class Indicator : public Observer
{
public:
Indicator( int step = 10 ) : m_step( step ) {}
 
void update( CMeshCalculator &obj )
{
if( !(obj.index() % m_step) )
std::cout << "[Indicator] " << " progress: " << obj.index() << std::endl;
}
 
private:
int m_step;
};
 
// Описываем наблюдателя для ведения лога
class Log : public Observer
{
public:
void update( CMeshCalculator &obj )
{
std::cout << "[Log] " << " progress: " << obj.index() << std::endl;
}
};
 
int main( int, char ** )
{
Indicator i( 5 );
Log l;
 
CMeshCalculator calc;
// Регистрируем нужных наблюдателей
calc.regObserver( &i );
calc.regObserver( &l );
 
calc.func();
 
return 0;
}
 
« Последнее редактирование: Сентябрь 12, 2010, 17:33 от BRE » Записан
Страниц: 1 2 [3] 4 5   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.224 секунд. Запросов: 22.