结构型 装饰器模式

为什么需要装饰器模式

装饰器模式在python中很常见到,这种设计模式相当于给原有的类套上马甲,让返回的新类拥有更多的功能。这类用作马甲的类一般来说本身并不实现业务方面的逻辑而是实现一些更加通用的增加功能,例如整块读写。

其中最出名的应该是Java的BufferedInputStream了,对于任何实现了InputStream的类,这个都能提供缓冲写入的功能,减少io消耗。

有一个经常用来做对比的情况是,装饰器模式和代理模式上面有什么区别?我个人的理解是,如果装饰器模式更多是一个打辅助的角色,使用者其实更加关心的是被装饰的业务类。对比之下,代理模式增加的新功能与原来的业务功能并不太相关,想封装具体的业务类例如rpc代理的实现就是封装网络交流和具体的类,处理了更多的“杂事”。

实现

我的例子用游戏中的武器,你有枪,可以增加爆炸效果,对伤害进行了增强。我这里使用了Golang的匿名组合,把interface 加到需要被decorate的Explosive类那里。

go.mod

module decorator

go 1.13

decorator.go

package decorator

type Weapon interface {
	Damage() int
}

type Gun struct {
	base int
}

func NewGun(base int) *Gun {
	return &Gun{base: base}
}
func (g *Gun) Damage() int {
	return g.base
}

type Explosive struct {
	Weapon     // anonymous import
	additional int
}

func AddExplosive(w Weapon, additional int) *Explosive {
	return &Explosive{
		Weapon:     w,
		additional: additional,
	}
}

func (e *Explosive) Damage() int {
	return e.Weapon.Damage() + e.additional
}

decorator_test.go

package decorator_test

import (
	"decorator"
	"testing"
)

func TestDecorator(t *testing.T) {
	gun := decorator.NewGun(20)
	if decorator.AddExplosive(gun, 5).Damage() != 25 {
		t.Fatal("Decorator is not implemented correctly")
	}
}

执行: go test decorator -v

Previous
Next