GoLang设计模式21 - 装饰模式
装饰器模式是一种结构型设计模式。通过装饰器模式可以为一个对象添加额外的功能而不需对其作出调整。
还是通过具体的案例来了解装饰器模式:假设我们开了一家披萨店,现在店里主营两款披萨:
- 素食狂披萨(Veggie Mania Pizza)
- 活力豆腐披萨(Peppy Tofu pizza)
以上两款披萨有不同的价格,为获取价格需要定义这样一个接口:
package main
type pizza interface {
getPrice() int
}
然后需要这两款披萨分别创建一个struct并实现getPrice()函数来返回价格。因为定义了getPrice()函数,因此这两款披萨的struct可以视为实现了pizza接口。
现在又有了一些变化:我们为设计了一些特色配料,这些配料也是需要收费的。这样我们需要修改下之前的pizza接口,通过装饰器的形式将配料(topping)的信息给加进去。当前已有的配料为:
- 番茄酱(TomatoTopping)
- 奶酪(CheeseTopping)
另外,我们也得注意,加了配料的披萨也是一种新的披萨,所以现在顾客有了更多的选择:
- 素食狂披萨 + 番茄酱
- 素食狂披萨 + 奶酪
- 不加任何配料的素食狂披萨
- 活力豆腐披萨 + 番茄酱
- ...
加上配料的信息后情况变得复杂起来了,为每种选择都创建一个新的struct明显是不可行的。装饰器模式是一个不错的解决方案:使用装饰器模式可以在不修改已有的struct的前提下添加额外的功能。要使用装饰器模式,我们需要为每种配料(Topping)分别创建一个struct。配料的struct也需要继承前面的pizza接口并嵌入一个pizza接口的实例。
现在每种披萨以及每种配料都有一个独立的struct了。每种披萨和配料都有各自的价格。当为披萨添加配料的时候,只需要在披萨的价格的基础上加上配料的价格就可以计算出最终的价格。
现在可以看到装饰器模式的作用了:我们不需要对pizza struct做任何调整,只是在pizza对象的基础上做了一些装饰就得到了最终的价格。在这个过程中pizza struct不知道 topping struct的任何信息,只知道自己的价格。
下面是装饰器模型的UML类图:
类图中ConcreteComponent(VeggieMania和PeppyTofu)和ConcreteDecorator(Topping)都实现了Component接口(Pizza),并且ConcreteDecorator还嵌入了一个Component接口的一个实例。
对比我们前面的例子:
pizza接口是图中的ComponentveggieMania和peppyPanner是图中的ConcreteComponent,他们都实现了pizza接口- ConcreteDecorator的代表是
cheeseTopping和tomatoTopping,它们也都实现了pizza接口,同时它们也都嵌入了一个pizza接口的实例
来看看具体的代码吧:
pizza.go
type pizza interface {
getPrice() int
}
peppyTofu.go
type peppyTofu struct {
}
func (p *peppyTofu) getPrice() int {
return 20
}
veggeMania.go
type veggieMania struct {
}
func (p *veggieMania) getPrice() int {
return 15
}
cheeseTopping.go
type cheeseTopping struct {
pizza pizza
}
func (c *cheeseTopping) getPrice() int {
pizzaPrice := c.pizza.getPrice()
return pizzaPrice + 10
}
tomatoTopping.go
type tomatoTopping struct {
pizza pizza
}
func (c *tomatoTopping) getPrice() int {
pizzaPrice := c.pizza.getPrice()
return pizzaPrice + 7
}
main.go
func main() {
veggiePizza := &veggieMania{}
//Add cheese topping
veggiePizzaWithCheese := &cheeseTopping{
pizza: veggiePizza,
}
//Add tomato topping
veggiePizzaWithCheeseAndTomato := &tomatoTopping{
pizza: veggiePizzaWithCheese,
}
fmt.Printf("Price of veggieMania pizza with tomato and cheese topping is %d\n", veggiePizzaWithCheeseAndTomato.getPrice())
peppyTofuPizza := &peppyTofu{}
//Add cheese topping
peppyTofuPizzaWithCheese := &cheeseTopping{
pizza: peppyTofuPizza,
}
fmt.Printf("Price of peppyTofu with tomato and cheese topping is %d\n", peppyTofuPizzaWithCheese.getPrice())
}
输出内容:
Price of veggieMania pizza with tomato and cheese topping is 32
Price of peppyTofu with tomato and cheese topping is 30
代码已上传至GitHub: zhyea / go-patterns / decorator-pattern
END!!!
GoLang设计模式21 - 装饰模式的更多相关文章
- 乐在其中设计模式(C#) - 装饰模式(Decorator Pattern)
原文:乐在其中设计模式(C#) - 装饰模式(Decorator Pattern) [索引页][源码下载] 乐在其中设计模式(C#) - 装饰模式(Decorator Pattern) 作者:weba ...
- Golang设计模式—简单工厂模式(Simple Factory Pattern)
Golang设计模式--简单工厂模式 背景 假设我们在做一款小型翻译软件,软件可以将德语.英语.日语都翻译成目标中文,并显示在前端. 思路 我们会有三个具体的语言翻译结构体,或许以后还有更多,但现在分 ...
- 数据结构和算法(Golang实现)(21)排序算法-插入排序
插入排序 插入排序,一般我们指的是简单插入排序,也可以叫直接插入排序.就是说,每次把一个数插到已经排好序的数列里面形成新的排好序的数列,以此反复. 插入排序属于插入类排序算法. 除了我以外,有些人打扑 ...
- Golang 常见设计模式之装饰模式
想必只要是熟悉 Python 的同学对装饰模式一定不会陌生,这类 Python 从语法上原生支持的装饰器,大大提高了装饰模式在 Python 中的应用.尽管 Go 语言中装饰模式没有 Python 中 ...
- .net设计模式之装饰模式
概述: 装饰模式是在不必改变原类文件和使用继承的情况下,动态地扩展一个对象的功能.它是通过创建一个包装对象,也就是装饰来包裹真实的对象. 装饰模式的特点: (1) 装饰对象和真实对象有相同的接口.这样 ...
- 设计模式之装饰模式(Decorator)摘录
版权声明:本文为博主原创文章,未经博主同意不得转载. https://blog.csdn.net/fengbingchun/article/details/29237955 23种GOF设计模式一般分 ...
- java设计模式之装饰模式
发现设计模式的学习越来越让自己学习的东西太少了,应该多接触一些东西,多出去走一走. 装饰模式概念: 动态地给一个对象添加一些额外的职责,就增加功能来说,装饰模式比生成子类更为灵活(大话设计模式) 在不 ...
- 【GOF23设计模式】装饰模式
来源:http://www.bjsxt.com/ 一.[GOF23设计模式]_装饰模式.IO流底层架构.装饰和桥接模式的区别 package com.test.decorator; /** * Com ...
- Java——设计模式(装饰模式_IO)
/* * 装饰设计模式: * 对一组对象的功能进行增强时,就可以使用该模式进行问题的解决; * 装饰和继承都能实现一样的特点: 就是进行功能的扩转增强. * */ public class ...
随机推荐
- Linux性能优化实战(一)
一.优化方向 1,性能指标 从应用负载的视角出发,考虑"吞吐"和"延时" 从系统资源的视角出发,考虑资源使用率.饱和度等 2,性能优化步骤 选择指标评估应用程序 ...
- react之withRouter的作用
withRouter的作用:把不是通过路由切换过来的组件,将react-router的history.location和match三个对象传入到props对象上: 默认情况下必须是经过路由匹配渲染的组 ...
- Android状态栏微技巧,带你真正理解沉浸式模式【转】
感谢! 本文转自大佬郭霖:http://blog.csdn.net/guolin_blog/article/details/51763825 转载请注明出处:http://blog.csdn.net/ ...
- linux 多个C源文件编译
转载请注明来源:https://www.cnblogs.com/hookjc/ 如果有多个源文件,基本上有两种编译方法: [假设有两个源文件为test.c和testfun.c] 1. 多个文件一起编译 ...
- mac brew安装
mac 安装homebrew出错 Failed to connect to raw.githubusercontent.com port 443: Connection refused error:原 ...
- sublime配置大全
配置:Preferences→Settings-User 字体和字体大小 "font_face": "YaHei Consolas Hybrid", " ...
- [转]API性能测试基本性能指标及要求
原文链接http://blog.csdn.net/strawbingo/article/details/46458959 指标的基本概念 1.事务(Transaction) 在web性能测试中,一个事 ...
- 基于redis5的redis cluster部署
一.环境规划 #准备六台主机,地址如下 10.0.0.8 ---> master1 10.0.0.18 ---> master2 10.0.0.28 ---> master3 10. ...
- Linux中使用systemctl操作服务、新建自定义服务
Linux有12种Unit,对于个人来讲,用的最多的是Service Unit,下面的Unit均指Service Unit(服务单元) # 启动Unit systemctl start appname ...
- Java泛型详解,史上最全图文详解!
泛型在java中有很重要的地位,无论是开源框架还是JDK源码都能看到它. 毫不夸张的说,泛型是通用设计上必不可少的元素,所以真正理解与正确使用泛型,是一门必修课. 一:泛型本质 Java 泛型(gen ...