Jaf932074323 2021-06-03 10:57 采纳率: 0%
浏览 261
已结题

不同的数据处理类,如何定义统一的调用接口?有好的设计模式吗?

数据有数据库和文件两种存储方式。用数据库类和文件类分别负责去读取。
但数据库需要传入数据的ID,而文件需要传入文件的路径。它们调用的参数不同。
应该如何设计一个统一的调用接口?有什么好的设计模式吗?

目前我能想到的方法是,传入参数的地址指针,或者传入参数的基类,类内部去将这个指针转换为自己需要的参数类型。

  • 写回答

6条回答 默认 最新

  • _mervyn 2021-06-03 18:08
    关注

    继承和多态不仅规定了函数的名称、参数、返回类型,还规定了类的继承关系。耦合性太强,
    在没有反射的c++中使用这些就是在找罪受,我认为在现代c++中(有了std::bind和std::function之后)很多设计模式没有存在的必要。
    用class封装是根本的,我建议在有了std::bind和std::function之后,只要基于对象的设计就足以,在大多数情况下绝对不要使用继承, 顶多在单纯为了功能的继承时使用继承就可以了。

    说回你的问题,
    我们首先一拳到肉,直接解决问题本身:

    //定义数据读取完毕后的回调
    typedef std::function<void(const void*, unsigned int)> DataCallback;
    //定义读取函数,只需传入回调地址获取数据
    typedef std::function<int(DataCallback)> DataReader;
    //从数据库读
    class ReadFromDatabase
    {
    public:
    	int read(int id ,DataCallback cb)
    	{
    		const void* data;
    		unsigned int dataLengh;
    		//... 
    		//...
    		//根据id 读取数据至data和dataLengh后回调出去
    		if (cb)
    		{
    			cb(data , dataLengh);
    		}
    		return 0;
    	}
    };
    //从文件读
    class ReadFromFile
    {
    public:
    	int read(const std::string& path,DataCallback cb)
    	{
    		const void* data;
    		unsigned int dataLengh;
    		//... 
    		//...
    		//根据path 读取数据至data和dataLengh后回调出去
    		if (cb)
    		{
    			cb(data, dataLengh);
    		}
    		return 0;
    	}
    };

    好了,现在已经有了问题的解决者,关键就在怎么调用了。
    你的问题中,有一点不可避免,那就是你总有一个时刻需要知道从哪里读取数据并决定使用id还是路径作为参数。
    如果这个时刻在你抽象的业务逻辑中,那么统一的接口是毫无意义的。因为你的逻辑本身就已经if else了,何必再去统一呢?
    换句话说,“判断从哪读”的这个逻辑不应该被抽象。你抽象出来的业务逻辑应该只管“读”即可。
    也就是你的业务开始前就应该需要知道“从哪读,哪个id或哪个路径”。这种业务才需要被抽象,才需要一个统一接口。

    上面的例子就定义了一个统一的接口DataReader,那么只要在业务开始前决定一个DataReader使用就可以了。

    class Reader
    {
    public:
    	static DataReader fromDatabase(int id)
    	{
    		return std::bind(&ReadFromDatabase::read, 
    			std::make_shared<ReadFromDatabase>(), 
    			id,
    			std::placeholders::_1);
    	}
    	static DataReader fromFile(const std::string& path)
    	{
    		return std::bind(&ReadFromFile::read,
    			std::make_shared<ReadFromFile>(),
    			path,
    			std::placeholders::_1);
    	}
    };
    class Business
    {
    public:
    	Business(const DataReader& fromWhere)
    		: reader_(fromWhere)
    	{}
    	void run()
    	{
    		//...
    		//...
    		if (reader_)
    		{
    			reader_(std::bind(&Business::dataReadDone, this, std::placeholders::_1, std::placeholders::_2));
    		}
    		//...
    		//...
    	}
    private:
    	void dataReadDone(const void* data, unsigned int size)
    	{
    		//...
    	}
    private:
    	DataReader reader_;
    	//...
    	//...
    };

    业务:

    Business b(Reader::fromDatabase(data_id));
    // Business b(Reader::fromFile(path));
    b.run();

    是不是比一拳拳总打在棉花上的大多数设计模式看着舒服

    评论
    1人已打赏

报告相同问题?

悬赏问题

  • ¥15 活动选择题。最多可以参加几个项目?
  • ¥15 飞机曲面部件如机翼,壁板等具体的孔位模型
  • ¥15 vs2019中数据导出问题
  • ¥20 云服务Linux系统TCP-MSS值修改?
  • ¥20 关于#单片机#的问题:项目:使用模拟iic与ov2640通讯环境:F407问题:读取的ID号总是0xff,自己调了调发现在读从机数据时,SDA线上并未有信号变化(语言-c语言)
  • ¥20 怎么在stm32门禁成品上增加查询记录功能
  • ¥15 Source insight编写代码后使用CCS5.2版本import之后,代码跳到注释行里面
  • ¥50 NT4.0系统 STOP:0X0000007B
  • ¥15 想问一下stata17中这段代码哪里有问题呀
  • ¥15 flink cdc无法实时同步mysql数据