【设计模式】7、decorate 装饰模式

七、decorate 装饰模式

装饰设计(装饰者模式 / 装饰器模式)

如果希望增强行为,可以使用 decorate 模式。且支持嵌套多层(套娃)。

和 proxy 模式的区别:proxy 只套了一层,而且行为相同。而 decorate 可以套多层,且行为会增强。

以具体例子,会更容易理解。

7.1 饮料:类型+配料

参考:https://www.bilibili.com/video/BV1Vp4y187dK/?spm_id_from=333.337.search-card.all.click&vd_source=5dfe92471f5072eaffbf480e25acd82d

有多种饮料类型:如奶茶、绿茶、柠檬茶。

如果希望在此基础上,添加配料:如布丁、珍珠、糖。

则可以定义【配料装饰者 interface】,并使 布丁、珍珠分别实现该 interface。

那么就可以套娃了,比如:

奶茶 = New奶茶()1份布丁的奶茶 = New布丁(奶茶)2份布丁的奶茶 = New布丁(New布丁(奶茶))2份布丁, 且加3份珍珠的奶茶 = New珍珠(New珍珠(New珍珠(New布丁(New布丁(奶茶)))))

上文的配料就是装饰:因为各种配料都实现了同样的 interface,所以可以层层嵌套。每层都“增强”了行为。

目录层级如下:

07decorator/071drink_ingredient
├── drink.go
├── drink_with_ingredient.go
└── drink_with_ingredient_test.go

7.1.1 drink_with_ingredient_test.go

package _71drink_ingredient

import (
	"github.com/stretchr/testify/require"
	"testing"
)

/*
=== RUN   TestDrinkWithIngredient
一杯奶茶 20 元

一杯奶茶 20 元
加 3 元的糖后, 共 23 元.

一杯奶茶 20 元
加 3 元的糖后, 共 23 元. 加 3 元的糖后, 共 26 元.

一杯奶茶 20 元
加 3 元的糖后, 共 23 元. 加 3 元的糖后, 共 26 元. 加 1 元的冰后, 共 27 元.

--- PASS: TestDrinkWithIngredient (0.00s)
PASS
*/
func TestDrinkWithIngredient(t *testing.T) {
	m := &milkTea{}
	require.EqualValues(t, 20, m.cost())
	t.Log()

	ms := &drinkWithSugar{m}
	require.EqualValues(t, 20+3, ms.cost())
	t.Log()

	mss := &drinkWithSugar{ms}
	require.EqualValues(t, 20+3+3, mss.cost())
	t.Log()

	mssi := &drinkWithIce{mss}
	require.EqualValues(t, 20+3+3+1, mssi.cost())
}



/*
=== RUN   TestDrinkWithIngredientByInterface
一杯奶茶 20 元
加 3 元的糖后, 共 23 元. 加 3 元的糖后, 共 26 元. 加 1 元的冰后, 共 27 元.
--- PASS: TestDrinkWithIngredientByInterface (0.00s)
PASS
*/
func TestDrinkWithIngredientByInterface(t *testing.T) {
	var d drinkWithIngredient = &milkTea{}
	for i := 0; i < 2; i++ {
		d = &drinkWithSugar{d}
	}
	d = &drinkWithIce{d}
	require.EqualValues(t, 20+3+3+1, d.cost())
}

7.1.2 drink_with_ingredient.go

package _71drink_ingredient

import "fmt"

// 饮料装饰器: 加配料的饮料
type drinkWithIngredient interface {
	// 饮料的价格
	cost() int
}

// 加糖饮料
type drinkWithSugar struct {
	d drinkWithIngredient
}

func (d *drinkWithSugar) cost() int {
	c := 3
	total := d.d.cost() + c
	fmt.Printf("加 %v 元的糖后, 共 %v 元. ", c, total)
	return total
}

// 加冰饮料
type drinkWithIce struct {
	d drinkWithIngredient
}

