目次

【デザインパターン】JavaのBridgeパターンについて

今回はbridgeパターンについて解説します。

September 20, 20237 min read
Java
デザインパターン

Bridge

Bridgeパターンは機能の拡張実装の拡張を分けるために存在します。 分けるためには機能の階層と実装の階層を作り、それらをBridge(橋)で渡す必要があります。

機能のクラス階層

あるクラスSomethingがあるとします。 このクラスに新しい機能を追加しようとしたらSomethingのサブクラスを作ります。

java
public class Something {
	public void doSomething() { ... }
}

public class SomethingGood extends Something {
	public void doSomethingAnother() { ... }
}

現在の階層は以下です。

Something
└ SomethingGood

さらに機能を追加したいと思いました。

java
public class SomethingBetter extends Something {
	public void doSomethingElse() { ... }
}

現在の階層は以下です。

Something
└ SomethingGood
	└ SomethingBetter

このように機能を継ぎ足していく場所を**機能のクラス階層**と言います。

実装のクラス階層

Templateメソッドを思い出してください。 スーパークラスは一連のメソッド群を抽象メソッドとして宣言しサブクラスでそれらを実装します。 ここにもクラス階層が存在します。 スーパークラスとしてAbstractClassを作り、その具体的なメソッドはConcreteClassで実装します。

java
public abstract class AbstractClass {
	public abstract void doSomething();
}

public class ConcreteClass {
	public void doSomething() {
		System.out.println("do something");
	}
}

この時の階層は以下のようになります。

AbstractClass
└ ConcreteClass

これを**実装のクラス階層**と呼びます。

まとめると

  • 機能のクラス階層では新しい機能の追加
  • 実装のクラス階層では新しい処理の中身の追加

を行っています。 絵を描く時にクレヨンで描く筆で描く(実装のクラス階層)の追加と似顔絵を描く風景画を描く(機能のクラス階層)の追加を別々に行うイメージです。

今回はデバイスごとの通知機能を実装します。

実装(機能のクラス階層)

Notification

**機能のクラス階層**の最上位に当たるクラスです。 implフィールドはNotificationクラスの実装を表すインスタンスです。 ここではimplで実装されている処理を用いて1人に対して知らせる機能Notifyメソッドを実装しています。

java
public class Notification {
    private NotificationImpl impl;

    public Notification(NotificationImpl impl) {
        this.impl = impl;
    }

    protected void setMessage(String title, String message) {
        impl.setMessage(title, message);
    }

    protected void sendMessage(String to) {
        impl.sendMessage(to);
    }

    public final void Notify(String title, String message, String to) {
        setMessage(title, message);
        sendMessage(to);
    }
}

MultiNotification

ここでは機能の追加を行いたいので、複数人に対して通知をするmultiNotifyを実装します。

java
public class MultiNotification extends Notification {
    public MultiNotification(NotificationImpl impl) {
        super(impl);
    }

    public void MultiNotify(String title, String message, String[] to) {
        setMessage(title, message);
        for (String s : to) {
            sendMessage(s);
        }
    }
}

実装(実装のクラス階層)

NotificatioinImpl

**実装のクラス階層**の最上位に位置します。 このクラスが具体的な実装をスーパークラスのNotificationへ橋渡ししています。 setMessageはテンプレートメソッドとして具体的な処理を記述しています。(今回はメッセージの形式がデバイスごとで変わらないため)

java
public abstract class NotificationImpl {
    protected StringBuilder message = new StringBuilder();
    protected void setMessage(String title, String message){
        this.message.append("Title: 【" + title + "】\n");
        this.message.append("----------------------------\n ");
        this.message.append(message + "\n");
        this.message.append("----------------------------\n ");
    }
    protected abstract void sendMessage(String to);
}

ここが肝で、NotificationImplが存在しないと実装機能を分離することができなくなってしまいます。 時間がある方は試しに直接スーパークラスをオーバーライドする形でメソッドを記述してみてください。 機能がNotificationクラスに集中してしまいます。 NotificationImplを噛ませて具体的な実装機能から隠すことでそれぞれ別々にスケールさせることができるようになり、いわゆる神クラスを防ぐことにもつながります。

iPhoneNotificationImpl

iPhoneに対してメッセージを送る具体的なメソッドを記述します。

java
public class iPhoneNotificationImpl extends NotificationImpl {
    @Override
    protected void sendMessage(String to) {
        System.out.println("Send message to \"" + to + "@icloud.com\"");
        System.out.println(this.message);
    }
}

AndroidNotificationImpl

Androidに対してメッセージを送る具体的なメソッドを記述します。

java
public class AndroidNotificationImpl extends NotificationImpl {
    @Override
    protected void sendMessage(String to) {
        System.out.println("Send message to \"" + to + "@gmail.com\"");
        System.out.println(this.message);
    }
}

実行

Mainクラス

機能と実装を分けたことにより、それぞれを組み合わせて柔軟な処理を少ない依存関係で実現できました。

java
public class Main {
    public static void main(String[] args) {
        Notification notification = new Notification(new iPhoneNotificationImpl());
        notification.Notify("Hello", "This is a message for iPhone", "John");
        notification = new Notification(new AndroidNotificationImpl());
        notification.Notify("Hello", "This is a message for Android", "Mary");
        MultiNotification multiNotification = new MultiNotification(new iPhoneNotificationImpl());
        multiNotification.MultiNotify("Hello", "This is a message for iPhone", new String[] {"Kurimatsu", "Steve"});
        multiNotification = new MultiNotification(new AndroidNotificationImpl());
        multiNotification.MultiNotify("Hello", "This is a message for Android", new String[] {"Tom", "Jerry"});
    }
}

実行結果

Send message to "John@icloud.com"
Title: 【Hello】
----------------------------
 This is a message for iPhone
----------------------------
 
Send message to "Mary@gmail.com"
Title: 【Hello】
----------------------------
 This is a message for Android
----------------------------
 
Send message to "Kurimatsu@icloud.com"
Title: 【Hello】
----------------------------
 This is a message for iPhone
----------------------------
 
Send message to "Steve@icloud.com"
Title: 【Hello】
----------------------------
 This is a message for iPhone
----------------------------
 
Send message to "Tom@gmail.com"
Title: 【Hello】
----------------------------
 This is a message for Android
----------------------------
 
Send message to "Jerry@gmail.com"
Title: 【Hello】
----------------------------
 This is a message for Android
----------------------------

See you later 👋


0

Conversation