web-dev-qa-db-ja.com

複数のクラスが1つのオブジェクト参照に依存している

Button、Textboxなどのクラスがいくつかありますが、これらのオブジェクトのインスタンス化時には、すべて1つのオブジェクト参照が必要です。ボタンは画面上の物理的なボタンを表しますが、UI要素ではありません。代わりに、Seleniumを使用して、物理的なボタンを操作する必要があります。

    public class Button : Element, IButton
    {
        public Button(IService someService) : base()
        {

        }
    }

どこか後で

var b = new Button(someService)
var b = new Button(someService)
var b = new Button(someService)
var b = new Button(someService)

ここで問題となるのは、アプリケーション全体でこのボタンオブジェクトを数回インスタンス化する必要があるため、常にコンストラクタ内で参照を渡す必要があることです。これは私にはあまり良くないコードのように見えます。だから、誰かがこれをよりよくする方法についての手がかりを持っているなら、私はとても感謝しています!

前もって感謝します

3
John

非常に単純な改善から始めることをお勧めします。コード全体で再利用できるメソッドにボタンのインスタンス化をリファクタリングするだけです。

_   Button CreateButton()
   {
       return new Button(someService);
   }
_

もちろん、必要な場所に応じて、このメソッドをどこに配置するかを決定します。 1つのクラス内でのみ必要な場合は、メソッドをそこに簡単に配置できます。

アプリケーションのいくつかの異なるクラスでメソッドが必要な場合は、メソッドをファクトリクラスに配置できます。ここで、someServiceは、ファクトリのコンストラクタを介して渡されるそのファクトリのメンバー変数です。

_   class ButtonFactory
   {
       ButtonFactory(someService)
       {
            this.someService = someService;
       }

       Button CreateButton()
       {
           return new Button(someService);
       }
  }
_

ここで、適切なサービスを使用してアプリケーションのファクトリーonceを初期化し、必要なアプリケーション全体で再利用する必要があります。

これを使用するコードは次のようになります

_  Button button = buttonFactory.CreateButton();
_

オリジナルより短くはありません。しかし、利点は、アプリケーションの1つの場所で正しいサービスonceを選択し、別の場所にボタンを作成できることです。後で別のサービスを選択する場合は、コードで変更する1つの場所(工場の構造)のみを指定します。

テキストボックスに同じサービスが必要な場合は、同様のメソッドCreateTextbox()を追加してファクトリクラスを拡張できます(もちろん、ファクトリをElementFactoryControlFactoryなどの名前に変更する必要があります)。

1
Doc Brown

改善のための追加のアイデアとして、一般的なButtonクラスを特別なサービスのようなものから直接依存させないことを検討するかもしれません。

ボタンはUI要素を表します。多分それを別のコンテキストで再利用したいでしょう。ビジネスロジックサービスなど、非常にアプリケーション固有の何かに関連付けることで、アプリケーション間での再利用を防ぐことができます。

オブザーバーパターン

ボタンに何かをさせ、ポリモーフィズムを使用して、ボタンが操作されたときに何が起こるかを切り離します。

(Java構文を使用しますが、要点はわかります)

interface Runnable {
    void run();
}

class Button {
    private List<Runnable> clickListeners = new List();

    public void addClickListener(Runnable listener) {
        this.clickListeners.add(listener);
    }

    private void onMouseLeftClicked() {
        if (this.disabled) return;

        this.clickListeners.forEach(listener -> listener.run());
    }
}

class MyApplicationWindow extends Window {
    public MyApplicationWindow(Runnable onFormSubmit) {
         // construct all of the UI layout and stuff
         Button submitButton = new Button();

         // here is where you connect UI and business logic:
         submitButton.addClickListener(onFormSubmit);
    }
}

// in your application bootstrap:
Service myService = ... ;

Runnable submitHandler = () -> myService.doStuff(getDataFromUI());

// when constructing your UI, pass a reference to the submit handler.
// note: conceptually, it is entirely up to the UI to decide when to trigger the
// submit; thats perfect because interpreting user intent is part of the UIs job
// whereas performing the action is part of your service layer
Window myApplicationWindow = new MyAplicationWindow(submitHandler)

繰り返しについて:すべてのボタンに共通のプロパティ/構成では、Doc Brownが his answer で書いたものと同様に、ファクトリーパターンを使用できます。

1
marstato