-1
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

4 回答 4

1

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

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

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

于 2012-04-22T03:41:25.723 回答
1

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

  • Connection应该是一个接口,而不是一个具体的类。
  • ConnectionFactory应该是一个接口,而不是一个具体的类,它定义了一个createConnection()返回Connection. 它不应该在其构造函数中需要参数。
  • 对于每个数据库,您将有一个不同的具体类来实现ConnectionFactory并返回实现Connection.

以上更好地满足了依赖倒置原则,因为现在 TestConnection 只指定了它需要从服务提供者那里得到什么,并且不耦合到任何具体的实现。任何具体的实现都可以被创建和使用,只要它满足为 TestConnection 定义的接口所指定的要求,并且接口指定的只是 TestConnection 真正需要的。

特别是,另一个包中的另一个供应商可以创建一个新的Factory实现Connection,您可以将其插入代码中(如果您遵循上述架构)并且您的TestConnection类不需要任何类型的修改。

这支持许多将具体服务与服务客户端关联的运行时范例。例如,在典型的启动时依赖注入场景中,您将注入一个具体实现ConnectionFactoryinto TestConnection,然后它看起来像:

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());
    }
}

这将 TestConnection 与对任何数据库的任何依赖完全分开,并且只需注入一个ConnectionFactory. 或者,您可以进行服务查找,而不是“执行依赖注入”。J2EE/J3EE 广泛使用它,例如DataSource从 JNDIContext对象中获取 ConnectionFactory (或更典型的是 a )。这些超出了问题的范围,仅作为示例提供了您为什么要这样做以及检查您是否满足该原则的一种方法。 TestConnection对于来自外部源(例如数据库驱动程序)的任何内容,应该只引用接口,而不是类。

于 2012-04-22T06:37:27.843 回答
0

依赖倒置原则原则是

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

在您的情况下,您已经抽象了 Connection,这很好。在我看来,工厂模式的使用也很好。

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

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

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

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

或者只是让它成为一个界面

public interface Connection {
  String description();
}
于 2012-04-22T06:38:03.770 回答
-1

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

至于是否存在一些违反依赖倒置的情况,我会说工厂有点好,这取决于它打算如何使用。您想要的是类将 aConnection作为参数,而不是拥有一个直接调用以获取连接的工厂。

于 2012-04-22T03:27:29.853 回答