C++ Builder
| Главная | Уроки | Статьи | FAQ | Форум | Downloads | Литература | Ссылки | RXLib | Диски |

 
класс Callback, Георгий, Asher, нужна критика
olegenty
Отправлено: 14.09.2005, 10:12


Ветеран

Группа: Модератор
Сообщений: 2412



если Callback используется ТОЛЬКО в интерактиве (т.е. никаких циклов), то, насколько это плохо:

CODE

// Header (H)

typedef map<AnsiString, Variant> TValMap; // Result Fields Type
typedef auto_ptr<TValMap> TValMapPtr; // Result Fields Pointer Type
typedef pair<bool, TValMapPtr> TResPair; // Result Fields Pointer Pair Type
typedef auto_ptr<TResPair> TResPairPtr; // Result Fields Pointer Pair Pointer Type
typedef auto_ptr<AnsiString> TStrPtr;

typedef TResPairPtr __fastcall (__closure *TPCallback)(TValMapPtr);
typedef map<AnsiString, TPCallback> TCallbackTable;

extern const TValMapPtr NullValMapPtr;

class CSDICallback
{
private:
TCallbackTable Table;
public:
bool __fastcall RegisterFunction(const AnsiString Name, const TPCallback Func);
bool __fastcall UnregisterFunction(const AnsiString Name);
TResPairPtr __fastcall Execute(const AnsiString Name, TValMapPtr Values) const;
TADOConnection* __fastcall Connection() const;
};

CODE

// Code (CPP)

//----------------------------------------------------------------------
bool __fastcall CSDICallback::RegisterFunction(const AnsiString Name, const TPCallback Func)
{
if (Table.find(Name) != Table.end()) return false;
Table[Name] = Func;
return true;
}
//----------------------------------------------------------------------

bool __fastcall CSDICallback::UnregisterFunction(const AnsiString Name)
{
if (Table.find(Name) == Table.end()) return false;
Table.erase(Name);
return true;
}
//----------------------------------------------------------------------

TResPairPtr __fastcall CSDICallback::Execute(const AnsiString Name, TValMapPtr Values) const
{
TCallbackTable::const_iterator res = Table.find(Name);
   if (res == Table.end())
       return TResPairPtr(new TResPair(false, static_cast<TValMapPtr>(NULL)));
   // это обязательно, без локальной переменной inline return НЕ РАБОТАЕТ с auto_ptr
   TResPairPtr r = (*res).second(Values);
   return r;
}
//----------------------------------------------------------------------

TADOConnection* __fastcall CSDICallback::Connection() const
{
TResPairPtr r = Execute("Connection", NullValMapPtr);
return (TADOConnection*)((unsigned int)((*(*r).second)["Connection"]));
}


Отредактировано olegenty — 16/09/2005, 09:23
olegenty
Отправлено: 16.09.2005, 08:24


Ветеран

Группа: Модератор
Сообщений: 2412



всё замечательно работает, но критика всё же нужна...
Георгий
Отправлено: 18.09.2005, 00:55


Почетный железнодорожник

Группа: Модератор
Сообщений: 874



не очень понятно что это — написал бы общую идею этой штуки тогда бы понятно стало что критиковать smile.gif

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

а по реализации только одно замечание — чем boost::mem_fn не понравились ( http://boost.org/libs/bind/mem_fn.html ) их можно использовать вместо TResPairPtr
olegenty
Отправлено: 19.09.2005, 06:06


Ветеран

Группа: Модератор
Сообщений: 2412



писал универсальный Callback. сначала — для связи EXE и DLL. программный продукт устроен так: основной запускающий модуль — EXE, и DLL-плагины, реализующие некоторый достаточно специфичный функционал. а получилось — без разницы. в EXE присутствует экземпляр сего класса. ряд методов, типа Connection, MainWindowHandle и др. — предопределены, просто я не стал их показывать, они как братья близнецы. а ряд других — регистрируются во время выполнения и становятся доступными всем прочим модулям. при инициализации плагина в его конструктор передаётся указатель на экземпляр Callback, и он получает доступ к функционалу, который един для всех плагинов и реализован в EXE. теперь же уже не важно, где реализован этот функционал, главное — зарегистрировать функцию в таблице Callback.

сама по себе идея появилась от того, что надоело каждый раз руками модифицировать код класса Callback, добавляя туда новый функционал. теперь достаточно просто зарегистрировать некий метод, как функцию Callback, и любой модуль получает к ней доступ по её имени. Всё, что нужно (как и раньше) — знать спецификацию вызова. порядок следования параметров не важен (это ж map), надо только отдать имена и значения. и получить обратно то же самое, но в виде auto_ptr< pair>. pair.first — признак того, выполнена ли функция. pair.second — auto_ptr на значения. туда надо лезть ТОЛЬКО если pair.first = true;

auto_ptr — чтобы параметры убиались сразу после использования.

про boost много слышал, но пока не дошли руки разобраться. также как много слышал про Loki (хотя, кое-что оттуда в экспериментах использовал) и Qt. наверное, boost будет следующей библиотекой для разбора и применения, тем более, что (по слухам) даже стандартные шаблоны (тот же map) там реализованы лучше.

в целом же все эти заморочки с разносом функционала по DLL-плагинам появились в преддверии рождения стандарта на разработку внутри подразделения, в котором я работаю (и которым руковожу). раньше подразделение было "с мира по нитке" (писали на Delphi, BCB, VBA под Access, VB). за последние 2 года плотно подсели на С++, конкретно — BCB. т.е. все предпосылки для рождения стандарта — имеют место.

Отредактировано olegenty — 19/09/2005, 09:00

Вернуться в Вопросы программирования в C++Builder