goでストラテジーパターンを用いてある処理のふるまいを変更していました。
すべての具体的なストラテジーに対して、付加的な処理を入れる場合と入れない場合が出てきたので、デコレーターパターンを用いて対応を検討しました。chatgptに質問すると、下記のように、インターフェースを埋め込むことで対応できることがわかりました。この場合、デコレーター構造体側でストラテジーの大元のインターフェースのメソッドをすべて実装しないとデコレーターがストラテジーインターフェースを満たしてくれませんでした。ほとんど委譲しかしないメソッドを定義しないとならないのですが(下記の例で言うと、Refundのようなメソッドが大量にあるイメージです。)、これは仕方のないことでしょうか。
ほかにgoらしいスマートなやり方があれば教えていただきたいです。よろしくお願いいたします。
package main
import "fmt"
// 支払い方法のストラテジー
type PaymentStrategy interface {
Pay(amount float64) string
Refund(amount float64) string
}
// クレジットカード支払い
type CreditCardStrategy struct{}
func (c *CreditCardStrategy) Pay(amount float64) string {
return fmt.Sprintf("クレジットカードで %.2f 円支払いました", amount)
}
func (c *CreditCardStrategy) Refund(amount float64) string {
return fmt.Sprintf("クレジットカードで %.2f 円返金しました", amount)
}
// 手数料デコレーター
type FeeDecorator struct {
strategy PaymentStrategy
fee float64
}
func (d *FeeDecorator) Pay(amount float64) string {
totalAmount := amount + d.fee
return fmt.Sprintf("%s(手数料 %.2f 円込み)", d.strategy.Pay(totalAmount), d.fee)
}
func (d *FeeDecorator) Refund(amount float64) string {
// 手数料デコレーターはRefundメソッドに手数料を加える必要はないため、そのまま委譲する
return d.strategy.Refund(amount)
}
func main() {
creditCard := &CreditCardStrategy{}
creditCardWithFee := &FeeDecorator{strategy: creditCard, fee: 2.0}
fmt.Println(creditCardWithFee.Pay(100.0))
fmt.Println(creditCardWithFee.Refund(50.0))
}