-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 デザイン パターンのビデオ チュートリアルからのものです。

factory.createConnection() は抽象化ではなく具体的​​な実装を返すため、TestConnection クラスは具体的な実装に依存するためです。

代わりにこれを行うことでこれを修正できますか?

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

ファクトリを取得するために "new" を呼び出すのではなく、TestConnection にファクトリを注入する (つまり、インターフェイスによって ConnectionFactory をパラメータとして受け取る) のが理想的です。そうすれば、TestConnection は Factory または Connection の具体的な実装に依存しません。

ファクトリが Connection の具体的な実装を返すことは問題ありません。実際、接続を実際に使用したい場合は必要です。ファクトリはそれを Connection として (つまり、インターフェイスとして) 返すため、特定の具体的な実装に依存していません。誰か、どこかが Connection の実装を実際にインスタンス化する必要があります。それが Factory の仕事です。

たとえば、OracleConnection に他の接続にはない特定のメソッドがあり、呼び出し元のクラスがそれらに依存していた場合、違反になります。ここではそうではありません。

于 2012-04-22T03:41:25.723 に答える
1

あなたの一般的なアーキテクチャはデータベース接続を実装するための最良の方法ではないと主張することができますが、質問はデータベースの実装ではなく依存関係の逆転に関するものであると理解しているため、スキップします。完全な依存関係の反転を実現するには:

  • Connection具体的なクラスではなく、インターフェイスにする必要があります。
  • ConnectionFactorycreateConnection()を返すメソッドを定義する、具体的なクラスではなく、インターフェイスにする必要がありますConnection。コンストラクターで引数を必要としないでください。
  • データベースごとに、実装ConnectionFactoryするオブジェクトを実装して返す異なる具象クラスがありますConnection

TestConnection はサービス プロバイダーから必要なもののみを指定し、具体的な実装には結び付けられていないため、上記は依存性逆転の原則をより適切に満たしています。TestConnection 用に定義されたインターフェースによって指定された要件を満たし、インターフェースが TestConnection に本当に必要なもの以上を指定しない限り、具体的な実装を作成して使用することができます。

特に、別のパッケージの別のベンダーが新しい実装を作成し、FactoryそれConnectionをコードにプラグインすることができ (上記のアーキテクチャに従っている場合)、TestConnectionクラスを変更する必要はありません。

これは、サービス クライアントへの具体的なサービスのランタイム関連付けの多くのパラダイムをサポートします。たとえば、典型的な起動時依存性注入シナリオでは、具体的な実装をに注入するConnectionFactoryと、次の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 (またはより一般的には ) を取得します。これらは質問の範囲を超えており、これを行う理由の例と、原則を満たしているかどうかを確認する1つの方法として提供されています。 TestConnection外部ソース (データベース ドライバなど) からのものについては、クラスではなくインターフェイスのみを参照する必要があります。

于 2012-04-22T06:37:27.843 に答える
0

依存性逆転原則のプリンシパルは

A - 高レベル モジュールは低レベル モジュールに依存すべきではありません。どちらも抽象化に依存する必要があります。

あなたの場合、接続が抽象化されています。これは良いことです。私の意見では、ファクトリーパターンの使用も問題ありません。

B - 抽象化は詳細に依存すべきではありません。詳細は抽象化に依存する必要があります。

Connection は下位の実装に依存せず、継承されたクラスは Connection のメソッド/変数を使用する場合があります (例がより複雑な場合は、おそらくそうするでしょう)。

余談ですが、後で Connection にさらに機能を追加する場合は、 Connection を抽象クラスにすることに傾倒し、作成されたデフォルトのコンストラクターを気にしません。

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

または単にインターフェースにする

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

createConnectionあなたが提案する2 つの実装は同等です。接続を返す方向と変数に接続を隠してそれを返す間に機能的な違いはありません。

依存関係の逆転に違反しているかどうかについては、使用目的によっては、ファクトリはある程度問題ないと思います。Connection必要なのは、接続を取得するために直接呼び出すファクトリを持つのではなく、クラスがパラメータとして を受け取ることです。

于 2012-04-22T03:27:29.853 に答える