func (d *drinkWithIce) cost() int {
	c := 1
	total := d.d.cost() + c
	fmt.Printf("加 %v 元的冰后, 共 %v 元. ", c, total)
	return total
}

7.1.3 drink.go

package _71drink_ingredient

import "fmt"

// 饮料
type drink interface {
	// 饮料的价格
	cost() int
}

// 奶茶
type milkTea struct{}

func (t *milkTea) cost() int {
	c := 20
	fmt.Printf("一杯奶茶 %v 元\n", c)
	return c
}

// 绿茶
type greenTea struct{}

func (t *greenTea) cost() int {
	c := 10
	fmt.Printf("一杯绿茶 %v 元\n", c)
	return c
}

// 柠檬茶
type lemonTea struct{}

func (t *lemonTea) cost() int {
	c := 5
	fmt.Printf("一杯柠檬茶 %v 元\n", c)
	return c
}

7.2 notifier

07decorator/072notifier
├── notifier.go
├── notifier_decorator.go
└── notifier_decorator_test.go

7.2.1 notifier_decorator_test

/*
=== RUN   TestNotifierDecorator
qq发送消息
wechat发送消息
phone发送消息
--- PASS: TestNotifierDecorator (0.00s)
PASS
*/
func TestNotifierDecorator(t *testing.T) {
	var n notifierDecorator
	n = &qqNotifierDecorator{}
	n = &wechatNotifierDecorator{wrappee: n}
	n = &phoneNotifierDecorator{wrappee: n}
	n.notify()
}

7.2.2 notifier_decorator

package _72notifier

import "fmt"

type notifierDecorator interface {
	notifier
}

type qqNotifierDecorator struct {
	wrappee notifierDecorator
}

func (n *qqNotifierDecorator) notify() {
	if n.wrappee != nil {
		n.wrappee.notify()
	}
	fmt.Println("qq发送消息")
}

type wechatNotifierDecorator struct {
	wrappee notifierDecorator
}

func (n *wechatNotifierDecorator) notify() {
	if n.wrappee != nil {
		n.wrappee.notify()
	}
	fmt.Println("wechat发送消息")
}

type phoneNotifierDecorator struct {
	wrappee notifierDecorator
}

func (n *phoneNotifierDecorator) notify() {
	if n.wrappee != nil {
		n.wrappee.notify()
	}
	fmt.Println("phone发送消息")
}

7.2.3 notifier

package _72notifier

type notifier interface {
	notify()
}

相关推荐

  1. 设计模式7decorate 装饰模式

    2024-04-21 19:14:03       14 阅读
  2. 设计模式-装饰模式 Decorator

    2024-04-21 19:14:03       31 阅读
  3. 设计模式--装饰模式Decorator Pattern)

    2024-04-21 19:14:03       21 阅读
  4. 设计模式装饰模式Decorator Pattern)

    2024-04-21 19:14:03       19 阅读
  5. 装饰模式Decorator

    2024-04-21 19:14:03       35 阅读

最近更新

  1. TCP协议是安全的吗?

    2024-04-21 19:14:03       19 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-04-21 19:14:03       19 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-04-21 19:14:03       19 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-04-21 19:14:03       20 阅读

热门阅读

  1. 黑马点评项目遇到的部分问题

    2024-04-21 19:14:03       57 阅读
  2. 关于指针变量的理解

    2024-04-21 19:14:03       17 阅读
  3. react脚手架创建项目,配置别名(alias)

    2024-04-21 19:14:03       17 阅读
  4. 面试经典150题——跳跃游戏

    2024-04-21 19:14:03       40 阅读
  5. dns高防和ip高防的区别是什么?

    2024-04-21 19:14:03       50 阅读
  6. IP和域名可以共用一个SSL证书吗

    2024-04-21 19:14:03       21 阅读
  7. 物理安全-中的网络安全包含哪些内容

    2024-04-21 19:14:03       36 阅读
  8. js生成pdf

    2024-04-21 19:14:03       35 阅读