42

まず第一に、私は Java アプリケーションを構築する方法を知っています。しかし、私はいつもクラスをどこに置くかについて困惑しています。厳密にドメイン指向の方法でパッケージを編成することを支持する人もいれば、階層ごとに分ける人もいます。

私自身、ずっと悩んできた

  • ネーミング、
  • 配置する

そう、

  1. ドメイン固有の定数をどこに置きますか (また、そのようなクラスに最適な名前は何ですか)?
  2. インフラストラクチャとドメイン固有の両方のクラスをどこに配置しますか (たとえば、ファイルをデータベースまたはデータベースに格納する FileStorageStrategy クラスがあります)。
  3. 例外をどこに置くか?
  4. 参照できる基準はありますか?
4

10 に答える 10

28

I've really come to like Maven's Standard Directory Layout.

One of the key ideas for me is to have two source roots - one for production code and one for test code like so:

MyProject/src/main/java/com/acme/Widget.java
MyProject/src/test/java/com/acme/WidgetTest.java

(here, both src/main/java and src/test/java are source roots).

Advantages:

  • Your tests have package (or "default") level access to your classes under test.
  • You can easily package only your production sources into a JAR by dropping src/test/java as a source root.

One rule of thumb about class placement and packages:

Generally speaking, well structured projects will be free of circular dependencies. Learn when they are bad (and when they are not), and consider a tool like JDepend or SonarJ that will help you eliminate them.

于 2008-08-16T19:06:10.267 に答える
12

私は整理されたソースの大ファンなので、常に次のディレクトリ構造を作成します。

/src - for your packages & classes
/test - for unit tests
/docs - for documentation, generated and manually edited
/lib - 3rd party libraries
/etc - unrelated stuff
/bin (or /classes) - compiled classes, output of your compile
/dist - for distribution packages, hopefully auto generated by a build system

/src では、デフォルトの Java パターンを使用しています。ドメインで始まるパッケージ名 (org.yourdomain.yourprojectname) と、クラスで作成している OOP の側面を反映するクラス名 (他のコメンターを参照)。utilmodelvieweventsなどの一般的なパッケージ名も役立ちます。

私は、ドメイン クラスの同じパッケージに含まれるSessionConstantsServiceConstantsのように、特定のトピックの定数を独自のクラスに入れる傾向があります。

于 2008-08-12T08:00:18.707 に答える
11

私が働いている場所では、Maven 2 を使用しており、私たちのプロジェクトには非常に優れたアーキタイプがあります。目標は、問題を適切に分離することでした。そのため、複数のモジュール (アプリケーションの「レイヤー」ごとに 1 つ) を使用してプロジェクト構造を定義しました。 - 共通: 他のレイヤーで使用される共通コード (i18n など) - エンティティ: ドメインエンティティ - リポジトリ: このモジュールには daos インターフェースと実装が含まれます - services-intf: サービスのインターフェース (UserService など) - services-impl: サービスの実装 (UserServiceImpl など) - web: に関するすべてWeb コンテンツ (例: css、jsps、jsf ページなど) - ws: Web サービス

各モジュールには独自の依存関係があり (たとえば、リポジトリは jpa を持つことができます)、一部はプロジェクト全体です (したがって、それらは共通モジュールに属します)。異なるプロジェクト モジュール間の依存関係により、物事が明確に分離されます (たとえば、Web レイヤーはサービス レイヤーに依存しますが、リポジトリ レイヤーについては認識しません)。

各モジュールには独自の基本パッケージがあります。たとえば、アプリケーション パッケージが「com.foo.bar」の場合、次のようになります。

com.foo.bar.common
com.foo.bar.entities
com.foo.bar.repositories
com.foo.bar.services
com.foo.bar.services.impl
...

各モジュールは、標準の Maven プロジェクト構造を尊重します。

   src\
   ..main\java
     ...\resources
   ..test\java
     ...\resources

特定のレイヤーの単体テストは、\src\test の下にある場所を簡単に見つけることができます... ドメイン固有のものはすべてエンティティ モジュールに配置されます。実装が何であるかを正確に知る必要がないため、FileStorageStrategy のようなものを repositories モジュールに入れる必要があります。サービス層では、リポジトリ インターフェースしか知りません。特定の実装が何であるかは気にしません (関心の分離)。

このアプローチには複数の利点があります。

  • 懸念事項の明確な分離
  • 各モジュールは jar (または web モジュールの場合は war) としてパッケージ化できるため、コードの再利用が容易になります (たとえば、モジュールを maven リポジトリにインストールして、別のプロジェクトで再利用できます)。
  • プロジェクトの各部分の最大の独立性

これがすべての質問に答えるわけではないことは承知していますが、これにより正しい道を歩むことができ、他の人にとって役立つことが証明される可能性があると思います.

于 2008-09-15T20:43:40.430 に答える
4

クラス名は、常に説明的でわかりやすいものにする必要があります。クラスの責任ドメインが複数ある場合は、おそらくリファクタリングする必要があります。

あなたのパッケージも同様です。責任範囲ごとにグループ化する必要があります。すべてのドメインには独自の例外があります。

通常、圧倒されて肥大化するまで汗をかかないでください. それからコードを書くのではなく、クラスをリファクタリングし、定期的にコンパイルして、すべてが機能することを確認します。次に、前と同じように続行します。

