在这种情况下,我如何才能保持良好的数据封装
How can I maintain a good data encapsulation in this situation?
我是c++的新手,我正在尝试制作一个非常简单的CRUD程序。
在这个例子中,一个客户在商店里买了很多东西,这个商店有这个客户买的东西的信息。我称之为Inventory
。
商店希望为每个客户打印一个Report
。在下面的代码中,main只有一个Inventory,仅用于示例。
问题是:当我想打印报告时,我必须从客户端获取数据,但不能丢失封装。我的意思是,我希望任何类都不能修改清单的内容。
我想做的是将地图转换为向量(我需要一些东西来对数据进行排序),并传递这个向量(按常规分配)。我在类Inventory
中分配这个向量,但谁在删除是类Report
,这不是正确的做法,但如果不这样做,我不知道如何传递这些信息。
无论如何,报表类可以获得指向Book的指针,并使用其set
函数或指向其他Book。再说一遍,我不知道如何正确地做。
有人能给我一个提示吗?在这种情况下我该怎么办?
谢谢。
抱歉代码太长。
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
{
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();
}
分类库存单位:
class Inventory
{
private:
map<int, Book *> books;
public:
void addBook(int code, const string& name);
vector<pair<int, Book *>> * getBooks();
};
.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());
}
您的库存类应该有这个接口:
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;
使用您的方法,将map
转换为vector
的技巧只引入了一个额外的依赖项:报告必须了解库存的内部。
我建议采用visitor设计模式:目标是将算法(生成报告、访问者)与您探索的数据结构(库存及其项目)分离。
class Item { ...}; // Your object structure
class Book : public Item { ... };
class Inventory { ...};
class Visitor { ... }; // Algorithms that shall be executed on structure
class Report : public Visitor {...};
这也可以简化清单的实现,因为您不再需要为不同类型的项预见不同的容器(前提是它们都继承自某个公共元素基类)。
这个图案上有很多乱丢的东西。我推荐您设计模式,可重用的面向对象软件的元素来自Gamma&al:这是最初的教科书,你猜怎么着,演示代码显示了一个带有定价访问者的库存;-)
这里有一个基于你的问题的天真的在线例子,来说明它是如何工作的。
- 我是c ++的新手,你能解释一下在这种情况下的指针吗
- 在这种情况下,java对象是否可以调用本机函数
- 如何在没有数据拷贝的情况下从指针创建一个Eigen VectorXd对象
- 在这种情况下显式调用时,std::cout 如何更改析构函数的行为?
- 在这种情况下,我真的复制了字节还是复制了字符?
- 为什么在这种情况下,bool 类型的输出等于 0?
- 在这种情况下,如何传递成员函数而不是函数?
- 为什么在这种情况下递增阵列名称有效?
- 在这种情况下我应该使用哪种设计模式
- 为什么在这种情况下我需要 .template
- 在这种情况下,使用 string_view 是否会导致不必要的字符串复制?
- 我是否访问了已释放的内存,或者在这种情况下DrMemory报告不正确?
- 在这种情况下,"typename..."意味着什么?
- 为什么在这种情况下 x = 44?
- 在这种情况下是私有的吗?试图使操作员<<过载
- 在这种情况下,如何防止C++输出/控制台窗体关闭
- 为什么 lambda nullptr 取消引用在这种情况下有效?
- 对象无法访问其私人数据.错误:在这种情况下私有
- 在这种情况下,将数据存储在诸如SQLite之类的数据库中,还是存储在平面文本文件中更好
- 在这种情况下,我如何才能保持良好的数据封装