Главная
Блог разработчиков phpBB
 
+ 17 предустановленных модов
+ SEO-оптимизация форума
+ авторизация через соц. сети
+ защита от спама

Спрятанная инициализация спрятанных свойств объекта

Anna | 24.06.2014 | нет комментариев

Предположим у нас имеется класс владеющий богатым внутренним миром числом свойств, которые нужно инициализировать перед началом работы с объектом. Возможен также, что построение объекта должно осуществляться данными поступающими из вне (Скажем это могут быть DTO либо строки XML/JSON формата из API библиотеки X).

У меня, в таких обстановках появляется желание перенести процесс адаптации и построения бизнес-объектов в обособленный слой моей системы, но возникают несколько вопросов:

  1. Каким образом инициализировать приватные свойства класса если их много (желанно не нарушая тезисов инкапсуляции)?
  2. Как реализовать несколько типов билдера из различных видов сырых данных?

Задача, так сказать, абсолютно обыкновенная, немного того рутинная. Ко каждому прочему, есть много методов ее реализации, как положительных традиционных (телескопические конструкторы, посредством аксессоров), так и не дюже. Для одного из таких методов нам абсолютно подойдет идиома pimpl. Почитать про нее дозволено здесь и здесь.

(Экстраординарно для краткости, каждый код будет яруса Hello world)

// data api version 1.0
struct api_msg_v1 {
    char value;
};
// data api version 2.0
struct api_msg_v2 {
    int value;
};

class object {
public:
    //...
    void do_some_work() {
        //...
    }
private:
    // ... other properties
    int m_value;
};

Выходит, представим нам требуется при создании экземпляра класса object инициализировать его качество m_value данными содержащимися в любом из 2-х объектов api_msg_v1 и api_msg_v2.

Для этого в объявление класса object добавим шаблонный форвард, внутреннего класса тот, что в последствии будет отвечать за создание и инициализацию наших объектов.

class object {
public:
    /// forward builder 
    template< typename T >
    struct builder;
    //...
    void do_some_work() {
        //...
    }
private:
    // ... other properties
    int m_value;
};

В нашем случае значимо то, что класс builder является внутренним, таким образом, он имеет доступ ко каждой кухне класса верхнего яруса. Шаблонными мы его сделали для специализации по типам сообщений.

Сейчас мы можем описать желаемую реализацию:

template<>
struct object::builder< api_msg_v1 >
{
    static object *create_from(api_msg_v1 v) {
        auto object = new object;
        // init by api version 1...
        object->m_value = static_cast<int>(v.value);
        return object;
    }
};

template<>
struct object::builder< api_msg_v2 > 
{
    static object *create_from(api_msg_v2 v) {
        auto object = new object;
        // init by api version 2...
        object->m_value = v.value;
        return object;
    }
};

//...
auto c = object::builder< api_message_v2 >::create_from(msg);

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

Я уверен, что не открыл для вас Америку, но хотел напомнить, что всякий язык дает 1001 метод выстрелить себе в ногу решить поставленную задачу.

Славных выходных.

 

Источник: programmingmaster.ru

 

Оставить комментарий
Форум phpBB, русская поддержка форума phpBB
Рейтинг@Mail.ru 2008 - 2017 © BB3x.ru - русская поддержка форума phpBB