c++ - 从文件加载时使用工厂

标签 c++ design-patterns factory

我是 C++ 的相对论新手,虽然我确实有一点 java 经验。
试图解决以下问题;(这是我大学一项更大任务的一部分)

class myCustomer :public Customer {/.../}
class myFlight:public Flight {/.../}
class myEmployee :public Employee {/.../}
class myPlane :public Plane {/.../}

所以 Customer 是一个接口(interface),而 myCustomer 是一个具有实现的派生类,其余部分也是如此。(我必须那样使用它)

其次是这个(某种)飞行公司数据库的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)创建指定的对象,我必须为其他类(飞机、预订、航类......)
每个都有自己的构造函数,具有不同数量的参数。
这些类之间的唯一联系是它们都实现了一个具有功能的 ID 接口(interface):
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;
 }

并让 load 方法决定创建哪个对象(可能发送一个 char 作为标识符),使用上面的 create 方法,
让每个类实现工厂接口(interface),而不是使用 create 函数,如下所示:
//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 更改为
 map <string,Factory *> objectName_map;

现在我有点卡住了,因为 map 包含指向工厂对象的指针,我想使用 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){//...//}

由于 map 持有 Factory* 。
我试图保持 map 原样,但无法在创建函数中使用它们,因为它无法将 myCustomer* 对象转换为 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));
    }
}

然后为所有 map 和文件名调用此函数 6 次?

关于c++ - 从文件加载时使用工厂,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53560656/

相关文章:

c++ - 将 irrlicht 类注册到 angelscript 中会得到 <未解析的重载函数类型>

java - 适当的模式来跟踪 N 个最近的值

design-patterns - 用 Dart 模式代替静态继承

ruby-on-rails - 六边形架构的缺点

c++ - 对 `GdiplusStartup@12' 的 undefined reference

c++ - 在c++中确定字符串中不同子字符串的数量并使用散列

c++ - 静态变量与静态成员

angular - ng4 componentFactory 将它放在 DOM 目标中

c++ - C++ 接口(interface)中的静态反序列化工厂

c++ - 工厂模式与全局状态不是一回事吗?