数据有数据库和文件两种存储方式。用数据库类和文件类分别负责去读取。
但数据库需要传入数据的ID,而文件需要传入文件的路径。它们调用的参数不同。
应该如何设计一个统一的调用接口?有什么好的设计模式吗?
目前我能想到的方法是,传入参数的地址指针,或者传入参数的基类,类内部去将这个指针转换为自己需要的参数类型。
数据有数据库和文件两种存储方式。用数据库类和文件类分别负责去读取。
但数据库需要传入数据的ID,而文件需要传入文件的路径。它们调用的参数不同。
应该如何设计一个统一的调用接口?有什么好的设计模式吗?
目前我能想到的方法是,传入参数的地址指针,或者传入参数的基类,类内部去将这个指针转换为自己需要的参数类型。
继承和多态不仅规定了函数的名称、参数、返回类型,还规定了类的继承关系。耦合性太强,
在没有反射的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();
是不是比一拳拳总打在棉花上的大多数设计模式看着舒服