iOS设计模式

创建型

一、原型模式

  1. 什么是原型模式?
    使用原型实例指定创建对象的种类,并通过复制这个对象创建新的对象。

原型模式其实是通过一个对象为模板创建另外一个可定制的对象,而且不需要知道任何的创建细节。

  1. 什么时候使用原型模式?

    • 需要创建的对象应该独立于其类型和创建方式。
    • 需要实例化的类是在运行时决定的。
    • 不想要与产品层次相对应的工厂层次。
    • 不同类的实例间的差异仅是状态的若干组合。因此复制相应数量的原型比手工实例化更加方便。
    • 类不容易创建,比如每个组件可把其他组件作为子节点的组合对象。复制已有的组合对象并对副本进行修改会更加容易。
  2. 深拷贝与浅拷贝

    • 浅拷贝,指针级拷贝,拷贝出的新实例依旧指向源内存空间,不论修改原来的实例或者拷贝出的实例,都会影响到另一个(因为指针指向同一块内存)。
    • 深拷贝,内存级拷贝,会开辟新的内存空间,修改原来的实例或者拷贝的实例,另一个不受到影响。

    iOS中默认的-copy是浅拷贝,若要深拷贝,需要遵守<NSCopying>协议,重写-copyWithZone方法。

二、简单工厂模式

  1. 什么是简单工厂模式?
    简单工厂模式(Simple Factory Pattern),又称为静态工厂方法(Static Factory Method)模式,在简单工厂模式中,可以根据参数的不同返回不同类的实例。简单工厂模式专门定义一个类来负责创建其他类的实例,被创建的实例通常都具有共同的父类。
  2. 简单工厂模式的优点
    • 将对象的创建和对象本身业务处理分离可以降低系统的耦合度,使得两者修改起来都相对容易。
    • 当你需要什么,只需要传入一个正确的参数,就可以获取你所需要的对象,而无须知道其创建细节。
    • 在调用工厂类的工厂方法时,由于工厂方法是静态方法,使用起来很方便,可通过类名直接调用,而且只需要传入一个简单的参数即可,修改参数时无须修改任何源代码。
  3. 简单工厂模式的缺点
    • 简单工厂模式最大的问题在于工厂类的职责相对过重,增加新的产品需要修改工厂类的判断逻辑,这一点与开闭原则是相违背的。

三、工厂模式

  1. 什么是工厂模式?
    定义创建对象的接口,让子类决定实例化哪一个类。工厂方法使得一个类的实例化延迟到了子类。

  2. 什么时候使用工厂模式?

    • 编译时无法准确预期需要创建对象的类。
    • 类想要其子类决定在运行时创建什么类型的实例。
    • 类有若干辅助类为其子类,而你想将返回哪个子类这种信息局部化。
  3. 工厂模式的优势
    和直接创建具体对象相比,使用工厂方法创建对象算是最佳的做法。
    工厂方法让客户端可以要求由工厂方法创建的对象拥有一组共同的行为。
    因此,向类层次结构中引入新的具体产品并不需要修改客户端代码,因为返回的任何具体对象的接口跟客户端一直使用的接口相同。

  4. Cocoa Touch中的工厂方法
    工厂方法在Cocoa Touch中使用极为广泛,以NSNumber为例,它提供了很多的创建方法,比如-numberWithBool-numberWithInt他们传入不同类型的参数,获得NSNumber实例。

四、抽象工厂

  1. 什么是抽象工厂?
    提供一个创建一系列相关或者相互依赖对象的接口,而无需指定他们的具体类。

    如果有多个类共有相同的行为,但实际实现不同,则可能需要某种抽象类型做为他们的父类,抽取其他们共同的行为到父类中。

    例如,我们知道普通的披萨饼是什么样子,在点餐的时候能预计到端上来的是什么。当我们说"出去吃披萨"时,这里的“披萨”其实就是一个抽象类型,定义了披萨饼应该共同具有的特征。但是,从不同的店我们得到同一披萨饼(比如意大利披萨饼、腊肠披萨饼)的味道大不相同。因为有太多类型的披萨饼,我们简单地将其叫做“披萨饼”以称呼这种特定类型的食品。

    父类的类方法-getFactory仅仅只是返回具体的(合适需求的)工厂类。其子类不应该重载这个方法。-getFactory方法根据配置返回一个具体的工厂实例。Demo

  2. 抽象工厂和工厂模式的比较
    这两者在很多方面都很相似,他们都用于相同的目的:创建对象而不让客户端知晓创建细节,他们的对比如下:

