C ++ композиция с итератором - PullRequest
       5

C ++ композиция с итератором

3 голосов
/ 04 сентября 2010

Я постараюсь сохранить пример кода очень простым, но он может содержать ошибки, так как я набираю его на месте.

У меня есть класс с именем Phone.

class Phone
{
 public:
  Phone(std::string manufacturer, std::string model, std::vector<Feature> features);

 private:
  std::vector<Features> features;
  std::string model;
  std::string manufacturer;
};

У меня есть структура с именем Feature.

struct Feature
{
   Feature(std::string feature, std::string category);
   std::string feature;
   std::string category;
};

Как видите, у телефона есть список (вектор) функций: т.е. Bluetooth, GPS, радио и т. д., которые имеют категорию: сеть, навигация, мультимедиа.

Теперь информация о телефонах и функциях хранится в базе данных sqlite3. У меня есть вспомогательная функция, которая извлекает конкретную модель телефона из базы данных и возвращает заполненный объект Phone. У меня также есть функция, которая принимает объект Phone и записывает его в базу данных.

Проблема в том, что мне нужно предоставить клиенту способ перебора списка функций телефона. Для начала, помощник базы данных должен знать о функциях, чтобы он мог записать их в базу данных. Во-вторых, клиенту может потребоваться извлечь телефон из базы данных, а затем отобразить пользователю список функций.

Одним из решений является добавление следующих функций в класс Phone

std::vector<Feature>::iterator begin()
std::vector<Feature>::iterator end()

Это не идеальное решение для меня, потому что код клиента не будет выглядеть интуитивно понятным - он будет выглядеть так, как если бы клиент итерировал по телефону, когда он фактически перебирал функции.

Другое решение обсуждается в статье на http://accu.org/index.php/journals/1527, в которой обсуждается использование техники с именем "memberspaces" для представления итераторов клиентскому коду. Это привело бы к более читаемому клиентскому коду, но реализация, на мой взгляд, немного запутанная.

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

Любая обратная связь будет принята с благодарностью.

Ответы [ 2 ]

1 голос
/ 05 сентября 2010

Если клиентский код будет использовать BOOST_FOREACH, почему бы просто не добавить метод

const std::vector<Feature>& getFeatures() const;

на телефон?

1 голос
/ 04 сентября 2010

В вашем случае я бы сначала выбрал лучшие имена:

typedef std::vector<Feature> Features;

Features::iterator features_begin();
Features::iterator features_end();
Features::const_iterator features_begin() const;
Features::const_iterator features_end() const;

Примеры:
1)

 // Note: you'll need to define an operator<< for Feature
 // can be used with std::algorithms
 std::copy( phone.features_begin(), phone.features_end(),
   std::ostream_iterator<Feature>( std::cout, "\n\r" ) );     

2)

// Note: shamelessly borrowed from http://www.boost.org/doc/libs/1_44_0/doc/html/foreach/extensibility.html
// add overloads of range_begin() and range_end() for Phone::Features
inline Phone::Features::iterator range_begin( Phone& phone ){
   return phone.features_begin();
}

inline Phone::Features::iterator range_end( Phone& phone ){
   return phone.features_end();
}

namespace boost{
   // specialize range_mutable_iterator and range_const_iterator in namespace boost
   template<>
   struct range_mutable_iterator< Phone >{
      typedef Phone::Features::iterator type;
   };

   template<>
   struct range_const_iterator< Phone >{
      typedef Phone::Features::const_iterator type;
   };
}
...
// can be used with BOOST_FOREACH
BOOST_FOREACH( Feature x, phone ){
   std::cout << x << std::endl;
}

P.S. Учитывая предложение Джонанна и соглашение об именах, используемое boost::range, имена теперь features_xxx() вместо xxx_features() (тем более, что они имеют больше смысла в этом контексте).

...