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

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

数据有数据库和文件两种存储方式。用数据库类和文件类分别负责去读取。
但数据库需要传入数据的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人已打赏

报告相同问题?