抽象工厂 工厂模式
创建方式 对象组合创建抽象产品 类继承创建抽象产品
创建种类 创建多系列产品 创建一种产品
如何扩展 修改父类的接口才支持新产品 子类创建者重载工厂方法以创建新的产品

五、建造者(生成器)模式

  1. 什么是建造者模式 将一个复杂对象的构建与他的表现分离,使得同样的构建过程可以创建不同的表现。

    它可以将一个产品的内部表象与产品的生成过程分割开来,从而可以使一个建造过程生成具有不同内部表象的产品对象。
    如果我们用了建造者模式,那么用户只需要指定需要建造的类型就可以得到他们的对象实例,而无需关心建造过程和细节。

    在此模式中,除了用户和其所需的产品,还有两个重要的角色Director(指导者)Builder(生成器)

    • Director知道Builder应该建造什么,以参数向其提供缺少的信息来创建特定产品。
    • Builder是一个抽象接口,声明了一个-build方法,该方法由ConcreBuilder实现,以构造实际的产品,ConcreBuilder有一个-getResult方法,向客户端返回建造完毕的结果。
  2. 何时使用建造者模式

    • 需要创建涉及各种部件的复杂对象。创建对象的算法应该独立于部件的装配方式。常见例子是构建组合对象。
    • 构建过程需要以不同的方式(比如,部件或者表现不同的组合)构建对象。
  3. 建造者模式和抽象工厂的对比
    抽象工厂和建造者模式在 抽象对象创建方有许多相似之处,但是,二者却大不相同。

    • 建造者模式关注的是分步骤创建复杂对象,很多时候,同一类型的对象可以以不同的方式创建。建造者模式在多步创建过程的最后一步返回产品。
    • 抽象工厂的重点在于创建简单或者复杂产品的套件。抽象工厂立即返回产品。
    建造者模式 抽象工厂
    象的复杂程度 构建复杂对象
    需要的步骤 多步创建
    创建方式种类 多种方式创建
    返回对象的时机 创建过程的最后一步
    创建结果 专注一个特定的产品
  4. 总结
    生成器模式能帮助构建涉及部件与表现的各种组合的对象。没有这一模式,知道构建对象所需细节的Director可能会最终变成一个极其复杂的类。带有无数用于构建同一类的各种表现的内嵌算法。而这些算法本应该独立于该对象的组成部分以及他们的装配过程。

六、单例模式

  1. 何为单例模式

    单例模式:保证一个类仅有一个实例,并且提供一个访问它的全局访问点。

    单例模式几乎是设计模式中最简单的了。它的意图是使得类的一个对象成为系统中的唯一实例。要实现这一点,可以从客户端对其进行实例化开始。因此,需要用一种只允许生成对象类唯一实例的机制来“阻止”所有想要生成对象的访问。

  2. 何时使用单例模式

    • 类只能有一个实例,而且必须从一个为人熟知的访问点对其进行访问,(比如工厂方法)。
    • 这个唯一的实例只能通过子类化进行扩展,而且扩展的对象不会破话客户端代码。
  3. Objective-C实现单例模式
    在OC中,单例模式的实现目前分为两种:Demo

    • 原始实现
      遵守<NSCopying>协议重写-alloc方法和-copy方法,考虑线程安全。
    • GCD实现
      借助GCD的dispatch_once实现

接口适配

