package decorator
import (
"errors"
"fmt"
)
type IngredientAdder interface {
AddIngredient() (string, error)
}
type PizzaDecorator struct {
Ingredient IngredientAdder
}
func (p *PizzaDecorator) AddIngredient() (string, error) {
return "Pizza with the following ingredients:", nil
}
type Meat struct {
Ingredient IngredientAdder
}
func (m *Meat) AddIngredient() (string, error) {
if m.Ingredient == nil {
return "", errors.New("An IngredientAdder is needed on the Ingredient field of the Meat")
}
s, err := m.Ingredient.AddIngredient()
if err != nil {
return "", err
}
return fmt.Sprintf("%s %s", s, "meat"), nil
}
type Onion struct {
Ingredient IngredientAdder
}
func (o *Onion) AddIngredient() (string, error) {
if o.Ingredient == nil {
return "", errors.New("An IngredientAdder is needed on the Ingredient field of the Onion")
}
s, err := o.Ingredient.AddIngredient()
if err != nil {
return "", err
}
return fmt.Sprintf("%s %s", s, "onion"), nil
}
装饰器模式测试
package decorator
import (
"strings"
"testing"
)
func TestPizzaDecorator_AddIngredient(t *testing.T) {
pizza := &PizzaDecorator{}
pizzaResult, err := pizza.AddIngredient()
if err != nil {
t.Error(err)
}
expectedText := "Pizza with the following ingredients:"
if !strings.Contains(pizzaResult, expectedText) {
t.Errorf("When calling the add ingredient of the pizza decorator it "+
"must return the text %s, not '%s'", expectedText, pizzaResult)
}
}
func TestOnion_AddIngredient(t *testing.T) {
onion := &Onion{}
onionResult, err := onion.AddIngredient()
if err == nil {
t.Errorf("When calling AddIngredient on the onion decorator without "+
"an IngredientAdder on its Ingredient field it must return an error, "+
"not a string with '%s'", onionResult)
}
onion = &Onion{&PizzaDecorator{}}
onionResult, err = onion.AddIngredient()
if err != nil {
t.Error(err)
}
if !strings.Contains(onionResult, "onion") {
t.Errorf("When calling the add ingredient of the onion decorator it "+
"must return a text with the word 'onion', not '%s'", onionResult)
}
}
func TestMeat_AddIngredient(t *testing.T) {
meat := &Meat{}
meatResult, err := meat.AddIngredient()
if err == nil {
t.Errorf("When calling AddIngredient on the meat decorator without " +
"an IngredientAdder on its Ingredient field must return an error, " +
"not a string with '%s'", meatResult)
}
meat = &Meat{&PizzaDecorator{}}
meatResult, err = meat.AddIngredient()
if err != nil {
t.Error(err)
}
if !strings.Contains(meatResult, "meat") {
t.Errorf("When calling the AddIngredient of the meat decorator it "+
"must return a text with the word 'meat', not '%s'", meatResult)
}
}
func TestPizzaDecorator_FullStack(t *testing.T) {
pizza := &Onion{&Meat{&PizzaDecorator{}}}
pizzaResult, err := pizza.AddIngredient()
if err != nil {
t.Error(err)
}
expectedText := "Pizza with the following ingredients: meat onion"
if !strings.Contains(pizzaResult, expectedText) {
t.Errorf("When asking for a pizza with onion and meat the returned "+
"string must contain the text '%s' but '%s' didn't have it", expectedText,
pizzaResult)
}
}
有疑问加站长微信联系(非本文作者)