0

リファクタリングが必要なプロジェクトがあります。これは、マイナーコンポーネントのライフサイクルを制御するメジャーコンポーネントを備えた約40のGUIコンポーネントを備えたJavaデスクトップSWT/JFaceアプリケーションです。結合度の低い優れたモジュラー設計が必要ですが、コンストラクターが非常に長い場合を除いて、グローバル状態を回避する方法を見つけることができません。

たとえば、ソフトウェアの国際化への現在のアプローチは次のようなものです。

public class Main {
    public static void main(String[] args) {
        MyMessages.loadMessages();
    }
}
public class MyMessages {
    private static ResourceBundle messages;
    public static void loadMessages() {
        messagesBundle = ResourceBundle.getBundle("messages", "en");
    }

    public static void getMessage(String m) {
        return messagesBundle.getString(m);
    }
}

public class SomeComponent extends Component() {
    public void init() {
        String textboxLabel = MyMessages.getMessage("someMessage");
    }
}

コード内の他の場所ではシングルトン(データモデル用)を使用しているため、コードベースが大きくなるにつれて依存関係を分析するのは困難です。

別のアプローチは、MyMessagesステートフルにし、そのインスタンスをGUIコンポーネントの階層全体に渡すことです。私には、これは厄介でエラーが発生しやすく、認識されている利点と比較して面倒な価値がないように見えます。

次のような方法でこれを設計するには、他にどのような方法がありますか。

  • 本質的にグローバル変数であるものに依存しません。
  • 依存関係を明示的にします。
  • 長いコンストラクターでコードを乱雑にしません。

依存性注入フレームワークを検討する必要がありますか、それとも小さなデスクトップアプリケーションにとってやり過ぎではないように思われる別のアプローチがありますか?

4

3 に答える 3

2

依存性注入フレームワークを検討する必要がありますか?それとも、小さなデスクトップ アプリケーションではやり過ぎとは思えない別のアプローチがありますか?

小さなデスクトップ アプリの場合は、依存性注入設計パターンを使用することをお勧めしますが、産業用強度の DI フレームワークの使用は控えます。

あなたのコードでは、メッセージ ヘルパー クラスは問題ありませんが、SomeComponent クラスは明らかに DI フレンドリーではありません。

public class SomeComponent extends Component() {
    public void init() {
        String textboxLabel = MyMessages.getMessage("someMessage");
    }
}

SomeComponent が MyMessages に関連付けられるようになりました。

代わりに次のようなものを使用します。

public class SomeComponent extends Component() {

    public void setTextBoxLabel(String value) {
        // implementation depends on requirements
    }

    public void init() {
        // do something with all the properties that were set
    }
}

基本的には、コンポーネントにセッターを追加するだけです。これはDIの最初の部分です。すべてのクラスが疎結合され、各クラスは、誰かがすべてのプロパティを設定することを信頼しているようにします。コンポーネントに必要なものはすべて注入されるため、グローバル状態は必要ありません。

もちろん、これを行うと、これらすべてのオブジェクトを作成し、それらのすべてのプロパティを設定する必要があり、すべてがアプリケーションに結び付けられているため、スタートアップ コードは悪夢になります。その時点で、スタートアップ コードのリファクタリングを開始し、オブジェクトの作成を処理するビルダーやファクトリを作成します。

コンポーネントの 1 つがプロパティ ファイルによって初期化されるとします。プロパティ ファイルを読み取り、コンポーネントをインスタンス化し、コンポーネント プロパティを設定してインスタンスを返すビルダーを作成します。コンポーネントはプロパティ ファイルについて何も認識しません。起動時に設定されることがわかっているゲッターとセッターがいくつかあるだけです。

後で、ファイル形式として XML を使用することを決定しますが、別のアプリでは、最初のアプリでは引き続きプロパティ ファイルを使用します。問題ありません。XML ファイルを読み取ってコンポーネントをビルドする新しい XML ビルダーを作成します。ただし、実際の G​​UI コンポーネントは、初期化方法から完全に切り離されているため、変更されません。

重要なのは、作成設計パターンを確認し、どのパターン (ビルダー、ファクトリなど) がグローバル状態を回避しながらコンポーネントを確実に作成するのに役立つかを理解することです。

于 2012-11-13T02:44:30.873 に答える
1

グローバル状態を使用します。特にビューを再利用している場合。私見では、アプリ全体で頻繁に使用されるさまざまなコンポーネントを何らかの形で検索することに何の問題もありません。

DI フレームワークを使用する場合は、ある種のグローバル状態を暗黙的に使用する可能性があることに注意してください (これは DI フレームワークに依存する実装です)。たとえば、Spring を考えると、ApplicationContext はグローバル オブジェクトであり、さまざまな Bean の構成に応じて、それ自体がさまざまなコンポーネントを保持したり、コンポーネントのライフサイクルを管理したりします。

グローバル コンポーネントを持つことは、必ずしも悪いことではありません。トレードオフが巨大なコンストラクター署名と参照の受け渡しである場合、私はいつでもグローバル参照を取得します (まあ、それらをある種のApplicationオブジェクトに入れます)。

于 2012-11-13T01:02:42.490 に答える
0

JavaロガーAPIを使用するのはどうですか...さらにStreamHandlerクラスを拡張して、出力ストリームをコンポーネントに設定できます。メッセージおよび関連するクラスとメソッドを追跡することもできます。

于 2012-11-13T01:05:15.463 に答える