如何选择可抽象多源IO操作的输入数据处理设计模式
适配方案:使用策略模式
策略模式可以把不同数据源的读写操作封装成独立的策略类,所有策略类都实现同一个抽象接口,上层的文本处理逻辑只和抽象接口交互,不需要感知底层是文件、管道还是套接字,完美适配你现在需要扩展多数据源的需求。如果后续需要新增其他类型的数据源,只需要新增对应策略实现即可,不需要修改原有处理逻辑,符合开闭原则。
实现示例
第一步:定义抽象数据源接口
所有数据源都要实现该接口的核心操作,上层逻辑仅依赖该抽象接口:
#include <string> #include <stdexcept> // 抽象数据源策略接口 class DataSource { public: virtual ~DataSource() = default; // 打开数据源,参数为对应资源的标识(文件路径/管道名/套接字地址等) virtual void open(const std::string& resource) = 0; // 读取一行内容,返回值表示是否还有更多内容可读 virtual bool readLine(std::string& line) = 0; // 关闭数据源 virtual void close() = 0; // 判断数据源是否处于可用状态 virtual bool isValid() const = 0; };
第二步:实现文件数据源策略类
适配你原有文件读取的逻辑:
#include <fstream> class FileDataSource : public DataSource { private: std::ifstream file; public: void open(const std::string& filePath) override { file.exceptions(std::ifstream::failbit | std::ifstream::badbit); file.open(filePath); } bool readLine(std::string& line) override { if (file.peek() == EOF) { return false; } std::getline(file, line); return true; } void close() override { if (file.is_open()) { file.close(); } } bool isValid() const override { return file.is_open(); } };
第三步:扩展管道数据源实现示例
新增其他数据源仅需要实现抽象接口即可,原有处理逻辑无需修改:
#include <fcntl.h> #include <unistd.h> class PipeDataSource : public DataSource { private: int pipeFd = -1; static const size_t BUF_SIZE = 1024; public: void open(const std::string& pipeName) override { pipeFd = ::open(pipeName.c_str(), O_RDONLY); if (pipeFd < 0) { throw std::runtime_error("Failed to open pipe"); } } bool readLine(std::string& line) override { // 此处为简化的按行读取示例,生产环境可自行完善换行判断逻辑 char buf[BUF_SIZE]; ssize_t len = ::read(pipeFd, buf, BUF_SIZE - 1); if (len <= 0) return false; buf[len] = '\0'; line = buf; return true; } void close() override { if (pipeFd >= 0) { ::close(pipeFd); pipeFd = -1; } } bool isValid() const override { return pipeFd >= 0; } };
第四步:上层统一处理逻辑
完全不依赖具体的数据源类型,所有数据源都可以复用该处理逻辑:
#include <iostream> void processDataSource(DataSource& source, const std::string& resource) { try { source.open(resource); if (source.isValid()) { std::string line; while (source.readLine(line)) { // 原有行处理逻辑完全不需要修改,直接复用即可 // process line here } source.close(); } } catch (const std::exception& e) { std::cout << "Processing error: " << e.what() << std::endl; return; } catch (...) { std::cout << "Unknown error occurred" << std::endl; } }
使用示例
int main() { // 处理文本文件 FileDataSource fileSource; processDataSource(fileSource, "test.txt"); // 处理管道 PipeDataSource pipeSource; processDataSource(pipeSource, "/tmp/test.pipe"); // 后续扩展套接字仅需要新增SocketDataSource实现类即可直接调用 // SocketDataSource socketSource; // processDataSource(socketSource, "127.0.0.1:8080"); return 0; }
扩展说明
如果需要根据配置动态生成不同类型的数据源实例,可以搭配工厂模式封装数据源的创建逻辑,上层仅需要传入数据源类型即可拿到对应实例,进一步降低耦合。
内容的提问来源于stack exchange,提问作者AreaOfGreenNoise
相关产品推荐
相关产品推荐

