我实现了一个类Database Manager
来管理两个数据库引擎上的操作。该类有一个私有变量databaseEngine
,它在使用类方法(删除数据库,创建数据库,运行脚本,比较,断开连接等)之前设置,并且基于此变量,类可以识别如何表现。
然而,我知道这是错误的,Database Manager
的方法充满了像这样的开关案例:
public void CreateNewDatabase(String databaseName){
switch (databaseEngine){
case "mysql":
//Executes a prepared statement for dropping mysql database (databaseName
break;
case "postgres":
//Executes a prepared statement for dropping postgres database (databaseName
break;
...
}
}
我需要一个很好的建议。我想加载配置和资源文件夹中的所有内容,我的意思是,准备好的创建和删除语句等等。如果需要支持新的数据库引擎,它将不会令人头疼,因为它只需要保存sql sripts在资源文件和配置文件中的任何其他数据。 请建议我对此案例有用的任何设计模式。
答案 0 :(得分:1)
每当需要基于switch语句调用不同的操作时,请考虑使用定义操作接口的抽象类和实现该操作的实现类。
在您的情况下,databaseEngine
是一个命名数据库的String。而是创建一个抽象类DatabaseEngine
并定义像createDatabase
:
public abstract class DatabaseEngine {
public abstract void createDatabase(String databaseName);
public abstract void dropDatabase(String databaseName);
}
并添加实现:
public class PostgresEngine extends DatabaseEngine {
public void createDatabase(String databaseName) {
... // do it the postgres way
}
}
然后在您的经理类
中使用它public void createNewDatabase(String databaseName) {
engine_.createDatabase(databaseName);
}
答案 1 :(得分:1)
第一件事:打开琴弦是如此古老的学校;如果有的话你会想要使用真正的枚举。但当然,这不是重点;切换枚举与从“OO设计”的角度切换字符串(关于你想到的东西)一样糟糕。
从OO的角度来看,wero的解决方案绝对是“正确的选择”。你看,好的OO设计始于SOLID;和SOLID以SRP开头。
在这种情况下,我会指出“改变SRP的方面只有一个原因”。事情是:如果你将2,3个,n个不同数据库的所有数据库处理推送到一个类......这意味着如果你的任何数据库需要更改,你必须更改那个类。除了显而易见的事实:为一个数据库提供“访问手段”(几乎更多),而不是单个类的“单一责任”。
另一种观点:这是关于平衡的。要么你对一个好的,结构良好的,“真正的OO类型”设计感兴趣...那么你必须咬紧牙关并定义一个接口或抽象基类;然后针对每个具体数据库实施/扩展。
或者您更喜欢“将所有东西都塞进一个班级”......然后保留您所拥有的东西,因为如果您使用由金或钢制成的门把手真的无关紧要......对于建造的房屋而言无论如何,在一个糟糕的地下室。
含义:您的switch语句只是设计不太理想的结果。现在决定是否要治愈症状或问题的根本原因。
答案 2 :(得分:1)
我实现了一个类数据库管理器,它管理两个数据库引擎上的操作。
如果您有三个或四个或五个不同的数据库/存储怎么办?例如,Oracle,MongoDB,Redis等。您是否仍然将所有这些实现都放入Database Manager
?
数据库管理器的方法充满了切换案例......
正如所料,因为你把所有东西放在一个班级里。
请建议我对这种情况有用的任何设计模式。
简化解决方案最简单的方法是将MySQL
和Postgree
实现彼此分开。您需要使用 Factory 和策略设计模式。如果有人看到一个开关,就应该考虑使用它们,但不要沉迷于模式。它们不是你的目标,即不要因为你可以将它们放在代码中的任何地方。
所以,你应该从定义你的抽象开始。如果所有数据库子类都有共同的功能,则创建一个接口或一个抽象类。
// I'm not sure what methods you need, so I just added methods you mentioned.
public interface MyDatabase {
void drop();
void create();
void runScript();
void compare();
void disconnect();
}
然后你需要实现数据库,实际上是策略。
public final class MySqlDatabase implements MyDatabase {
@Override
public void drop() {}
...
}
public final class PostgreDatabase implements MyDatabase {
@Override
public void drop() {}
...
}
最后,您需要创建工厂。如果您愿意,可以将其设置为静态或实现接口。
public class MyDatabaseFactory {
public MyDatabase create(String type) {
switch (type) {
case "mysql":
return new MySqlDatabase();
case "postgress":
return new PostgreDatabase();
default:
throw new IllegalArgumentException();
}
}
}
您不一定要传递字符串。它可以是一个选项/设置类,但它们有增长的趋势,这可能导致膨胀的类。但是不要过于担心,这不是你目前最大的问题。
最后,但并非最不重要。如果您不介意,请修改您的命名约定。请don't name your classes as managers or helpers。
答案 3 :(得分:0)
您可以为您的DatabaseEngines创建一个抽象基类,如下所示:
public abstract class DatabaseEngine {
public abstract void createDatabase(final String databaseName);
public abstract void dropDatabase(final String databaseName);
}
然后为您支持的每个DatabaseEngine创建具体实现:
public final class MySQLEngine extends DatabaseEngine {
@Override
public void createDatabase(final String databaseName) {
}
@Override
public void dropDatabase(final String databaseName) {
}
}
然后,当你想要创建/删除它时,它看起来会更像这样:
databaseEngine.createDatabase("whatever");
答案 4 :(得分:0)
这是基于意见的问题:但在我看来,你可以使用:
示例:
public interface IDataBaseEngine {
...
}
public class OracleDBConnection implements IDataBaseEngine {
...
}
public class MySQLDBConnection implements IDataBaseEngine {
....
}
public class DatabaseEngineFactory {
public IDataBaseEngine getDatabaseConnection() {
....
}
}
示例:
SQL文件: customer.table
<TABLE>
<SELECT>
<FROM>customer</FROM>
<WHERE>customer_id = ?</WHERE>
<ORDER_BY>customer_id<ORDER_BY>
</SELECT>
</TABLE>
现在,如果您的配置文件说您的数据库是oracle,那么在编译上面的SQL文件时,它将创建以下SQL文件:
SELECT * FROM customer
WHERE customer_id = ?
ORDER BY customer_id