设置一系列基/派生类来处理天气数据



我正在设计一个程序,该程序从世界各地的一堆气象站获取数据并在其上运行一些时间序列数据。 我正在寻找有关如何正确设置类结构的一些指导。我对设计原则的了解非常基本,所以提前道歉 如果我以愚蠢的方式布置了它

程序:

  • 从世界各地的一堆气象站收集数据, 然后对其进行时间序列分析
  • 来自不同气象站的数据有不同的格式, 表示data_format_1,data_format_2

转换此原始数据有 2 个步骤:

  • 首先进入一个称为weather_data_for_processing的结构 - 它 包含处理数字实际需要的数据,以及一些技术数据 数据,例如保存数据的格式
  • 然后是一个名为weather_data_for_crunching的结构,它只包含处理数字所需的数据

它几乎是以前结构的一个子集,但我想为它创建一个单独的类,因为在现实生活中,这些类很大,并且传递不必要的数据会变得混乱

我做了以下工作:

  • 创建了一个基类weather_station_core,它具有 所有气象站通用的数据
  • 创建了 2 个派生类,data_format_1, data_format_2它继承自核心,并描述了数据的 2 种格式 来自气象站的CSV文件
  • 包装所有内容的函数 - 称为process_weather_data_master
  • 从云端硬盘加载数据,然后对其进行转换,然后输入数字运算器
  • 在这个包装函数中,还有另一个函数充当 另一个包装纸 -analyse_weather_and_save
  • 包装器内部有实际的数字运算器功能- crunch_numbers

这些相互包装的函数中的每一个都有一组略有不同的输入,我正在努力创建一组健壮的类来:

  • 尽可能避免参数重复
  • 保持清洁/不凌乱

如果你能指导我正确的方向/或一般在哪里阅读,那就太神奇了,即使只是通用的指导

提前感谢您的任何帮助/指点

typedef std::pair<time_t, double> time_series_atom;
/// Every weather station has this data
struct weather_station_core{
int weather_station_id;
double latitude;
double longitude;
std::vector <time_series_atom> weather_data; 
};
/// Data Format 1
struct data_format_1 : weather_station_core {
int number_of_thermometers_at_station;
std::string thermometer_brand;
std::string file_format_to_save_processed_data_in;
};
/// Data Format 2
struct data_format_2 : weather_station_core {
int number_of_thermometers_at_station;
int year_started_operation;
};
/// data which is needed to perform the calculation PLUS some technical parameters, like how to save it on the drive
struct weather_data_for_processing : weather_station_core{  
std::vector <time_series_atom> weather_data_in_celcius; 
int number_of_thermometers_at_station;
std::string file_format_to_save_processed_data_in;
};
/// this structure is just the data which is needed to perform the calculation
struct weather_data_for_crunching : weather_station_core{  
std::vector <time_series_atom> weather_data_in_celcius; 
};
/// RESULTS
struct analysed_weather_data : weather_station_core{  
std::vector<double> measurement_error;
};

namespace weather{
/// Load data on weather stations from a CSV file - in 2 different formats
data_format_1 load_raw_input_format_1(std::string full_file_path_to_input_file); /// loads data from a CSV file into an object of data_format_1
data_format_2 load_raw_input_format_2(std::string full_file_path_to_input_file); /// loads data from a CSV file into an object of data_format_1
/// Process the data_format_1, data_format_2 input structures into something common that feeds into the next function
weather_data_for_processing process_format_1(data_format_1);
weather_data_for_processing process_format_2(data_format_2);
processed_weather_data_core reduce_data(weather_data_for_processing);
/// Process and crunch numbers
void process_weather_data_master(int format_id); /// outermost function containing analyse and save, and inside it, crunch
void analyse_weather_and_save(weather_data_for_processing); /// 2nd most outermost
analysed_weather_data crunch_numbers(weather_data_for_crunching); /// function wrapper inside the 2 functions above

/// Utility
void save_weather_data(analysed_weather_data, std::string full_file_path); // saves the processed data to drive
}

void weather::process_weather_data_master(int format_id){
std::string full_file_path_to_input_file = "C:/users/weather_data.csv";
data_format_1 D1; data_format_2 D2;
weather_data_for_processing DD:
if (format_id == 1) {D1 =  load_raw_input_format_1(std::string full_file_path_to_input_file);
analyse_weather_and_save(process_format_1(D1));
}
if (format_id == 2) {D2 =  load_raw_input_format_2(std::string full_file_path_to_input_file);
analyse_weather_and_save(process_format_2(D2));
}

}

void weather::analyse_weather_and_save(weather_data_for_processing D){
std::string drive_location = "C:/users/weather_data";
std::string file_format = D.file_format_to_save_processed_data_in;
std::string full_file_path = drive_location + "processed_weather_data" + file_format;
processed_weather_data_core F = reduce_data(D);
analysed_weather_data OUTPUT = crunch_numbers(F);
save_weather_data(OUTPUT,full_file_path);
}

这个问题对于Stackoverflow来说太宽泛了。这不是代码审查的地方,但我认为您有一个关于如何在处理多种文件格式的特定区域中避免代码重复的有效问题。

我将首先将每种文件格式的处理封装到一个类中,而不是使用单独的函数:

struct DataFormat1Loader {
data_format_1 load_raw_input_format(std::string full_file_path_to_input_file);
weather_data_for_processing process_raw_data(data_format_1);
};
struct DataFormat2Loader {
data_format_2 load_raw_input_format(std::string full_file_path_to_input_file);
weather_data_for_processing process_raw_data(data_format_2);
};

然后打开一些选项,你可以让这些加载器从抽象基类继承并多态地处理它们。或者,在函数模板中使用它们可能更容易:

template<typename FormatLoader>
void process_weather_data(FormatLoader loader) {
std::string full_file_path_to_input_file = "C:/users/weather_data.csv";
auto raw_data = loader.load_raw_input_format(full_file_path_to_input_file);
auto data_for_processing = loader.process_raw_data(raw_data);
analyse_weather_and_save(data_for_processing);
} 

然后,调用代码只需创建正确的文件格式加载器:

void weather::process_weather_data_master(int format_id) {
if (format_id == 1) {
process_weather_data(DataFormat1Loader{});
}
if (format_id == 2) {
process_weather_data(DataFormat2Loader{});
}
}

最新更新