于 2008-08-11T08:00:58.830 に答える
3

パッケージを使用して、関連する機能をグループ化します。

通常、パッケージ ツリーの一番上はドメイン名を反転させたもの ( com.domain.subdomain) であり、一意性を保証します。その後、通常、アプリケーションのパッケージが表示されます。次に、それを関連する領域で細分化しますFileStorageStrategy。たとえば、 に入るcom.domain.subdomain.myapp.storageことができ、 および に特定の実装/サブクラス/その他が存在する可能性がありcom.domain.subdomain.myapp.storage.fileますcom.domain.subdomain.myapp.storage.database。これらの名前はかなり長くなる可能性がimportありますが、すべてファイルの先頭に保持され、IDE はそれを管理するのにも役立ちます。

FileStorageException例外は通常、それらをスローするクラスと同じパッケージに入れられるため、たとえば、FileStorageStrategy. 同様に、定数を定義するインターフェイスは同じパッケージに含まれます。

そのような標準は実際にはありません。常識を使用してください。すべてが面倒な場合は、リファクタリングしてください。

于 2008-08-11T08:24:02.950 に答える
3

簡単な答え: システム アーキテクチャをモジュールの観点から描画し、横に並べて描画し、各モジュールを垂直にスライスしてレイヤー (ビュー、モデル、永続化など) に分割します。次に、com.mycompany.myapp.somemodule.somelayerのような構造を使用します(例: com.mycompany.myapp.client.viewまたはcom.mycompany.myapp.server.model )

アプリケーションモジュールに最上位のパッケージを使用することは、昔ながらのコンピューター サイエンスの意味でのモジュラー プログラミングであることは明らかです。しかし、私が取り組んできたほとんどのプロジェクトでは、それを忘れてしまい、トップレベル構造のないパッケージがごちゃごちゃになってしまいます。このアンチパターンは通常、「リスナー」や「アクション」のようなもののパッケージとして表示されます。これらのクラスは、たまたま同じインターフェイスを実装しているという理由だけで、関連のないクラスをグループ化します。

モジュール内または小さなアプリケーションでは、アプリケーション レイヤーにパッケージを使用します。アーキテクチャに応じて、パッケージには次のようなものが含まれている可能性があります。

  • com.mycompany.myapp.view
  • com.mycompany.myapp.model
  • com.mycompany.myapp.services
  • com.mycompany.myapp.rules
  • com.mycompany.myapp.persistence (またはデータ アクセス レイヤーの場合は「dao」)
  • com.mycompany.myapp.util (これが「その他」であるかのように使用されることに注意してください)

これらの各レイヤー内で、クラスが多数ある場合は、クラスをタイプ別にグループ化するのが自然です。ここでの一般的なアンチパターンは、各パッケージに少数のクラスしか存在しないように、必要以上に多くのパッケージとサブパッケージのレベルを導入することです。

于 2008-09-04T13:40:54.440 に答える
3

単体テストで非常に役立つと思ったのは、myApp/src/ ディレクトリと myApp/test_src/ ディレクトリを用意することです。このようにして、テストするクラスと同じパッケージに単体テストを配置できますが、本番環境のインストールを準備するときにテスト ケースを簡単に除外できます。

于 2008-09-03T12:21:37.760 に答える
2

シンプルに保ち、考えすぎないようにしましょう。抽象化しすぎないでください。きちんと保つだけで、成長するにつれて、リファクタリングは簡単です。IDEの最も優れた機能の1つはリファクタリングです。コード編成のようなメタの問題ではなく、リファクタリングを利用して、アプリに関連する問題を解決するための頭脳の力を節約してみませんか。

于 2008-08-12T03:36:32.123 に答える
0

私が過去に行ったことの1つは、クラスを拡張する場合は、それらの規則に従うようにすることです。たとえば、Spring Frameworkを使用する場合、MVCコントローラークラスはcom.mydomain.myapp.web.servlet.mvcというパッケージに含まれます。拡張しない場合は、最も単純なものを使用します。ドメインオブジェクトのcom.mydomain.domain(ただし、ドメインオブジェクトが大量にある場合、このパッケージは少し扱いに​​くくなる可能性があります)。ドメイン固有の定数については、実際に最も関連性の高いクラスのパブリック定数として配置します。たとえば、「Member」クラスがあり、メンバー名の最大長が一定の場合、それをMemberクラスに入れます。いくつかのショップは別個の定数クラスを作成していますが、無関係な数値と文字列を1つのクラスにまとめることの価値はわかりません。私' 他のいくつかのショップがSEPARATEConstantsクラスを作成することでこの問題を解決しようとしているのを見てきましたが、それは時間の無駄のように思え、結果はあまりにも混乱しています。この設定を使用すると、複数の開発者がいる大規模なプロジェクトで、定数がいたるところに複製されます。

于 2008-08-11T23:25:44.503 に答える
0

クラスを相互に関連するパッケージに分割するのが好きです。

例: データベース関連の呼び出しのモデル

あなたが見ているものを扱うクラスを見る

コントロールコア機能クラス

Utilその他 使用されるクラス(通常は静的関数)

于 2008-08-12T01:28:23.287 に答える