Skip to content

Instantly share code, notes, and snippets.

Created July 21, 2008 23:21
Show Gist options
  • Save anonymous/432 to your computer and use it in GitHub Desktop.
Save anonymous/432 to your computer and use it in GitHub Desktop.
#include <exception>
#include <iostream>
#include <string>
//объект посредник
template<
typename I, // класс - сервис
typename X, // тип свойства
X (I::*Get)(), // метод класса сервиса, для получения значения
void (I::*Set)(const X&)// метод для изменения свойства
>
class proxy_t
{
I& srv_;//значение параметра
std::string name_;//имя параметра
public:
proxy_t(I& srv, const std::string& str) : srv_(srv), name_(str)
{
}
proxy_t& operator = (const X& value)
{
(srv_.*Set)(value);
return *this;
}
operator X ()
{
return (srv_.*Get)();
}
std::string get_name()
{
return name_;
}
};
//враппер для значения с диапазоном допустимых значений
template<class T>
struct value_wrapper
{
T& value_;
std::pair<T,T> range_;
value_wrapper(T& v, T min, T max) : value_(v), range_(min, max) {}
//value_wrapper
value_wrapper& operator = (const value_wrapper& v) {value_ = v.value_; range_ = v.range_;}
value_wrapper& operator = (const T& v) {value_ = v;}
operator T() const {return value_;}
bool check_range(T& v)
{
if (v < range_.first)
return false;
if (v > range_.second)
return false;
return true;
}
};
//класс отвечает за диалог с пользователем, ничего не знает о том объекте, чьи свойства он показывает
class Client//GUI
{
public:
//метод получает объект посредник и отображает диалог изменения свойства
template<
class Proxy
>
void apply(Proxy& p);
//специализация для посредника любого типа
template<
class I,
class X,
X (I::*Get)(),
void (I::*Set)(const X&)
>
void apply (proxy_t<I, X, Get, Set>& p)
{
X tmp = static_cast<X>(p);
std::cout << p.get_name() << " = " << tmp << std::endl;
std::cout << "let " << p.get_name() << " = " << std::ends;
std::cin >> tmp;
p = tmp;
}
//специализация для строковых значений
template<
class I,
std::string (I::*Get)(),
void (I::*Set)(const std::string&)
>
void apply (proxy_t<I, std::string, Get, Set>& p)
{
//значение типа std::string
std::cout << "str: " << p.get_name() << " = " << static_cast<std::string>(p) << std::endl;
std::cout << "let " << p.get_name() << " = " << std::ends;
std::cin >> static_cast<std::string>(p);
}
//специализация для числовых значений с проверкой диапазона
template<
class I,
class X,
value_wrapper<X> (I::*Get)(),
void (I::*Set)(const value_wrapper<X>&)
>
void apply (proxy_t<I, value_wrapper<X>, Get, Set>& p)
{
std::cout << p.get_name() << " = " << static_cast< value_wrapper<X> >(p) << std::endl;
std::cout << "let " << p.get_name() << " = " << std::ends;
X tmp;
std::cin >> tmp;
if (! static_cast< value_wrapper<X> >(p).check_range(tmp) )
throw std::runtime_error("input error");
p = value_wrapper<X>(tmp,tmp,tmp);
}
};
//класс - сервис, реализует какую-то бизнес логику, не работает с GUI сам
class Service
{
int int_value;
double dbl_value;
std::string str_value;
public:
Service(int i, std::string s, double d) : int_value(i), dbl_value(d), str_value(s)
{
}
//метод создает proxy объекты для своих полей и передает их клиенту
template<class C>
void apply(C& client)
{
proxy_t<Service, int, &Service::get_int_value,
&Service::set_int_value> int_proxy(*this, "int_value");
proxy_t<Service, std::string, &Service::get_str_value,
&Service::set_str_value> str_proxy(*this, "str_value");
proxy_t<Service, value_wrapper<double>, &Service::get_dbl_value,
&Service::set_dbl_value> dbl_proxy(*this, "dbl_value");
client.apply(int_proxy);
client.apply(str_proxy);
client.apply(dbl_proxy);
}
//методы для доступа к полям объекта
void set_int_value(const int& v)
{
int_value = v;
}
void set_dbl_value(const value_wrapper<double>& v)
{
dbl_value = (double)v;
}
void set_str_value(const std::string& s)
{
str_value = s;
}
int get_int_value()
{
return int_value;
}
value_wrapper<double> get_dbl_value()
{
return value_wrapper<double>(dbl_value, 0, 10);
}
std::string get_str_value()
{
return str_value;
}
};
int main()
{
Service srv(25, "Foo", 3.14159);
Client gui;
srv.apply(gui);
std::cout << "result: " << srv.get_int_value() << ", "
<< srv.get_str_value() << ", "
<< (double)srv.get_dbl_value()
<< std::endl;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment