从文件加载时使用工厂
Using factory when loading from file
我是 C++ 的相对论新手,尽管我在 java 方面有一点经验。
尝试解决以下问题;(这是我大学更大任务的一部分)
class myCustomer :public Customer {/.../}
class myFlight:public Flight {/.../}
class myEmployee :public Employee {/.../}
class myPlane :public Plane {/.../}
所以 Customer 是一个接口,而 myCustomer 是派生的 class 与实现,其余部分也是如此。(我必须那样使用它)
后跟这个(某种)API 用于航班公司数据库;
class MyImplementation{
//I want to link id's to an object so i can call object pointer using a given id
map <string,myCustomer*> customers_map;
map <string,myEmployee*> employees_map;
map <string,myReservation*> reservations_map;
map <string,myPlane*> planes_map;
map <string,myFlight*> flights_map;
...
//must implement this function
virtual Customer* addCustomer(string full_name, int priority){
if(!customers_loaded){
load_customers();
}
auto curr_customer = new myCustomer(id,full_name,priority);
customers_map.insert(pair<string,myCustomer*>(id,curr_customer));
}
void load_customers(){
vector<string> parameters;
string line;
fstream customers_file;
customers_file.open(CUSTOMER_INFO_PATH,fstream::out);
//check if null is returned
if (!customers_file.is_open()) {
throw "Error:cannot open employees file";
}
//iterate over lines
while(getline(customers_file,line)){
//just a function to split a line from file to a vector
parameters=splitLine(line,SPLITTER);
try{
customer_from_string(parameters);
}catch(...){
//could not load current object
cout << "Could not load customer "<< parameters[0] <<
"(line number:"<< lineNumber << ")" <<endl;
continue;
}
}
customers_file.close();
}
void customer_from_string(vector<string> parameters){
string id = parameters[0];
string name = parameters[1];
int priority = stoi(parameters [2];
auto curr_customer = new myCustomer(id,name,priority);
customers_map.insert(pair<string,myCustomer*>(id,curr_customer));
}
void employee_from_string(vector<string>& parameters,
map<string, string>& toLink) {
//get parameters
string employee_id = parameters[0];
Jobs job = string_to_job(parameters[1]);
int seniority = stoi(parameters[2]);
int year = stoi(parameters[3]);
string employer_id = parameters[4];
//check if employee_id is legal
if (employer_id.empty()) {
throw "Employer ID cannot be an empty argument";
}
auto curr_employee = new myEmployee(employee_id, job, seniority,year);
//add to employee map
employees_map.insert(pair<string, myEmployee *>(employee_id, curr_employee));
}
/** more code**/
所以我尝试从文本文件中读取参数,并使用 customer_from_string、employee_from_string 等匹配函数创建指定的对象,我必须为另一个 class 这样做es(飞机,预订,航班......)
每个都有自己的构造函数,参数数量不同。
这些 classes 之间的唯一联系是它们都实现了具有功能的 ID 接口:
virtual string getID() = 0;
尽量避免以下代码重复(所以我不会为每个对象创建加载函数):
void load_employees() {
/** same code as load_customers**/
//iterate over lines
while (getline(employees_file, line)) {
//as before
parameters = splitLine(line, SPLITTER);
try {
/*the only change - it has different implementation than customer_from_string*/
employee_from_string(parameters);
} catch (...) {
/** print error **/
}
}
/** as before **/
}
我知道我需要使用工厂设计模式来解决这个问题。(因为我需要动态创建文本文件中列出的对象,每次打开程序时将它们加载到数据库中)
所以我考虑实施以下内容:
class Factory {
virtual void create(vector<string>& parameters,
map<string,Factory*>&id_map,/*..more parameters*/)=0;
}
并让加载方法决定创建哪个对象(可能发送一个字符作为标识符),使用上面的创建方法,
让每个 class 实现工厂接口,然后使用创建函数,如下所示:
//Implementation for customer
void create(vector<string>& parameters,map<Factory *, string>&
toLink,map<string,Factory*>& id_map){
string id = parameters[0];
string name = parameters[1];
int priority = stoi(parameters [parameters.size()-1]);
auto curr_customer = new myCustomer(id,name,priority);
id_map.insert(pair<string,Factory *>(id,curr_customer));
}
所以我想我需要将地图更改为
map <string,Factory *> objectName_map;
现在我有点卡住了,因为地图包含指向工厂对象的指针,我想使用地图 ID 来执行以下操作:
virtual Customer* getCustomer(string id){ //must implement this function
if(!customers_loaded){
load('Customers');
}
return customers_map.find(id)->second;
}
我不能为每个对象调用任何内部函数,之后,让我们说:
void setEmployer(Employee* employer){//...//}
因为地图上有工厂*。
我试图保持地图原样,但无法在创建函数中使用它们,因为它无法将 myCustomer* 对象转换为 Factory* 。
我有点迷路,试图在网上找到解决方案但没有运气,尽管我觉得我实施这个错误。
在此先感谢您对此的任何帮助!
*编辑 post 使问题更清楚
那么,您真正需要的是一个 "factory" 模板:
template<typename T>
pair<string, shared_ptr<T>>
from_string_vector(const vector<string>& parameters);
具有明确的专业化,例如:
template<>
pair<string, shared_ptr<myCustomer>>
from_string_vector(const vector<string>& parameters) {
string id = parameters[0];
string name = parameters[1];
int priority = stoi(parameters [2]);
return make_pair(id, make_shared<myCustomer>(
id, name, priority));
}
和通用函数如:
template<typename T>
void load_database(map<string, shared_ptr<T>>& objectMap,
const string& filename) {
vector<string> parameters;
string line;
ifstream file(filename);
while (getline(file, line)) {
parameters = splitLine(line, SPLITTER);
objectMap.insert(from_string_vector<T>(parameters));
}
}
然后为所有地图和文件名调用此函数 6 次?
我是 C++ 的相对论新手,尽管我在 java 方面有一点经验。 尝试解决以下问题;(这是我大学更大任务的一部分)
class myCustomer :public Customer {/.../}
class myFlight:public Flight {/.../}
class myEmployee :public Employee {/.../}
class myPlane :public Plane {/.../}
所以 Customer 是一个接口,而 myCustomer 是派生的 class 与实现,其余部分也是如此。(我必须那样使用它)
后跟这个(某种)API 用于航班公司数据库;
class MyImplementation{
//I want to link id's to an object so i can call object pointer using a given id
map <string,myCustomer*> customers_map;
map <string,myEmployee*> employees_map;
map <string,myReservation*> reservations_map;
map <string,myPlane*> planes_map;
map <string,myFlight*> flights_map;
...
//must implement this function
virtual Customer* addCustomer(string full_name, int priority){
if(!customers_loaded){
load_customers();
}
auto curr_customer = new myCustomer(id,full_name,priority);
customers_map.insert(pair<string,myCustomer*>(id,curr_customer));
}
void load_customers(){
vector<string> parameters;
string line;
fstream customers_file;
customers_file.open(CUSTOMER_INFO_PATH,fstream::out);
//check if null is returned
if (!customers_file.is_open()) {
throw "Error:cannot open employees file";
}
//iterate over lines
while(getline(customers_file,line)){
//just a function to split a line from file to a vector
parameters=splitLine(line,SPLITTER);
try{
customer_from_string(parameters);
}catch(...){
//could not load current object
cout << "Could not load customer "<< parameters[0] <<
"(line number:"<< lineNumber << ")" <<endl;
continue;
}
}
customers_file.close();
}
void customer_from_string(vector<string> parameters){
string id = parameters[0];
string name = parameters[1];
int priority = stoi(parameters [2];
auto curr_customer = new myCustomer(id,name,priority);
customers_map.insert(pair<string,myCustomer*>(id,curr_customer));
}
void employee_from_string(vector<string>& parameters,
map<string, string>& toLink) {
//get parameters
string employee_id = parameters[0];
Jobs job = string_to_job(parameters[1]);
int seniority = stoi(parameters[2]);
int year = stoi(parameters[3]);
string employer_id = parameters[4];
//check if employee_id is legal
if (employer_id.empty()) {
throw "Employer ID cannot be an empty argument";
}
auto curr_employee = new myEmployee(employee_id, job, seniority,year);
//add to employee map
employees_map.insert(pair<string, myEmployee *>(employee_id, curr_employee));
}
/** more code**/
所以我尝试从文本文件中读取参数,并使用 customer_from_string、employee_from_string 等匹配函数创建指定的对象,我必须为另一个 class 这样做es(飞机,预订,航班......) 每个都有自己的构造函数,参数数量不同。 这些 classes 之间的唯一联系是它们都实现了具有功能的 ID 接口:
virtual string getID() = 0;
尽量避免以下代码重复(所以我不会为每个对象创建加载函数):
void load_employees() {
/** same code as load_customers**/
//iterate over lines
while (getline(employees_file, line)) {
//as before
parameters = splitLine(line, SPLITTER);
try {
/*the only change - it has different implementation than customer_from_string*/
employee_from_string(parameters);
} catch (...) {
/** print error **/
}
}
/** as before **/
}
我知道我需要使用工厂设计模式来解决这个问题。(因为我需要动态创建文本文件中列出的对象,每次打开程序时将它们加载到数据库中) 所以我考虑实施以下内容:
class Factory {
virtual void create(vector<string>& parameters,
map<string,Factory*>&id_map,/*..more parameters*/)=0;
}
并让加载方法决定创建哪个对象(可能发送一个字符作为标识符),使用上面的创建方法, 让每个 class 实现工厂接口,然后使用创建函数,如下所示:
//Implementation for customer
void create(vector<string>& parameters,map<Factory *, string>&
toLink,map<string,Factory*>& id_map){
string id = parameters[0];
string name = parameters[1];
int priority = stoi(parameters [parameters.size()-1]);
auto curr_customer = new myCustomer(id,name,priority);
id_map.insert(pair<string,Factory *>(id,curr_customer));
}
所以我想我需要将地图更改为
map <string,Factory *> objectName_map;
现在我有点卡住了,因为地图包含指向工厂对象的指针,我想使用地图 ID 来执行以下操作:
virtual Customer* getCustomer(string id){ //must implement this function
if(!customers_loaded){
load('Customers');
}
return customers_map.find(id)->second;
}
我不能为每个对象调用任何内部函数,之后,让我们说:
void setEmployer(Employee* employer){//...//}
因为地图上有工厂*。 我试图保持地图原样,但无法在创建函数中使用它们,因为它无法将 myCustomer* 对象转换为 Factory* 。 我有点迷路,试图在网上找到解决方案但没有运气,尽管我觉得我实施这个错误。 在此先感谢您对此的任何帮助!
*编辑 post 使问题更清楚
那么,您真正需要的是一个 "factory" 模板:
template<typename T>
pair<string, shared_ptr<T>>
from_string_vector(const vector<string>& parameters);
具有明确的专业化,例如:
template<>
pair<string, shared_ptr<myCustomer>>
from_string_vector(const vector<string>& parameters) {
string id = parameters[0];
string name = parameters[1];
int priority = stoi(parameters [2]);
return make_pair(id, make_shared<myCustomer>(
id, name, priority));
}
和通用函数如:
template<typename T>
void load_database(map<string, shared_ptr<T>>& objectMap,
const string& filename) {
vector<string> parameters;
string line;
ifstream file(filename);
while (getline(file, line)) {
parameters = splitLine(line, SPLITTER);
objectMap.insert(from_string_vector<T>(parameters));
}
}
然后为所有地图和文件名调用此函数 6 次?