6

序章

インターフェイス、抽象クラス、およびジェネリックを使用して、Java でかなり複雑な構造を作成しようとしています。ジェネリックの経験がなく、優れた OOP 設計を作成する平均的な経験しかないため、これはかなりの課題になり始めています。

私がやろうとしていることは、実際にはできないかもしれないが、それに十分近づくことができると感じています。できるだけ簡潔に説明しようと思います。この構造は、データベースにアクセスするための DAO およびサービス層を表すことをすぐに説明します。この質問をより抽象的にすると、より難しくなるだけです。

私のDAO層はそのままで大丈夫です。ジェネリック DAO インターフェイスがあり、エンティティごとに、ジェネリックを拡張してジェネリック型を埋める DAO インターフェイスがあります。次に、各 DAO 実装によって拡張される抽象クラスがあり、対応するインターフェイスを実装します。おそらく混乱を招くので、例として製品のDAOを示す図を次に示します。

Product エンティティの DAO 実装を示す図

サービスクラスについても、同様の構造を念頭に置いていました。とにかく、サービス クラスのほとんどのメソッドは DAO メソッドにマップされます。上の図のすべての「DAO」を「サービス」に置き換えると、私のサービス層の基礎が得られます。しかし、私が持っている次のアイデアに基づいて、やりたいことが1つあります。

エンティティのすべてのサービス クラスは、少なくとも 1 つの DAO オブジェクト、つまり、それが設計されたエンティティの DAO にアクセスします。

どちらが...

質問/問題

各サービス クラスがそれぞれのエンティティの DAO オブジェクトのインスタンス変数を 1 つ持つように適切な OO 設計を作成できれば、サービス レイヤーは完璧だと思います。私のデザインが見た目ほど良くない場合に備えて、これに関するアドバイスを歓迎します。

私は次のように実装しました:

クラス AbstractService

public abstract class AbstractService<EntityDAO> {

    EntityDAO entityDAO;

    public AbstractService() {
        entityDAO = makeEntityDAO(); //compiler/IDE warning: overridable method call in constructor
    }

    abstract EntityDAO makeEntityDAO();
}

クラス ProductServiceImpl

public class ProductServiceImpl extends AbstractService<ProductDAOImpl> {

    public ProductServiceImpl() {
        super();
    }

    @Override
    ProductDAOImpl makeEntityDAO() {
        return new ProductDAOImpl();
    }
}

この設計の問題は、私が気に入らないコンパイラの警告です: コンストラクターにオーバーライド可能なメソッド呼び出しがあります(コメントを参照)。現在はオーバーライドできるように設計されており、実際、各サービス クラスが対応する DAO への参照を確実に持つように強制しています。これは私ができる最善のことですか?

私はあなたが必要とするかもしれないすべてを、この質問に必要なものだけを含めるために最善を尽くしました. 私が今言わなければならないのは、コメントは大歓迎であり、さらに広範な回答です。時間を割いて読んでくれてありがとう.

StackOverflow に関するその他のリソース

サービス層と DAO 層について

DAO およびサービス層 (JPA/Hibernate + Spring)

4

1 に答える 1

3

最初に少し注意してください: 通常、たとえばプレゼンテーション / サービス / DAO などのレイヤーで編成されたアプリケーションでは、次のルールがあります。

  • 各レイヤーは、すぐ下のレイヤーのみを認識します。
  • 実装クラスではなく、インターフェイスによってのみ認識されます。

これにより、テストが容易になり、コードのカプセル化が改善され、さまざまなレイヤーの明確な定義が提供されます (パブリック API として簡単に識別されるインターフェイスを介して)。

とはいえ、最も柔軟な方法でそのような状況を処理するための非常に一般的な方法があります:依存性注入です。そして、Springは、依存性注入 (および他の多くのもの) の業界標準の実装です。

(要するに) アイデアは、サービスが IEntityDAO を必要とすることを認識し、実際にサービスを使用する前に誰かがそれに注入し、インターフェイスの実装を行うことです。その誰かが IOC コンテナー ( Inversion of Controlコンテナー) と呼ばれます。それはSpringである可能性があり、それが行うことは通常、アプリケーション構成ファイルによって記述され、アプリケーションの起動時に行われます。

重要な注意:コンセプトは素晴らしく強力ですが、非常に単純で馬鹿げています。Inversion of Control アーキテクチャ パターンは、アプリケーション パーツを「組み立てる」大規模な静的メソッドで構成される非常に単純な実装を使用して、フレームワークなしで使用することもできます。しかし、産業のコンテキストでは、データベース接続、Web サービス スタブ クライアント、JMS キューなどの他のものを注入できるフレームワークを使用することをお勧めします...

利点:

  • クラスが依存するのはインターフェイスだけなので、簡単にモックとテストを行うことができます
  • アプリケーションの構造全体を記述する XML ファイルの小さなセットの 1 つのファイルがあり、これはアプリケーションが大きくなったときに非常に便利です。
  • これは非常に広く採用されている標準であり、多くの Java 開発者によく知られています。

サンプル Java コード:

public abstract class AbstractService<IEntityDAO> {

    private IEntityDAO entityDAO; // you don't know the concrete implementation, maybe it's a mock for testing purpose

    public AbstractService() {
    }

    protected EntityDAO getEntityDAO() { // only subclasses need this method
    }

    public void setEntityDAO(IEntityDAO dao) { // IOC container will call this method
        this.entityDAO = dao;
    }
}

そして春の設定ファイルには、次のようなものがあります:

<bean id="ProductDAO" class="com.company.dao.ProductDAO" />

[...]

<bean id="ProductService" class="com.company.service.ProductService">
    <property name="entityDAO" ref="ProductDAO"/>
</bean>
于 2012-11-05T22:39:36.497 に答える