七、适配器

  1. 何为适配器模式

    适配器模式,用于连接两种不同种类的对象,使其毫无问题地协同工作。其思想比较简单:适配器实现客户端所需要的某种接口的行为,同时,它又连接到一个具有(完全)不同接口行为的对象。一边是客户端懂得如何使用的目标接口,另一边是客户端一无所知的被适配者,适配器在二者之间。它的主要作用是把被适配者的行为传递给管道另一端的客户端。

    定义:将一个类的接口转换成客户希望的另外一个接口。Adapter模式使得原本接口不兼容而不能在一起工作的类可以一起工作了。

  2. 适配器分类

    • 类适配器
      它是通过类继承实现的,而Objective-C有着协议(Protocol)这一语言特性,所以在Objective-C中,类可以实现协议,同时又继承自父类,从而达到C++中多继承的效果。
      要在OC中实现类适配器,首先需要有定义了客户端要使用的一套行为的协议,然后用具体的适配器类来实现这个协议,适配器类同时也继承被适配者。

    • 对象适配器
      与上面的类适配器不同,对象适配器不继承被适配者,而是组合了一个对他的引用。

  3. 类适配器与对象适配器的比较

    类适配器 对象适配器
    只针对单一具体的Adaptee类,把Adaptee适配到target 可以适配多个Adaptee及子类
    易于重载Adaptee的行为,以为是通过直接的子类化进行的适配 难以重载,需要借助子类的对象而非Adaptee本身
    只有一个Adaptee对象,无需额外的这镇间接访问Adaptee 需要额外的指针间接访问Adaptee并适配其行为

    Adaptee:被适配者
    Target:目标接口

  4. 何时使用适配器模式

    • 已有类的接口与需求不匹配
    • 想要一个可复用的类,该类能够同可能带有不兼容接口的其他类协作。
    • 需要适配一个类的几个不同子类,可是让每一个子类去子类化一个类适配又不现实,那么可以使用对象适配器(委托)来适配其父类的接口。

八、桥接模式

  1. 何为桥接模式?
    将抽象部分与它的实现部分分离,使它们都可以独立地变化。

    所谓抽象与它的实现分离,这并不是说,让抽象类与其派生类分离,因为这没有任何意义。实现指的是抽象类和它的派生类用来实现自己的对象。

    实现系统时可能有多角度分类,每一种分类都有可能变化,那么就把这种多角度分离出来,让他们独立变化,减少他们之间的耦合。

  2. 合成/聚合复用原则

    • 继承的弊端
      对象的继承关系在编译时就已经定好了,所以无法在运行时改变从父类继承的实现。子类的实现与其父类有着非常紧密的依赖关系,以至于父类实现中任何变化必然会导致子类发生变化。当需要复用子类时,如果继承下来的实现不适合新的问题,则父类必须重写或者被其他更适合的类替换。这种依赖关系限制了灵活性并最终限制了复用性。

    • 合成/聚合复用原则
      合成(也叫做组合,Composition)和聚合(Aggregation)都是关联的特殊种类。聚合表示一种弱的“拥有“关系,体现的是A对象可以包含B对象,但B对象不是A对象的一部分;合成则是一种强的”拥有“关系,体现了严格的部分和整体的关系,部分和整体的生命周期一样。

      比如:大雁有两个翅膀,翅膀与大雁是部分和整体的关系,并且他们的生命周期相同,于是大雁和翅膀就是合成关系。大雁是群居动物,每只大雁都属于一个雁群,一个雁群可以有多只大雁,所以,大雁和雁群是聚合关系。

    优先使用对象的组合/聚合将有助于保持每个类被封装,并集中在单个任务上。这样类和类继承层次会保持较小规模,并且不太可能增长为不可控制的庞然大物。

  3. 何时使用桥接模式

    • 不想在抽象与实现之间形成固定的绑定关系(这样可以在运行时按需切换实现)
    • 抽象及其实现都应可以通过子类化独立扩展。
    • 对抽象的实现进行修改不应该影响客户端代码。
    • 如果每个实现需要额外的子类以细化抽象,则说明有必要把他们分成两个部分。
    • 想在带有不同抽象接口的多个对象之间共享一个实现。

桥接模式Demo

猜你喜欢

转载自juejin.im/post/5c1663fee51d4570915006c2