web-dev-qa-db-ja.com

2つの方法の設計パターンには、他の方法の70%の引数があります

システムで通知部分のデザインを実行しようとしています。アプリ通知と電子メール通知の2つの部分があるので、1つのメソッドsendを持つインターフェイスNotificationSenderがある戦略パターンを使用しました。

NotificationSender{
    public void send(A,B,C);
}

それから私は2つの実装を持っています

InAppNotificationSender{
    public void send(A,B,C){}
}
EmailNotificationSender{
    public void send(A,B,C){}
}

後で、InAppNotificationSenderのパラメーターを増やす必要があったので、sendにもD、Eパラメーターが必要です。これにより、次のようなビルダーパターンを使用して、両方のメソッドに対して1つのパラメーターを実行することを考えた設計が変更される可能性があります。

NotificationSender{
        public void send(NotificationTemplateBuilder);
    }

このような場合に適したデザインは何でしょうか

6
YouYou

最も簡単な答えは、通知機能インターフェースが、それらのいずれかが必要とするすべてのパラメーター、つまりパラメーターのスーパーセットを受け入れる必要があるということです。実装がインターフェースの一部のパラメーターを無視しても問題ありません。

5つのパラメーターが少し扱いに​​くくなり始めていますが、このための型を作成するのはひどい考えではありません。問題は、5つすべてのパラメーターをまとめる必要があるか、3つだけをまとめる必要があるかを理解しようとする努力をしたいかどうかです。

正当な理由がない限り、わざわざ3つのパラメーターに制限しようとしないでください。設計が非常に複雑になります。最後の2つのパラメーター(D、E)を取得するのに特にコストがかかる場合は、実行する必要があるかもしれません。

その場合、ビルダーの代わりに ファサードパターン を使用することをお勧めします。パラメータオブジェクトは実際には値を保持しませんが、代わりにオンデマンドでそれらを取得します。つまり、getA()は、知っているソースからAパラメータをプルします。ノーティファイアはAを取得する方法を知る必要がないため、シンプルなままです。利点は、電子メール通知機能がgetD()またはgetE()を呼び出さず、そのためのコストがアプリ内通知機能によってのみ発生することです。ただし、DとEを取得するのにコストがかからない場合、これははるかに複雑で価値がありません。

1
JimmyJames

抽象化が不足しているようです:通知です。

Notificationと呼ばれる新しいクラスは、データのバッグに過ぎない可能性があり、EmailNotificationSenderに関連しないInAppNotificationSenderに関連する情報が含まれている可能性がありますが、これは問題ありません。

これにより、通知送信者に渡す一貫したパラメーターが提供され、送信者は適切と思われるものを自由に使用(または使用しない)できます。また、既存の実装に追加コストをかけずに、このNotificationクラスが保持できるものを拡張するという追加の利点も得られます。

10
Greg Burghardt

私は単純な解決策を好む。この場合、インターフェイスのSendメソッドからすべてのパラメーターを削除します。このインターフェイスを実装する各クラスに、必要なプロパティを持つコンストラクターを与え、それらをプライベートフィールドに保存して、Sendメソッドの実装で使用します。

0
Rik D

私はおそらく、大まかにビルダーパターンに基づいて、適切な動作を追加して、次の設計(パラメーターのユースケースがわからない)に行きます。

_public interface Notification {
    Notification withRecipient(...); // A
    Notification withSubject(...); // B
    Notification addParagraph(...); // C
    ...
    void send(); // That's what we want from a Notification      
}
_

複数のスタイル/意味論に基づくものを導入することができ、実際の実装では、それをどのように(またはどのように)処理するかを決定できます。このような:

_public interface NotificationFactory {
    Notification create();
}

public final class EmailNotificationFactory implements NotificationFactory {
    @Override
    public Notification create() {
        // This is just an example here
        Message message = new MimeMessage(session); // Using javax.mail
        return new Notification() {
            @Override
            public Notification withRecipient(String recipient) {
                message.setRecipients(...);
            }
            ...
            @Override
            public void send() {
                Transport.send(message); // Or whatever
            }
        }
    }
}
_

アプリ内通知は、適切なウィジェットまたは通知ダイアログを作成し、send()を画面に表示します。

0

私は@GregBurghardtの回答が好き(そして賛成)ですが、たぶんなら、もっと簡単な方法で回避できます。これは境界線の「迅速で汚い」ので、自分で使用するかどうかはわかりません-このAPIの重要性、変更の可能性などによって異なります(そして、このより「動的な言語」を使用するユーザーの快適さはどの程度かによって異なります。感じる。)

If

  1. A、B、およびCは常に必要です
  2. D、Eは「まれ」
  3. DとEは同じタイプです、たとえばURL

あなたの署名は

public void send(A a, B b, C c, URL... extras)

そして、dとeにアクセスしますエクストラの長さをチェックした後extras[0]extras[1]を介して。

0
user949300