这是否违反了“依赖倒置原则”?

时间:2012-04-22 03:22:15

标签: java design-patterns dependency-inversion

public class Connection {
public Connection(){

}

public String description() {
    return "Generic";
}

}

public class SqlServerConnection extends Connection{


public SqlServerConnection(){

}

public String description(){
    return "SQL Server";
}

}

public class OracleConnection extends Connection{
public OracleConnection(){

}

public String description(){
    return "Oracle";
}

}

public class MySqlConnection extends Connection{
public MySqlConnection(){

}

public String description(){
    return "MySQL";
}

}

public class FirstFactory {
String type;

public FirstFactory(String t){
    type = t;
}

public Connection createConnection(){
    if(type.equals("Oracle")){
        return new OracleConnection();
    }else if(type.equals("SQL Server")){
        return new SqlServerConnection();
    }else{
        return new MySqlConnection();
    }
}

}

public class TestConnection {
public static void main(String[] args) {
        FirstFactory factory;

        factory = new FirstFactory("Oracle");

        Connection connection = factory.createConnection(); //createConnection return concrete implementation not an abstraction

        System.out.println("You're connection with " + connection.description());
}

}

这是来自VTC设计模式视频教程我的问题是这个例子违反了依赖倒置原则吗?

因为TestConnection类依赖于具体实现,因为factory.createConnection()返回具体实现而不是抽象。

我可以通过这样做来解决这个问题吗?

public Connection createConnection(){

Connection connection = null;

if(type.equals("Oracle")){
    connection = new OracleConnection();
}else if(type.equals("SQL Server")){
    connection = new SqlServerConnection();
}else{
    connection = new MySqlServerConnection();
}
return connection;

}

4 个答案:

答案 0 :(得分:1)

理想情况下,您会将工厂注入TestConnection(即,它将ConnectionFactory作为参数,通过接口)而不是调用“new”来获取工厂。这样,TestConnection既不依赖于Factory或Connection的具体实现。

工厂返回Connection的具体实现很好 - 事实上,如果你想实际使用连接,这是必要的。您不依赖于特定具体实现,因为工厂将其作为Connection(即作为接口)返回。有人在某处确实必须实例化Connection实现 - 这是Factory的工作。

如果OracleConnection具有其他连接没有的某些方法,并且调用类依赖于那些,那么这将是违规的。不是这里的情况。

答案 1 :(得分:1)

虽然可以说你的通用架构不是实现数据库连接的最佳方式,但我会跳过它,因为我理解更多关于依赖倒置而不是数据库实现的问题。实现完全依赖性倒置:

  • Connection应该是一个接口,而不是具体的类。
  • ConnectionFactory应该是一个接口,而不是具体的类,它定义了返回createConnection()的{​​{1}}方法。它的构造函数中不应该包含参数。
  • 对于每个数据库,您将拥有一个实现Connection的不同具体类,并返回实现ConnectionFactory的对象。

上述内容更好地满足了依赖性倒置原则,因为现在TestConnection仅指定了服务提供者所需的内容,并未与任何具体实现相结合。可以创建和使用任何具体实现,只要它满足为TestConnection定义的接口所指定的要求,并且接口仅指定TestConnection真正需要的接口。

特别是,另一个软件包中的另一个供应商可以创建一个新的ConnectionFactory实现,您可以将其插入到代码中(如果您已遵循上述架构)和{{1 class不需要任何修改。

这支持了许多具体服务与服务客户端的运行时关联范例。例如,在典型的启动时依赖注入方案中,您会将Connection的具体实现注入TestConnection,然后它将如下所示:

ConnectionFactory

这将TestConnection完全与任何数据库的依赖关系分开,并且只需注入TestConnection即可轻松配置。或者,您可以执行服务查找,而不是“执行依赖注入”。 J2EE / J3EE广泛使用它,例如从JNDI public class TestConnection { private ConnectionFactory connectionFactory; public setConnectionFactory(ConnectionFactory connectionFactory) { this.connectionFactory = connectionFactory; } public static void main(String[] args) { // // Perform dependency injection here // // after dependency injection Connection connection = connectionFactory.createConnection(); //createConnection return concrete implementation not an abstraction System.out.println("You're connection with " + connection.description()); } } 对象中获取ConnectionFactory(或更典型地为ConnectionFactory)。这些超出了问题的范围,只是作为一个例子提供了你想要这样做的一个例子,以及一种检查你是否满意这个原则的方法。对于来自外部源(例如数据库驱动程序)的任何内容,DataSource应仅指代接口而不是类。

答案 2 :(得分:0)

依赖性倒置原则主体是

A - 高级模块不应该依赖于低级模块。两者都应该取决于抽象。

在你的情况下,你得到了抽象的连接,这很好。在我看来,工厂模式的使用也很好。

B - 抽象不应该依赖于细节。细节应取决于抽象。

您的Connection不依赖于较低的实现,并且继承的类可能使用Connection的方法/变量(如果示例可能更复杂)

顺便说一句,我倾向于使Connection成为一个抽象类,如果你以后要为它添加更多功能,而不是打扰为你制作的默认构造函数

public class Connection {
  public abstract String description();
}

或只是将其设为界面

public interface Connection {
  String description();
}

答案 3 :(得分:-1)

您提出的两个createConnection实施方案是等效的;返回连接的方向与存储变量中的连接并返回该连接之间没有功能差异。

至于是否存在违反依赖倒置的情况,我会说工厂很好,取决于它的使用方式。你想要的是让类以Connection作为参数,而不是让它直接调用以获得连接的工厂。