2015-12-03 2 views
1

Я новичок в C++, я пытаюсь сделать очень простую программу CRUD.Как я могу поддерживать хорошую инкапсуляцию данных в этой ситуации?

В этом примере клиент купил много вещей в магазине, и этот магазин содержит информацию о том, что купил этот клиент. Я назвал его Inventory.

Магазин, хочет распечатать Report для каждого клиента. В приведенном ниже коде основной только один Инвентарь, только для образца.

Проблема: когда я хочу распечатать отчет, мне нужно получить данные от клиента, но без потери инкапсуляции. Я хочу сказать, что я не хочу, чтобы ни один класс не мог изменять содержимое инвентаря.

То, что я пытаюсь сделать, это преобразовать карту в вектор (мне нужно что-то сортировать данные) и передать этот вектор (динамически выделен). Я выделяю этот вектор в классе Inventory, но который удаляет - это класс Report, это неправильный способ сделать что-то, но я не знаю, как передать эту информацию, не делая этого.

В любом случае класс отчета может получить указатель на книгу и использовать его функцию set или указать другую книгу. Опять же, я не знаю, как это сделать правильно.

Может кто-нибудь дать мне совет, что я должен сделать в этом случае?

Спасибо.

Извините за длинный код.

Главная:

int main(void) 
{ 
    Inventory i; 
    Report r(i); 

    i.addBook("Foo Bar I"); 
    i.addBook("Foo Bar II"); 

    r.generateReport(); 

    return 0; 
} 

класса Отчет в .h:

class Report 
{ 
private: 
    Inventory* i; 
public: 
    Report(Inventory& i); 
    void generateReport(); 
}; 

класса Отчет в CPP:

Report::Report(Inventory& i) 
{ 
    this->i = &i; 
} 

void Report::generateReport() 
{ 
    ofstream out ("Report.txt"); 

    out << "Books: " << endl; 

    vector<pair<int, Book *>> * b = i->getBooks(); 

    for(pair<int, Book *> p : *b) 
    { 
     out << p.first << ": " << p.second.getName() << endl; 
    } 
    out << endl; 

    delete b; 

    out.close(); 
} 

класса Inventory в .h:

class Inventory 
{ 
private: 
    map<int, Book *> books; 

public: 
    void addBook(int code, const string& name); 
    vector<pair<int, Book *>> * getBooks(); 
}; 

класса Inventory в .cpp:

void Inventory::addBook(int code, const string& name) 
{ 
    books.insert(pair<int, Book *>(code, new Book(name))); 
} 

vector<pair<int, Book *>> * Inventory::getBooks() 
{ 
    return new vector<pair<int, Book *>>(books.begin(), books.end()); 
} 
+1

Пожалуйста, напишите [минимальный, полный и проверяемый пример] (https://stackoverflow.com/help/mcve) –

+0

Вы слышали о методах setter/getter? – user463035818

+0

Да, но я сделаю геттер для карты? – ViniciusArruda

ответ

0

Ваш класс инвентаризации должен иметь этот интерфейс:

class Inventory 
{ 
private: 
    map<int, Book *> books; 

public: 
    using const_iterator = std::map<int, Book*>::const_iterator; 

    void addBook(int code, const string& name); 
    const_iterator begin() const { return books.begin(); } 
    const_iterator end() const { return books.end(); } 
}; 

нет причин, чтобы создать копию карты в вектор! это неэффективно, а не причина для этого.

Перепишите generateReport работать с этим интерфейсом следующим образом:

for(const auto &p : *i) 
{ 
    out << p.first << ": " << p.second.getName() << endl; 
} 
out << endl; 
+0

Хорошо, я передам итератор. Но мне приходится сортировать данные. В этом и заключается причина преобразования карты в вектор. – ViniciusArruda

+0

@ X0R40 'map' по сути сортируется. Вы сортировали на основе чего-то помимо кода? –

+0

В этом коде нет никаких оснований для того, чтобы значение карты было указателем, а не значением. –

0

С вашим подходом, трюк, чтобы превратить map в vector introductes только дополнительная зависимость: отчет должен знать о внутренностях инвентарь.

Я предпочел бы рекомендовать пройти путь vistitor design pattern: цель состоит в том, чтобы отделить алгоритм (получения отчета, посетитель) от вас изучить структура данных (описи и ее элементы).

class Item { ...};  // Your object structure 
class Book : public Item { ... }; 
class Inventory { ...}; 

class Visitor { ... }; // Algorithms that shall be executed on structure 
class Report : public Visitor {...}; 

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

Theres много литтера на этом образце. Я рекомендую вам дизайн шаблоны, элементы многократного использование объекта ориентированных программного обеспечение от Gamma & аль: сво Orginal учебника, и угадать, что демо-код показывает инвентаризацию с ценовым посетителем ;-)

Here a naive on-line example на основе вашей проблемы , чтобы проиллюстрировать, как он может работать.

+0

Ницца, это будет полезно, но я учусь, на данный момент мне нужно что-то более простое. – ViniciusArruda

+0

@ X0R40 ok! В случае, если это полезно, я добавил ссылку на рабочий пример, вдохновленный вашей проблемой, чтобы показать вам, как он может работать. – Christophe

Смежные вопросы