设计模式--装饰者(Decorator)模式

模式定义

动态(组合)地给一个对象增加一些额外的职责,就增加功能而言,Decorator模式比生成子类(继承)更为灵活(消除重复代码并且减少子类个数)

类图

image-20210719214707356.png

应用场景

扩展一个类的功能或给一个类添加附加职责

优点

1.符合开闭原则

2.不改变原有对象的情况下给一个对象扩展功能

3.使用不同的组合可以实现不同的效果

要点总结

  • 通过采用组合而非继承的手法,Decorator模式实现了在运行时动态扩展对象功能的能力,而且可以根据需要扩展多个功能。避免了使用继承带来的“灵活性差”和“多子类衍生问题”
  • Decorator类在接口上表现为is-a 的继承关系,即Decorator类继承了Component类所具有的接口,但在实现上又表现为has-a的组合关系,即Decorator类又使用了另外一个Component类
  • Decorator模式的目的并非解决“多子类衍生的多继承”问题,Decorator模式应用的要点在于解决“主体类在多个问题方向上的扩展功能”–是为“装饰”的含义

Go语言代码实现

举个例子,假设我们正在开发一个咖啡店的订单系统,我们需要为咖啡提供不同的调料选项,例如牛奶、糖浆、巧克力等。每个调料都有不同的价格,而且可以组合使用。这里,咖啡是原始对象,而调料是装饰者。我们可以通过装饰者模式来动态地为咖啡添加不同的调料。

下面是通过 Golang 实现的简单示例:

package main

import "fmt"

// 咖啡接口
type Coffee interface {
	GetDescription() string
	GetCost() float64
}

// 原始咖啡
type SimpleCoffee struct{}

func (c *SimpleCoffee) GetDescription() string {
	return "简单咖啡"
}

func (c *SimpleCoffee) GetCost() float64 {
	return 1.0
}

// 调料装饰者
type CoffeeDecorator struct {
	Coffee Coffee
}

func (cd *CoffeeDecorator) GetDescription() string {
	return cd.Coffee.GetDescription()
}

func (cd *CoffeeDecorator) GetCost() float64 {
	return cd.Coffee.GetCost()
}

// 牛奶调料
type MilkDecorator struct {
	CoffeeDecorator
}

func (md *MilkDecorator) GetDescription() string {
	return md.CoffeeDecorator.GetDescription() + " + 牛奶"
}

func (md *MilkDecorator) GetCost() float64 {
	return md.CoffeeDecorator.GetCost() + 0.5
}

// 糖浆调料
type SyrupDecorator struct {
	CoffeeDecorator
}

func (sd *SyrupDecorator) GetDescription() string {
	return sd.CoffeeDecorator.GetDescription() + " + 糖浆"
}

func (sd *SyrupDecorator) GetCost() float64 {
	return sd.CoffeeDecorator.GetCost() + 0.3
}

func main() {
	// 创建原始咖啡
	coffee := &SimpleCoffee{}
	fmt.Println(coffee.GetDescription()) // 输出:简单咖啡
	fmt.Println(coffee.GetCost())       // 输出:1.0

	// 添加牛奶调料
	coffeeWithMilk := &MilkDecorator{CoffeeDecorator{coffee}}
	fmt.Println(coffeeWithMilk.GetDescription()) // 输出:简单咖啡 + 牛奶
	fmt.Println(coffeeWithMilk.GetCost())       // 输出:1.5

	// 添加糖浆调料
	coffeeWithMilkAndSyrup := &SyrupDecorator{CoffeeDecorator{coffeeWithMilk}}
	fmt.Println(coffeeWithMilkAndSyrup.GetDescription()) // 输出:简单咖啡 + 牛奶 + 糖浆
	fmt.Println(coffeeWithMilkAndSyrup.GetCost())       //
}

通过装饰者模式,我们实现了在简单咖啡的基础上可以添加牛奶和添加糖浆的功能,在简单牛奶咖啡的基础上添加糖浆的任意组合功能。

桥接设计模式和装饰者设计模式有一些相似之处,但也存在一些不同点。

共同点:

结构型模式:桥接模式和装饰者模式都是结构型设计模式,关注对象之间的组织和关联关系。
解耦抽象和实现:两种模式都通过将抽象和实现部分分离,实现了解耦的目的。
动态性:两种模式都具有动态性,可以在运行时动态地添加或修改对象的行为。
不同点:

关注点:桥接模式的主要关注点是将抽象和实现分离,以便它们可以独立地变化。而装饰者模式的主要关注点是在不修改现有对象结构的情况下,动态地添加功能。
目的:桥接模式的目的是将抽象和实现解耦,使它们可以独立变化。而装饰者模式的目的是动态地为对象添加功能,同时保持接口的一致性。
参与者:桥接模式中,抽象部分和实现部分是两个独立的层次结构,它们之间可以自由组合。而装饰者模式中,装饰者对象包装原始对象,并通过组合的方式为其添加功能。
使用方式:桥接模式通常在系统设计初期使用,用于处理两个独立变化的维度。而装饰者模式通常在系统已经存在一些基本功能的情况下使用,用于动态地添加额外的功能。
需要注意的是,桥接模式和装饰者模式虽然具有一些相似之处,但它们的关注点和目的略有不同。在实际应用中,应根据具体需求选择适合的设计模式。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值