简体   繁体   中英

How can I maintain a good data encapsulation in this situation?

I am new in c++, I am trying to make a very simple CRUD program.

In this example, a client bought many things in a store, and this store has the information about the things that this client bought. I called it Inventory .

The store, wants to print a Report for every client. In the code below, the main just has one Inventory, just for sample.

The problem is: When I want to print the Report, I have to get the data from the client, but without lose encapsulation. I mean, I want that no class can modify the content of the inventory.

What I am trying to do is convert the map into a vector (I need something to sort the data) and pass this vector (dinamically allocated). I am allocating this vector at the class Inventory but who is deleting is the class Report , this is not the correctly way to do things, but I do not know how to pass this information without doing like this.

Anyway, the report class can get the pointer to a Book, and use its set function or point to other Book. Again, I do not know how to do it correctly.

Can someone give me a tip what I have to do in this case ?

Thanks.

Sorry for the long code.

Main:

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

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

    r.generateReport();

    return 0;
}

Class Report in .h:

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

Class Report in 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();
}

Class Inventory in .h:

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

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

Class Inventory in .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());
}

Your inventory class should have this interface:

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(); }
};

no reason to create a copy of the map into a vector! that is inefficient and not reason for doing it.

Rewrite the generateReport to work with this interface as follows:

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

With your approach, the trick to transform the map into a vector introductes only an additional dependency: the report has to know about the internals of the inventory.

I'd rather recommend to go the way of the vistitor design pattern : the goal is to separate the algorithm (producing the report, the visitor) from the datastructure you explore (the inventory and its items).

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

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

This could also simplify the implementation of your inventory, as you'd no longer need to foresee different containers for different kind of items (provided they all inherit from some common element base class).

Theres is plenty of litterature on this pattern. I recommend you Design patterns, elements of reusable object oriented software from Gamma & al: its the orginal textbook, and guess what, the demo code shows an inventory with a pricing visitor ;-)

Here a naive on-line example based on your problem, to illustrate how it could work.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM