关于数据库连接架构的设计难题

Design puzzle about database connectivity architecture

本文关键字:难题 数据库连接      更新时间:2023-10-16

我正在设计一个数据库浏览应用程序,它到目前为止还支持MySQL,但最近我开始实现支持Sqlite,我在设计连接架构实现的方式时遇到了一些丑陋的问题。这只是关于"连接"部分(即:在哪里你得到用户/db/主机,或sqlite的文件名),而不是数据库功能。那已经整理好了。

我有一个基类"连接",它暴露了"正常"方法,如name(),或纯虚拟方法,如virtual string fullLocation() = 0,它返回给我一个字符串,可用于识别数据库(如:MySql的database@host,或Sqlite的/etc/mydb.sqlite)。

现在,用户当然需要指定他想要连接的数据库,因此在应用程序的GUI中,他只需选择类型,然后填写凭据。我的麻烦开始了。我创建了一个MySqlConnection和一个SqliteConnection类,都是从Connection派生的,但大多数情况下,我最终会得到类似的东西:

        Connection* c = 0;
        if(gui->engine_name() == "MYSQL")
        {
            string host = gui->getHost();
            string user = gui->getUser();
            string password = gui->getPassword();
            int port = gui->getPort();
            string db = gui->getDatabase();
            c = new MySqlConnection(host, user, password, db, port);
        }
        else
        {
            string dbFile = gui->getSqliteDbFile();
            c = new SqliteConnection(dbFile);
        }
        string meta = application->use_connection(&c);

和我担心,这将持续整个应用程序,由于这两个数据库引擎的性质如此不同。

你有一些关于如何以优雅的方式解决这个问题的指导吗?

您需要模式工厂,它将以抽象的方式为您创建连接。这是肤浅的回答。这个工厂可以很好地用Builder模式参数化。像这样:

 ParamBuilder *b = new ParamBuilder;
 if(gui->engine_name() == "MYSQL")
 {
      b->setHost(gui->getHost())
       ->setUser(gui->getUser());
       ->setPassword(gui->getPassword());
        ...
  }
  else
  {
      b->setFile(gui->getSqliteDbFile());
  }
  Connection *c = globalConnectionFactory->createConnection(b);

更优雅的方法是设计一个工厂类并在该工厂的GenerateConnection()方法中处理GUI输入:

void ConnectionFactory::GenerateConnection(Connection* c)
{
 if(gui->engine_name() == "MYSQL")
    {
        string host = gui->getHost();
        string user = gui->getUser();
        string password = gui->getPassword();
        int port = gui->getPort();
        string db = gui->getDatabase();
        c = new MySqlConnection(host, user, password, db, port);
    }
    else
    {
        string dbFile = gui->getSqliteDbFile();
        c = new SqliteConnection(dbFile);
    }
}

如果你不喜欢依赖gui,你可以定义一个名为Parameters的结构体,并根据gui的输入更新它的实例,然后把这个对象交给连接工厂的连接生成方法。