Created
July 21, 2008 23:21
-
-
Save anonymous/432 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #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