前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >设计模式 -- 装饰模式

设计模式 -- 装饰模式

作者头像
xy_ss
发布2023-11-22 09:26:11
1450
发布2023-11-22 09:26:11
举报
文章被收录于专栏:浮躁的喧嚣浮躁的喧嚣

场景

现需要定制几个品牌的手机,如iPhone、xiaomi、huawei等,根据其功能不同进行定制,再不断的迭代中手机功能需要不停的升级

实例类图

问题来了

  • 系统扩展麻烦。如果用户需要一个既能打游戏又有导航的手机,在图中通过增加了一个新的类PlayGameAndMapiPhone来实现,该类既作为PlayGamePhone的子类,又作为MapPhone的子类;但现在很多面向对象编程语言,如iOS、Java等都不支持多重类继承,因此在这些语言中无法通过继承来实现对来自多个父类的方法的重用。此外,如果还需要扩展一项功能,例如增加一个听音乐的功能,它是iPhone(Xiaomi、HUAWEI)类的子类,现在需要一个同时拥有三项功能(打游戏、导航、听音乐)的手机,必须再增加一个类作为三个类的子类,这同样在iOS等语言中无法实现
  • 代码重复。如类图,不只是iPhone支持打游戏功能,xiaomi、huawei都需要,该方法具体实现基本相同,代码重复
  • 系统庞大,类的数目非常多。如果增加新的功能系统都需要增加大量的具体类,这将导致系统变得非常庞大

问题改进 根本原因在于复用机制的不合理,根据“合成复用原则”,在实现功能复用时,我们要多用关联,少用继承,因此我们可以换个角度来考虑,将PlayGame()方法抽取出来,封装在一个独立的类中,在这个类中定义一个Component类型的对象,通过调用Component的display()方法来显示最基本的构件,同时再通过setScrollBar()方法对基本构件的功能进行增强

表述 (结构型模式)

动态地给一个对象添加一些额外的职责,就扩展功能来说,装饰模式比生成子类更加灵活

装饰模式类图

组合模式类图

  • Component(抽象构件):定义一个对象接口,可以给这些对象动态添加职责
  • ConcreteComponent(具体构件):定义一个具体对象,可以给这个对象添加一些职责
  • Decorator (抽象装饰类):装饰抽象类,继承Component,从外类来扩展Component类的功能,但是对于Component来说,是无需知道Decorator存在的
  • ConcreteDecoratorA 和 ConcreteDecoratorB(具体装饰类):具体的装饰对象,起到给Component添加职责的功能

优点

  • 对于扩展一个对象的功能,装饰模式比继承更加灵活性,不会导致类的个数急剧增加
  • 可以通过一种动态的方式来扩展一个对象的功能,通过配置文件可以在运行时选择不同的具体装饰类,从而实现不同的行为
  • 可以对一个对象进行多次装饰,通过使用不同的具体装饰类以及这些装饰类的排列组合,可以创造出很多不同行为的组合,得到功能更为强大的对象
  • 具体构件类与具体装饰类可以独立变化,用户可以根据需要增加新的具体构件类和具体装饰类,原有类库代码无须改变,符合“开闭原则”

缺点

使用装饰模式进行系统设计时将产生很多小对象,这些对象的区别在于它们之间相互连接的方式有所不同,而不是它们的类或者属性值有所不同,大量小对象的产生势必会占用更多的系统资源,在一定程序上影响程序的性能

使用场景

  • 在不影响其他对象的情况下,以动态、透明的方式给单个对象添加职责
  • 对类的职责的扩展是可选的

注意事项

  • 尽量保持装饰类的接口与被装饰类的接口相同,这样,对于客户端而言,无论是装饰之前的对象还是装饰之后的对象都可以一致对待
  • 尽量保持具体构件类ConcreteComponent是一个“轻”类,也就是说不要把太多的行为放在具体构件类中,我们可以通过装饰类对其进行扩展

示例

需求V1:现需要定制几个品牌的手机,如iPhone、xiaomi、huawei等,根据其功能不同进行定制,再不断的迭代中手机功能需要不停的升级

构建类

代码语言:javascript
复制
//抽象构件,可以给这些对象动态添加方法
class Phone {
    func supportFunctions() {
        
    }
}

//具体构件类,也可以给这个对象添加方法
class iPhone : Phone {
    var name : String
    init(name:String) {
        self.name = name
    }
    override func supportFunctions() {
        print("\(self.name)支持以上功能")
    }
}
//具体构件类,也可以给这个对象添加方法
class Xiaomi : Phone {
    var name : String
    init(name:String) {
        self.name = name
    }
    override func supportFunctions() {
        print("\(self.name)支持以上功能")
    }
}

装饰类

代码语言:javascript
复制
//抽象装饰类,继承Phone从外类来扩展Phone类的功能,但是对于Phone来说,是无需知道PhoneDecorator的存在的
class PhoneDecorator : Phone {
    var phone : Phone
    init(phone:Phone) {
        self.phone = phone
    }
    override func supportFunctions() {
        self.phone.supportFunctions()
    }
}

//具体的装饰对象,起到给Phone类添加技能的方法
class PlayGame: PhoneDecorator {
    override func supportFunctions() {
        self.playGame()
        super.supportFunctions()
    }
    func playGame() {
        print("打游戏")
    }
}

//具体的装饰对象,起到给Phone类添加技能的方法
class Map : PhoneDecorator{
    override func supportFunctions() {
        self.map()
        super.supportFunctions()
    }
    func map() {
        print("导航")
    }
}

客户端

代码语言:javascript
复制
let iphone = iPhone.init(name: "apple")
let playGamePhone = PlayGame.init(phone: iphone)
let mapPhone = Map.init(phone: playGamePhone)
mapPhone.supportFunctions()

let xiaomi = Xiaomi.init(name: "xiaomi")
let mapXiaomi = Map.init(phone: xiaomi)
mapXiaomi.supportFunctions()

log:
//导航
//打游戏
//apple支持以上功能
//导航
//xiaomi支持以上功能

需求V2:再原有基础上,支持音乐播放功能

只需创建PlayMusic继承PhoneDecorator,客户端直接调用便可

代码语言:javascript
复制
class PlayMusic : PhoneDecorator {
    override func supportFunctions() {
        self.playMusic()
        super.supportFunctions()
    }
    func playMusic() {
        print("音乐播放")
    }
}

客户端

代码语言:javascript
复制
let xiaomi = Xiaomi.init(name: "xiaomi")
let mapXiaomi = Map.init(phone: xiaomi)
let playMusic = PlayMusic.init(phone: mapXiaomi)
playMusic.supportFunctions()

log
//音乐播放
//导航
//xiaomi支持以上功能
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2019-10-16,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 场景
  • 表述 (结构型模式)
  • 装饰模式类图
  • 优点
  • 缺点
  • 使用场景
  • 注意事项
  • 示例
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档