Использование фабрики при загрузке из файла - PullRequest
0 голосов
/ 30 ноября 2018

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

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

Таким образом, Customer - это интерфейс, а 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, который имеет функцию:

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

и пусть метод загрузки решит, какой объект создать (возможно, отправит символ в качестве идентификатора), используя метод 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 <string,Factory *> objectName_map;

Теперь я вроде застрял, так как карта содержит указатель на объект фабрики,и я хочу использовать идентификаторы карт, чтобы сделать следующее:

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 *.Я немного потерян, пытался найти решения в Интернете, но не повезло, хотя я чувствую, что реализую это неправильно.Заранее спасибо за любую помощь с этим!

* Отредактированный пост, чтобы прояснить проблему

1 Ответ

0 голосов
/ 30 ноября 2018

Итак, вам действительно нужен «фабричный» шаблон:

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 раз для всех ваших карт и имен файлов?

...