设计模式-装饰者模式(Go语言描述)

标签: go语言 设计模式
5489人阅读 评论(4) 收藏 举报
分类:

什么是装饰者模式

好久没有更新设计模式系列的博客了, 今天我们来聊一聊装饰者模式, 用过java的同学肯定对装饰者模式非常熟悉,就算你不知道什么是装饰者模式这概念, 你也一定在代码中经常用到这个模式,为什么这么说呢? 大家都用过java中的流吧, 我们可以这样写:

new BufferedOutputStream(new FileOutputStream());

大家对这样的代码肯定很熟悉了, 用另外一个类包装一下另外一个类, 或方便了我们的使用, 或增强了功能. 不是说设计模式嘛, 怎么扯开流了… 其实java中这种io操作的代码正式装饰者模式的一种使用.
那它有什么特点呢?

  1. 理论上它们是可以无限包装的.
  2. 装饰者和被装饰者们有相同的超类型(super).
  3. 想要拓展功能无需修改原有的代码, 定义一个装饰者就可以.

看了这些特点和上面的小段代码,不禁让我们想到了前面说的适配器模式, 越看越想适配器模式! 那他们有什么区别吗?其实区别很简单:

适配器模式是在类型不匹配的时候使用, 目的是将一种类型伪装成另一种类型以便我们的代码可以正常使用;而装饰者模式装饰者和被装饰者拥有相同的类型(相同的超类),目的是为了增强功能或者方便使用.

看完了区别,我们再从上面的代码和特点中找一下装饰者模式都是用了哪些设计原则.

  1. 从”包装”我们可以看到”多用组合,少用继承”
  2. 从”拓展”我们可以看到”开闭原则”

在不必改变原类文件和使用继承的情况下, 动态地扩展一个对象的功能. 它是通过创建一个包装对象, 也就是装饰来包裹真实的对象.

概念多看几遍,对照下面的代码理解一下就ok了.扯完了概念,下面我们就应该开始实战一下, 实现一下这个设计模式了.

代码描述环节

在上班的时候, 我和同时经常去路边吃各种路边摊, 吃的最多的还是各种面, 有纯面条的, 面条加鸡蛋的, 面条加火腿肠的… 下面我们就以面条为例来实现一下代码.
首先我们先来定义一个超类型, 也就是一个接口,用来规范面条的几个方法.

type Noddles interface {
    Description() string
    Price() float32
}

只有两个方法, 一个是面条的描述,另一个是价格. 接着我们搞一个拉面出来,

type Ramen struct {
    name  string
    price float32
}

func (p Ramen) Description() string {
    return p.name
}

func (p Ramen) Price() float32 {
    return p.price
}

拉面有两个属性nameprice, 同样他有两个方法DescriptionPrice, 所以它实现了上面的Noddles接口. 不着急下面的代码,我们先来造一碗面条尝尝.

面条出来了, 不过光吃面条不行,我想吃加蛋的面条, 咋办? 重写Ramen让他支持加蛋吗? 当然不行, 那以后我们还要加香肠,加西红柿呢? 难道每次推出新品种都要修改Ramen吗?
这当然不是一个好办法, 这个时候我们就可以使用装饰者模式了. 不就是加个鸡蛋嘛, 我们再定义一个鸡蛋的装饰者!

type Egg struct {
    noddles Noddles
    name    string
    price   float32
}

func (p Egg) SetNoddles(noddles Noddles) {
    p.noddles = noddles
}

func (p Egg) Description() string {
    return p.noddles.Description() + "+" + p.name
}

func (p Egg) Price() float32 {
    return p.noddles.Price() + p.price
}

这个鸡蛋装饰者比上面的Ramen多了一个Noddles类型的属性, 这个属性也就是我们将要装饰的类型, 我们下面提供了SetNoddles来设置它. 好了,现在鸡蛋装饰者有了, 可以给我搞一个
加鸡蛋的拉面了吧.

ramen := Ramen{name: "ramen", price: 10}
egg := Egg{noddles: ramen, name: "egg", price: 2}

fmt.Println(egg.Description())
fmt.Println(egg.Price())

我们再初始化Egg的时候只需要指定一下要被装饰的对象就可以了. 来看看加了鸡蛋的拉面长啥样.

鸡蛋是加上了, 价格也变贵了. 突然有一天我想吃带香肠的鸡蛋拉面了, 你说咋办? 很简单, 依鸡蛋画瓢, 搞出一个香肠的装饰者来.

type Sausage struct {
    noddles Noddles
    name    string
    price   float32
}

func (p Sausage) SetNoddles(noddles Noddles) {
    p.noddles = noddles
}

