专栏首页我杨某人的青春满是悔恨设计模式之结构型模式(下)

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

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

装饰者(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(委托)其实跟代理模式是有区别的,委托对象跟实际对象并没有一致的接口,只是在某些特定的时间节点调用委托对象中的方法(一般以对应实际对象为参数),从而对实际对象进行操作。

小结

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

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

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 动手写个 JSON-Model Mapping 库

    Swift 在 JSON解析方面有个比较有名的第三方库——SwiftyJSON,之前我也一直用的它。虽然用着还不错,但是它主要是为了避免手动解析 JSON 数据...

    Sheepy
  • Swift2网络操作和异常处理

    相信写过Swift的人应该都知道Alamofire,它是AFNetworking的Swift版本,同一个作者写的。之前在项目中我也一直使用Alamofire,但...

    Sheepy
  • 狼人杀入坑指南

    之前在年终总结里说 2017 年可能要退出搜车狼人杀 club 了,想想就这么净身出户还是有些遗憾,不如就把这两个月的游戏心得总结一下。当然我自己也是个业余选...

    Sheepy
  • 20W+喜爱的Pathview网页版 | 整合表达谱数据KEGG通路可视化

    前段时间介绍了一个R包 — Pathview。它可以整合表达谱数据并可视化KEGG通路,操作是先自动下载KEGG官网上的通路图,然后整合输入数据对通路图进行再次...

    生信宝典
  • 麦子陪你做作业(二):KEGG通路数据库的正确打开姿势

    KEGG是通路数据库中最庞大的,涵盖基因组网络信息,主要注释基因的功能和调控关系。当我们选到了合适的候选分子,单变量研究也已做完,接着研究机制的时便可使用到它。...

    企鹅号小编
  • NeurIPS 2018开锣,中国论文数全球第二!清华、中科院、北大排前三

    神经信息处理系统大会(原名 Neural Information Processing Systems,NeurIPS)是人工智能和机器学习领域最重要的盛会,自...

    新智元
  • 麦子陪你做作业(二):KEGG通路数据库的正确打开姿势

    KEGG是通路数据库中最庞大的,涵盖基因组网络信息,主要注释基因的功能和调控关系。当我们选到了合适的候选分子,单变量研究也已做完,接着研究机制的时便可使用到它。...

    企鹅号小编
  • 持续交付的商业价值

    对企业来说,这些价值一起使持续交付成为真正的游戏变革者。尽管可以在团队或项目级别开始采用和验证,但持续交付的本质是它以需要真正投资和自上而下承诺的方式跨越了组织...

    LinuxSuRen
  • kmeans聚类理论篇K的选择(轮廓系数)

    kmeans是最简单的聚类算法之一,但是运用十分广泛。最近在工作中也经常遇到这个算法。kmeans一般在数据分析前期使用,选取适当的k,将数据分类后,然后分类...

    机器学习AI算法工程
  • R语言的kmeans客户细分模型聚类

    前言 kmeans是最简单的聚类算法之一,但是运用十分广泛。最近在工作中也经常遇到这个算法。kmeans一般在数据分析前期使用,选取适当的k,将数据分类后,然后...

    CDA数据分析师

扫码关注云+社区

领取腾讯云代金券