设计模式之结构型模式(下)

上篇已经介绍了适配器模式、桥接模式和组合模式,这篇将介绍装饰者模式、外观模式、享元模式和代理模式。

装饰者(Decorator)

装饰者模式可以动态地给一个对象添加一些额外的职责。

举个例子,我们要给UIView及其子类创建一个装饰者,在调用addSubview方法的时候打印一条调试信息:

class LogDecorator: UIView {
    var view: UIView
    
    init(frame: CGRect, view: UIView) {
        self.view = view
        super.init(frame: frame)
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    override func addSubview(view: UIView) {
        self.view.addSubview(view)
        log()
    }
    
    func log() {
        // ...
        print("Add a subview.")
    }
}

LogDecorator继承自UIView,在能够使用UIView的地方也同样可以使用LogDecorator。这个装饰者可以用来装饰UIView及其所有子类,譬如装饰一个 Button:

let button = LogDecorator(frame: frame, view: UIButton())
button.addSubview(UIView())

//打印信息
Add a subview.

装饰者模式跟对象适配器模式很像,但是装饰者跟被装饰者必须是继承自同一个抽象类的,对外提供一致的接口;而适配器跟被适配者却没有这个限制。虽然适配器也可以给被适配者增加新的职责,扩展它的功能,但是它们的目的是不同的,前者是为了动态地给某个对象增添新功能,而后者则是为了包装已有对象,对外提供符合需求的接口。

外观(Facade)

外观模式为子系统中的一组接口提供一个一致的界面。

这个呢其实没什么可多说的,无非是新建一个类用作用户界面,将一个复杂子系统中的类组合起来,对外提供一个易用的高层接口,隐藏内部细节。这里蕴含分层的思想,可以让系统模块化程度更高,便于复用,也便于使用。

享元(Flyweight)

享元模式运用共享技术有效地支持大量细粒度的对象。

Flyweight 是一个共享对象,它包含内部状态和外部状态,内部状态是那些可以用来共享的状态,而外部状态则是需要根据不同场景进行计算得到的状态。

有些做 iOS 开发的同学可能对享元模式这个名字比较陌生,但其实我们几乎天天都要跟它打交道。比如 TableView 和 CollectionView 中 Cell 的重用机制,就是运用享元模式的一大典范。Cell 对象就是一个 Flyweight,Cell 包含的那些 Subview(以及Subview 的位置大小颜色等信息)都是内部状态,而 Cell 的高度、要显示的内容等等,这些都是外部状态,是需要在 Cell 显示之前计算得到的。说到这里想必大家也明白享元模式的作用了,对的,就是为了节约内存。

代理(Proxy)

代理模式为其他对象提供一种代理以控制对这个对象的访问

代理模式在形式上其实跟装饰者模式是差不多的,代理者跟实际对象都继承自同一个抽象类,代理者持有一个指向实际对象的指针。使用时可以用代理对象代替实际对象,代理对象控制对实际对象的存取,并可能负责创建和删除它,其他附加功能根据代理的类型而有所不同。

代理一般分为以下几种类型:

  • 远程代理(Remote Proxy):负责对请求及其参数进行编码,并向不同地址空间的实体对象发送已编码的请求。
  • 虚代理(Virtual Proxy):缓存实体的附加信息,实现延迟加载(Lazy Load)等功能。
  • 保护代理(Protection Proxy):检查调用者是否拥有对实体的访问权限,并分情况进行处理。
  • 智能指引(Smart Reference):取代简单的指针,在访问对象时执行一些附加操作(控制引用计数、首次加载持久对象、加锁保证线程安全等)。

由此可见,iOS 开发中无处不在的 Delegate(委托)其实跟代理模式是有区别的,委托对象跟实际对象并没有一致的接口,只是在某些特定的时间节点调用委托对象中的方法(一般以对应实际对象为参数),从而对实际对象进行操作。

小结

到此为止结构型模式就介绍完了,想必大家也发现了,其实绕来绕去就是类继承跟对象组合罢了,只是因为设计目的不同以及一些实现上的细微差别,才分出了这么多模式。

设计模式就像公式定理,你可以把它背下来,这样在跟人交流或者阅读别人的系统的时候,会少很多障碍。但比公式更重要的是推导过程,对应到日常开发中就是系统设计能力。套用公式并不能解决所有问题,所以大家在学习设计模式的时候还是要多学习它的设计思路,知道每个模式是针对什么场景设计的,这样设计的好处与弊端,它具体是怎么实现的,场景变化的时候可以做怎样的变通,等等。只有这样,你才能真正从设计模式中受益。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,793评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,567评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,342评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,825评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,814评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,680评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,033评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,687评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,175评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,668评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,775评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,419评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,020评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,978评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,206评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,092评论 2 351
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,510评论 2 343

推荐阅读更多精彩内容