func (p Sausage) Description() string {
    return p.noddles.Description() + "+" + p.name
}

func (p Sausage) Price() float32 {
    return p.noddles.Price() + p.price
}

看看我这个加了香肠和鸡蛋的拉面吧.

现在香肠也加上了, 不过价格又高了, 虽然价格贵了点,不过我们终于搞明白什么是装饰者模式了, 还是很开心的. 到现在为止, 我们不仅可以吃上香肠鸡蛋面, 还可以吃双蛋面!

ramen := Ramen{name: "ramen", price: 10}
egg := Egg{noddles: ramen, name: "egg", price: 2}
egg2 := Egg{noddles: egg, name: "egg", price: 2}

fmt.Println(egg2.Description())
fmt.Println(egg2.Price())

突然发现, 现在我可以吃任意组合的面了, 好开心, 你可以试试加4个鸡蛋5根香肠啥效果.
总结: 不总结了, 上面扯概念的时候扯的差不多了, 在装饰者模式中我们再一次见识到了组合的魅力, 所以多用组合,少用继承.

代码放github上了,欢迎star: https://github.com/qibin0506/go-designpattern

查看评论

Golang设计模式之装饰模式

1. 概述装饰模式就是在不改变对象内部结构的情况下,动态扩展它的功能。它提供了灵活的方法来扩展对象的功能。2. 实现下面是一个简单的实现逻辑,通过Decorate来进一步装饰Dressing函数:ty...
  • Jeanphorn
  • Jeanphorn
  • 2017-10-14 21:20:47
  • 917

golang设计模式(9)装饰模式

golang装饰模式
  • m0_38132420
  • m0_38132420
  • 2017-10-24 10:33:35
  • 141

设计模式-单例模式(Go语言描述)

这篇博客我们继续来看设计模式,今天带来的是一个最简单而且最常用的模式-单例模式。那什么是单例模式呢?相信大家最它最熟悉不过了,那我们就来快速的了解一下它的定义。 保证一个类仅有一个实例,并提供一个...
  • qibin0506
  • qibin0506
  • 2016-02-24 20:30:18
  • 12945

设计模式-策略模式(Go语言描述)

好久没有更新博客了,最近也是在忙着充电,从今天这篇博客开始,我们来了解一下设计模式。设计模式那什么是设计模式呢?首先来看看我从百科上copy下来的概念吧。 设计模式/软件设计模式(Design p...
  • qibin0506
  • qibin0506
  • 2016-01-22 23:49:23
  • 6725

设计模式练习(9)——装饰模式

装饰模式 一、题目:简单的手机(SimplePhone)在接收到来电的时候,会发出声音来提醒主人,而现在我们需要为该手机添加一项功能,在接收来电的时候,除了有声音,还能产生震动(JarPhone),还...
  • qq_33220449
  • qq_33220449
  • 2017-01-20 15:30:30
  • 813

设计模式-装饰者模式(Go语言描述)

什么是装饰者模式好久没有更新设计模式系列的博客了, 今天我们来聊一聊装饰者模式, 用过java的同学肯定对装饰者模式非常熟悉,就算你不知道什么是装饰者模式这概念, 你也一定在代码中经常用到这个模式,为...
  • qibin0506
  • qibin0506
  • 2016-04-07 08:55:07
  • 5489

golang视角下的设计模式

单利模式func NewSingleton() *singleton {    if instance == nil {         instance = &singleton{}...
  • lengyuezuixue
  • lengyuezuixue
  • 2018-03-26 13:06:02
  • 23

Head First设计模式:(三)装饰者模式

星巴兹咖啡准备更新订单系统,以合乎他们的饮料供应需求。 他们原先的类设计为: 这样的订单系统没有办法考虑到咖啡调料的部分,把加入不同调料的咖啡看做不同的类会导致类爆炸(每个类的cost方法计算...
  • lissdy
  • lissdy
  • 2012-05-06 19:31:09
  • 3145

最常用的设计模式---装饰者模式(C++实现)

最常用的设计模式---适配器模式(C++实现)
  • lh844386434
  • lh844386434
  • 2014-01-06 22:39:18
  • 2124

设计模式之golang实现策略

package strategy type cashCal interface { cashCal(float64) float64 } type deal struct{} type nor...
  • Yvlen
  • Yvlen
  • 2018-01-30 16:55:12
  • 45
    个人资料
    专栏达人 持之以恒
    等级:
    访问量: 68万+
    积分: 7043
    排名: 4048
    友情链接

    鸿洋_

    Aggie的博客

    梁肖技术中心

    极客导航

    文章分类
    博客专栏
    最新评论