顧客への連絡方法を柔軟に切り替えよう
顧客への通常の連絡や、注文受付メールなどの固定文言の連絡送る仕組みを作ります。
メールやSMSなど方法は柔軟に選べるような作りにしたいと考えています。
今回はBridgeパターンで作ってみましょう。
Bridgeパターンとは
機能と実装を橋渡しすることで、機能と実装を分離させるパターンです。
interface MessengerImpl
{
public function sendMessage(string $customerName, string $message): void;
public function sendOrderAcceptanceMessage(string $customerName): void;
}
class MailMessengerImpl implements MessengerImpl
{
public function sendMessage(string $customerName, string $message): void
{
echo $customerName . 'に「'.$message.'」というメールを送ります';
}
public function sendOrderAcceptanceMessage(string $customerName): void
{
$this->sendMessage($customerName, '注文を受け付けました');
}
}
class ChatMessengerImpl implements MessengerImpl
{
public function sendMessage(string $customerName, string $message): void
{
echo $customerName . 'に「'.$message.'」というチャットを送ります';
}
public function sendOrderAcceptanceMessage(string $customerName): void
{
$this->sendMessage($customerName, '注文を受け付けました');
}
}
class SmsMessengerImpl implements MessengerImpl
{
public function sendMessage(string $customerName, string $message): void
{
echo $customerName . 'に「'.$message.'」というSMSを送ります';
}
public function sendOrderAcceptanceMessage($customerName): void
{
$this->sendMessage($customerName, '注文を受け付けました');
}
}
/**
* メッセージ送信.
*/
class Messenger
{
protected MessengerImpl $impl;
public function Messenger(MessengerImpl $impl)
{
$this->impl = $impl;
}
public function sendMessage(string $customerName, string $message):void
{
$this->impl->sendMessage($customerName, $message);
}
}
/**
* 注文受付メッセージ送付機能を持つクラス.
*/
class OrderAcceptanceMessenger extends Messenger
{
public function sendOrderAcceptanceMessage(string $customerName): void
{
$this->impl->sendOrderAcceptanceMessage($customerName);
}
}
$messenger = new Messenger(new MailMessengerImpl());
$messenger->sendMessage('お客様', 'メッセージ内容');
echo "\n";
$messenger = new Messenger(new SmsMessengerImpl());
$messenger->sendMessage('お客様', 'メッセージ内容');
echo "\n";
$messenger = new OrderAcceptanceMessenger(new MailMessengerImpl());
$messenger->sendOrderAcceptanceMessage('お客様');
echo "\n";
$messenger = new OrderAcceptanceMessenger(new ChatMessengerImpl());
$messenger->sendOrderAcceptanceMessage('お客様');
このような作りにすることで、「何を送るか」と「どのように送るか」の組み合わせを自由に行うことができます。
Bridgeパターンを使わないと、次のようになります。
class MailMessenger
{
public function sendMessage($customerName, $message): void
{
echo $customerName . 'に「' . $message . '」というメールを送ります';
}
}
class OrderAcceptanceMailMessenger extends MailMessenger
{
public function sendOrderAcceptanceMessage($customerName): void
{
$this->sendMessage($customerName, '注文を受け付けました');
}
}
class ChatMessenger
{
public function sendMessage($customerName, $message): void
{
echo $customerName . 'に「' . $message . '」というチャットを送ります';
}
}
class OrderAcceptanceChatMessenger extends ChatMessenger
{
public function sendOrderAcceptanceMessage($customerName): void
{
$this->sendMessage($customerName, '注文を受け付けました');
}
}
class SmsMessenger
{
public function sendMessage($customerName, $message): void
{
echo $customerName . 'に「' . $message . '」というSMSを送ります';
}
}
class OrderAcceptanceSmsMessenger extends SmsMessenger
{
public function sendOrderAcceptanceMessage($customerName): void
{
$this->sendMessage($customerName, '注文を受け付けました');
}
}
$messenger = new MailMessenger();
$messenger->sendMessage('お客様', 'メッセージ内容');
echo "\n";
$messenger = new SmsMessenger();
$messenger->sendMessage('お客様', 'メッセージ内容');
echo "\n";
$messenger = new OrderAcceptanceMailMessenger();
$messenger->sendOrderAcceptanceMessage('お客様');
echo "\n";
$messenger = new OrderAcceptanceChatMessenger();
$messenger->sendOrderAcceptanceMessage('お客様');
さて、出荷完了メールを増やしたくなった場合、クラスの数はどうなるでしょう?
Bridgeパターンでは、機能側のクラスを増やし、各実装クラスにメソッドを追加します。
一方、Bridgeパターンを使わない方法の場合、クラスの数は機能の数と送信方法の数の積になってしまいます。
機能と実装を自由に組み合わせるような要件の場合にはBridgeパターンを検討してみると良いでしょう。