我是设计图案的新手. 我正在实施一个工具,可以连接到不同的数据库根据用户的需要. 这是我的代码 struct .

enter image description here

在控制器中,我有我的API调用.下面我粘贴了获取服务器中所有数据库的POST API调用

 @PostMapping("/allDatabases")
    public List<String> getDatabases(@RequestBody DatabaseModel db) 
        throws IOException, SQLException {
        
        return migrationInterface.getAllDatabases(db);
         

    }

目前,我通过调用服务包内部接口中的方法来获得响应. 但当数据库服务器发生变化时(例如:Postgres、MySQL),我必须使用不同的查询.

例:

public class PostgresPreparedStatements {

    public PreparedStatement getAllDbs(Connection con) throws SQLException {
        
    return con.prepareStatement(
        "SELECT datname FROM pg_database 
             WHERE datistemplate = false;");
    }
    
    
}

此查询在MySQL数据库中不起作用.因此,我将为不同的数据库保留不同的预准备语句.我的 idea 是从控制器调用BaseAdapter并判断服务器类型,如下所示.

public class BaseAdapter {
    
    public void checkServerType(String server) {
        
        switch(server) {
            case "postgres" :
//               postgres functions
                break;
            case "mysql" :
//              mysql functions
                break;
            default: 
                break;
        }   
    }

}

如果服务器是Postgres,我想调用PostgresConnector.java.在连接器中,我想调用Facade来调用函数和相关查询.

你知道怎么做吗?

请注意:目前我正在为Postgres和MySQL实现这一点,但在future ,这应该适用于任何数据库.

推荐答案

当您想要在 case 中添加新行为(如新数据库)时,不使用适配器模式.适配器类的目标是允许其他类访问existing功能.Adapter converts the interface of one class into something that may be used by another class.

看起来BaseAdapter有责任为不同的数据库 Select SQL语句.我们可以解释这一责任,就像我们希望基于数据库生成SQL查询一样.所以看起来像是 我们可以用HashTable(Java)或Dictionary(C#)替换这条switch语句.这个HashTable(Java)或Dictionary(C#)可以是创建SQL查询的简单工厂.生成的SQL查询可以作为具体数据库的策略.

因此,让我们潜入代码中.

看起来这是一个可以使用Strategy pattern的地方:

策略模式是一种行为软件设计模式,它支持 在运行时 Select 算法.而不是实现单个 算法,代码接收运行时指令,关于在 要使用的一系列算法.

让我通过C#展示一个例子.我很抱歉我不是Java爱好者,但是我提供了关于代码在Java中看起来如何的 comments .

我们需要有一些共同的行为,这些行为将在所有战略中共享.在我们的例子中,它只是来自不同数据Provider 的GetAllDbs()种方法:

public interface IDatabaseStatement
{
    IEnumerable<string> GetAllDbs();
}

以及它的具体实施.以下是可交换的策略:

public class PostgresDatabaseStatement : IDatabaseStatement // implements in Java
{
    public IEnumerable<string> GetAllDbs()
    {
        return new [] { "PostgresDatabaseStatement" };
    }
}

public class MySQLDatabaseStatement : IDatabaseStatement // implements in Java
{
    public IEnumerable<string> GetAllDbs()
    {
        return new[] { "MySQLDatabaseStatement" };
    }
}

public class SqlServerDatabaseStatement : IDatabaseStatement // implements in Java
{
    public IEnumerable<string> GetAllDbs()
    {
        return new[] { "SqlServerDatabaseStatement" };
    }
}

我们需要一个可以存储所有战略的地方.我们应该能够从这家store 获得必要的战略.因此,这是一个可以使用简单工厂的地方.简单的工厂不是Factory method pattern也不是Abstract factory.

public enum DatabaseName
{
    SqlServer, Postgres, MySql
}

public class DatabaseStatementFactory
{
    private Dictionary<DatabaseName, IDatabaseStatement> _statementByDatabaseName
        = new Dictionary<DatabaseName, IDatabaseStatement>()
        {
                { DatabaseName.SqlServer, new SqlServerDatabaseStatement() },
                { DatabaseName.Postgres, new PostgresDatabaseStatement() },
                { DatabaseName.MySql, new MySQLDatabaseStatement() },
        };

    public IDatabaseStatement GetInstanceByType(DatabaseName databaseName) =>
        _statementByDatabaseName[databaseName];
}

这样您就可以更轻松地获取所需存储的实例:

DatabaseStatementFactory databaseStatementFactory = new();
IDatabaseStatement databaseStatement = databaseStatementFactory
    .GetInstanceByType(DatabaseName.MySql);
IEnumerable<string> allDatabases = databaseStatement.GetAllDbs(); // OUTPUT: 
    // MySQLDatabaseStatement 

这一设计符合open/closed principle标准.

Mysql相关问答推荐

如何获得表中只有最大值行的一个列被另一个列分区?

如果WHERE语句包含所有列,唯一键顺序是否重要?

数组上的MySQL、JSON_CONTAINS用法

使用字符串文字与使用日期文字时的SQL行为

为什么嵌套循环逻辑不能按预期工作

多个 FULLTEXT 索引上的 MySQL SELECT.结果极其缓慢

错误1075:表定义不正确;只能有一个自动列,它必须定义为一个键(使用 gorm 和 mysql)

在一个 SQL 查询中对同一列中相同类型的不同值求和

从 SQL 中的左连接和内连接中减go 计数

mysql从另一个表中 Select 不相等的值

避免重复进入mysql数据库的最佳方法

如何使用 laravel 连接 mysql?

如何在 Windows 上访问 xampp 的命令行

在 MySQL 的存储过程中调用存储过程

mysql 按日期 Select 总和组

如何为 php 启用 mysqlnd?

如何改进 INSERT INTO ... SELECT 锁定行为

警告:mysqli_connect(): (HY000/1045): Access denied for user 'username'@'localhost' (using password: YES)

Yii2 如何进行 where AND 或 OR 条件分组?

将mysql查询输出存储到shell变量中