web-dev-qa-db-ja.com

機能別パッケージはアプローチが良いですか?

最近、このjavalobbyの投稿に遭遇しました http://Java.dzone.com/articles/how-changing-Java-package on packages Java code by features。

アイデアは好きですが、このアプローチについてはいくつか質問があります。質問をしましたが、満足のいく返事がありませんでした。 StackOverflowの誰かが私の質問を明確にしてくれることを願っています。

機能ごとのパッケージのアイデアが気に入っています。これにより、コーディング中にパッケージ間を移動する時間を大幅に削減でき、関連するすべてのものが1つの場所(パッケージ)に配置されます。しかし、異なるパッケージのサービス間の相互作用についてはどうでしょうか?

ブログアプリを作成していて、ユーザー関連のすべての操作(コントローラー/サービス/リポジトリ)を_com.mycompany.myblog.users_パッケージに入れているとします。そして、_com.mycompany.myblog.posts_パッケージのすべてのブログ投稿関連操作(コントローラー/サービス/リポジトリ)。

ここで、ユーザープロファイルと、彼が投稿したすべての投稿を表示します。 myblog.posts.PostsService.getPostsByUser(userId)からmyblog.users.UserController.showUserProfile()を呼び出す必要がありますか?

パッケージ間の結合はどうですか?

また、機能ごとにパッケージについて読んだときはどこでも、それは良い習慣だと誰もが言っています。では、なぜ多くの本の著者やフレームワークでさえも、レイヤーごとにグループ化することを勧めているのでしょうか。知りたいだけです:-)

51

ボブおじさんの Package Design Principles を見てください。彼はこれらの原則の背後にある理由と動機について説明します。

一緒に再利用されるクラスは、一緒にパッケージ化して、パッケージを利用可能な完全な製品の一種として扱うことができるようにする必要があります。また、一緒に再利用されるものは、再利用されないものから分離する必要があります。たとえば、ロギングユーティリティクラスは、必ずしもファイルioクラスと一緒に使用されるわけではありません。したがって、すべてのログを個別にパッケージ化してください。ただし、ロギングクラスは互いに関連している可能性があります。したがって、たとえば、commonsの名前を改善したい場合のために、ロギング用の完全な製品を作成します。ロギングパッケージを(再)使用可能なjarにパッケージ化し、IOユーティリティ用の別の完全な製品を作成します。 io.jar。 say Java nioと言うようにsay commons-ioライブラリを更新する場合、必ずしもロギングライブラリに変更を加える必要はないかもしれません。したがって、それらを分離する方が良いでしょう。

ここで、たとえば、splunkなどのツールによるログ分析のような、ロギングユーティリティクラスが構造化ロギングをサポートするようにしたいとします。ロギングユーティリティのクライアントによっては、新しいバージョンに更新する必要がある場合があります。他の人はそうしないかもしれません。そのため、新しいバージョンをリリースするときは、移行に必要で再利用されるすべてのクラスをパッケージ化します。したがって、ユーティリティクラスの一部のクライアントは、古いcommons-logging jarを安全に削除して、commons-logging-new jarに移動できます。他の一部のクライアントは古いjarでまだ問題ありません。ただし、古いパッケージ化されたjarに対していくつかのクラスを使用するように強制しただけで、クライアントはこれらのjar(新旧)の両方を持つ必要はありません。

循環依存は避けてください。 aはbに依存します。 bのc; c on d;しかし、dはaに依存します。レイヤーやモジュールなどを定義することは非常に困難であり、それらを相互に独立して変更することができないため、シナリオは明らかに抑止されます。

また、レイヤーまたはモジュールが変更された場合に、他のモジュールまたはレイヤーが必ずしも変更される必要がないように、クラスをパッケージ化することもできます。したがって、たとえば、古いMVCフレームワークから残りのAPIのアップグレードに移行する場合は、ビューとコントローラーのみを変更する必要があります。モデルにはありません。

25
Atul

パッケージ設計のカップリング以外にも、私はOOAD原則、特に次のようなパッケージ設計原則を検討することをお勧めします。

REPリリースの再利用の等価原理再利用のグラニュールは、リリースのグラニュールです。

CCP Common Closure Principle一緒に変化するクラスは一緒にパッケージ化されます。

CRP一般的な再利用の原則一緒に使用されるクラスは一緒にパッケージ化されます。

ADP非循環依存関係の原則パッケージの依存関係グラフに循環があってはなりません。

SDP安定した依存関係の原則安定性の方向に依存します。

SAP安定した抽象化の原則抽象度は安定性とともに増加します。

詳細については、次を参照してください book "アジャイルソフトウェア開発、原則、パターン、およびプラクティス"

14
Jigar Parekh

私は個人的には「機能別パッケージ」アプローチが好きですが、パッケージの境界をどこに描くかについてかなりの判断をする必要があります。それは多くの状況で確かに実現可能で賢明なアプローチです。

おそらく、パブリックインターフェイスを使用してパッケージとモジュール間のカップリングを実現する必要があります。これにより、カップリングがクリーンで管理しやすくなります。

適切に設計されたパブリックインターフェイスを使用する限り、「ブログ投稿」パッケージが「ユーザー」パッケージを呼び出すことは完全に問題ありません。

ただし、このアプローチを使用する場合は、1つの大きなアドバイスがあります。パッケージ間の依存関係、特に循環依存関係を回避するについては十分に注意してください。優れた設計は、依存関係ツリーのように見える必要があります。ユーティリティ関数のライブラリなどに依存する一連の共通サービスに応じて、機能のより高いレベルの領域が含まれます。ある程度、これは、バックエンドサービスを呼び出すエンドパッケージ。

12
mikera