解答 01.6 — SOLID(OrderService)¶
このノートブックは 01.6-solid-design-patterns.ipynb の練習問題の解答です。
先に自分の力で解いてから、答え合わせに使ってください。
前提コード(問題ノートブックと同じ定義)¶
In [1]:
import "fmt"
In [2]:
type Notifier interface {
Notify(message string) error
}
解答: OrderService¶
Complete は注入された抽象(Notifier)にだけ依存します。具体的な通知方法を一切知りません(DIP)。
In [3]:
type OrderService struct {
notifier Notifier
}
func NewOrderService(n Notifier) *OrderService {
return &OrderService{notifier: n}
}
func (s *OrderService) Complete(orderID string) error {
return s.notifier.Notify("注文 " + orderID + " が完了しました")
}
チェック(問題ノートブックと同じ期待値)¶
In [4]:
import "reflect"
import "fmt"
func mustEqual(got, want any, name string) {
if reflect.DeepEqual(got, want) {
fmt.Printf("✅ Passed: %s\n", name)
return
}
panic(fmt.Sprintf("❌ %s\n got = %v (%T)\n want = %v (%T)", name, got, got, want, want))
}
In [5]:
type recorderNotifier struct {
messages []string
}
func (r *recorderNotifier) Notify(message string) error {
r.messages = append(r.messages, message)
return nil
}
In [6]:
%%
rec := &recorderNotifier{}
svc := NewOrderService(rec)
err := svc.Complete("ORD-1")
mustEqual(err, nil, "Complete はエラーなし")
mustEqual(rec.messages, []string{"注文 ORD-1 が完了しました"}, "注入された notifier が使われた")
mustEqual(len(rec.messages), 1, "1 回だけ通知された")
println("🎉 すべてのチェックが通りました")
✅ Passed: Complete はエラーなし ✅ Passed: 注入された notifier が使われた ✅ Passed: 1 回だけ通知された
🎉 すべてのチェックが通りました
解説¶
type OrderService struct { notifier Notifier }— フィールドが具体的な型(EmailNotifier等)でなく抽象(Notifierinterface)です。これが DIP の核心ですNewOrderService(n Notifier)— コンストラクタで依存を注入します(依存性注入 DI)return s.notifier.Notify("注文 " + orderID + " が完了しました")— 自分は通知の実装を知らず、抽象に丸投げします
OrderService は「注文完了を通知する」という責任だけを持ち、通知の実装は注入された Notifier が担います。
こうすることで、通知方法の追加(OCP)も、テストでのモック差し替えも、OrderService を変更せずに行えます。