Skip to content

简介

装饰模式(Decorator Pattern):动态地给一个对象增加一些额外的职责,就增加对象功能来说,装饰模式比生成子类实现更为灵活。装饰模式是一种对象结构型模式。

装饰模式中的角色和职责

Component(抽象构件)

它是具体构件和抽象装饰类的共同父类,声明了在具体构件中实现的业务方法,它的引入可以使客户端以一致的方式处理未被装饰的对象以及装饰之后的对象,实现客户端的透明操作。

ConcreteComponent(具体构件)

它是抽象构件类的子类,用于定义具体的构件对象,实现了在抽象构件中声明的方法,装饰器可以给它增加额外的职责(方法)

代码

在装饰器模式中,“裸机”、“有贴膜的手机”、“有手机壳的手机”、“有手机壳&贴膜的手机”都是一个构件。 “贴膜装饰器”、“手机壳装饰器”是装饰器也是一个构件。

package main

import "fmt"

// ---------- 抽象层 ----------
//抽象的构件
type Phone interface {
    Show() //构件的功能
}

//装饰器基础类(该类本应该为interface,但是Golang interface语法不可以有成员属性)
type Decorator struct {
    phone Phone
}

func (d *Decorator) Show() {}


// ----------- 实现层 -----------
// 具体的构件
type HuaWei struct {}

func (hw *HuaWei) Show() {
    fmt.Println("秀出了HuaWei手机")
}

type XiaoMi struct{}

func (xm *XiaoMi) Show() {
    fmt.Println("秀出了XiaoMi手机")
}

// 具体的装饰器类
type MoDecorator struct {
    Decorator   //继承基础装饰器类(主要继承Phone成员属性)
}

func (md *MoDecorator) Show() {
    md.phone.Show() //调用被装饰构件的原方法
    fmt.Println("贴膜的手机") //装饰额外的方法
}

func NewMoDecorator(phone Phone) Phone {
    return &MoDecorator{Decorator{phone}}
}

type KeDecorator struct {
    Decorator   //继承基础装饰器类(主要继承Phone成员属性)
}

func (kd *KeDecorator) Show() {
    kd.phone.Show()
    fmt.Println("手机壳的手机") //装饰额外的方法
}

func NewKeDecorator(phone Phone) Phone {
    return &KeDecorator{Decorator{phone}}
}


// ------------ 业务逻辑层 ---------
func main() {
    var huawei Phone
    huawei = new(HuaWei)
    huawei.Show()    //调用原构件方法

    fmt.Println("---------")
    //用贴膜装饰器装饰,得到新功能构件
    var moHuawei Phone
    moHuawei = NewMoDecorator(huawei) //通过HueWei ---> MoHuaWei
    moHuawei.Show() //调用装饰后新构件的方法

    fmt.Println("---------")
    var keHuawei Phone
    keHuawei = NewKeDecorator(huawei) //通过HueWei ---> KeHuaWei
    keHuawei.Show()

    fmt.Println("---------")
    var keMoHuaWei Phone
    keMoHuaWei = NewMoDecorator(keHuawei) //通过KeHuaWei ---> KeMoHuaWei
    keMoHuaWei.Show()
}

总结

优点

  1. 单例模式提供了对唯一实例的受控访问。
  2. 节约系统资源。由于在系统内存中只存在一个对象

缺点

  1. 扩展略难。单例模式中没有抽象层。
  2. 单例类的职责过重。

适用场景

  1. 系统只需要一个实例对象,如系统要求提供一个唯一的序列号生成器或资源管理器,或者需要考虑资源消耗太大而只允许创建一个对象。
  2. 客户调用类的单个实例只允许使用一个公共访问点,除了该公共访问点,不能通过其他途径访问该实例

代理模式和装饰器模式的区别

  1. 装饰器模式强调的是增强自身,在被装饰之后你能够在被增强的类上使用增强后的功能。增强后你还是你,只不过能力更强了而已;代理模式强调要让别人帮你去做一些本身与你业务没有太多关系的职责(记录日志、设置缓存)。代理模式是为了实现对象的控制,因为被代理的对象往往难以直接获得或者是其内部不想暴露出来。

  2. 装饰模式是以对客户端透明的方式扩展对象的功能,是继承方案的一个替代方案;代理模式则是给一个对象提供一个代理对象,并由代理对象来控制对原有对象的引用;

  3. 装饰模式是为装饰的对象增强功能;而代理模式对代理的对象施加控制,但不对对象本身的功能进行增强;