iOS设计模式(一)-认识设计模式

设计模式名称解释

  • 设计模式是为特定场景下的问题制定的解决方案
    • 特定场景:问题重复出现的场景
    • 问题:开发中常见的,似曾相识的问题
    • 设计模式:对上诉问题的分类,并提出解决方案;是面向对象软件开发的经验总结.
    • 面相对像软件开发的设计目标是:高内聚,低耦合

设计模式的作用

  • 设计模式是经时间证明有效的,对特定面向对象设计问题主要方面的一种抽象,体现了面向对象设计的重要思想.
  • 面向对象软件开发的原则是构建可复用/可维护的面向对象应用程序,这些设计原则影响着设计模式
  • 如果在设计中使用了设计模式,将来就更易于复用与扩展,更易于变更
  • 基于设计模式的程序会变得更加简洁而高效,因为达成同样目标的所需的代码会更少
  • 设计模式对于可复用软件的编写非常重要

列如,通过给程序的变动部分定义接口而对其封装和隔离,这些部分的变动就独立于程序的其他部分,因为它们不依赖于任何细节.以后就可以变更或扩展这些可变的部分而不影响程序的其他部分. 程序将因此能够更灵活而可靠地进行变更,因为我们消除了部分与部分之间的依赖关系并减少了耦合.

iOS中的基础设计模式MVC

起源

  • 模型-视图-控制器(MVC)设计模式及其变体至少在Smalltalk诞生初期就已经出现了. 这个设计模式是Cocoa Touch中很多机制和技术的基础.
  • MVC模式定义了对象之间跨越角色的抽象边界的通信方式,应用程序设计的一个主要步骤就是决定对象或类应该属于(M,V,C)这三组中哪一组
  • MVC模式本身不是独立的模式,而是由几个其他基本模式组成的复合设计模式
  • MVC模式的程序更易于扩展和复用,因为其接口通常会定义的很好

M-模型:封装数据和基本行为

  • 模型对象维护应用的程序的数据,并定义操作数据的特定逻辑.
  • 模型对象可以复用,因为它表示的信息适用于特定的问题领域-模型对象可以表示复杂的数据的结构,对应于用户在屏幕上所画的图形,或者仅仅表示待办事项应用程序中的一条待办事项.
  • 只要加载的是包含有应用程序永久信息的数据,就应该将其放入模型对象.
  • 模型对象在理想状态下是不应该和View有任何直接联系的

V-视图:向用户展示信息(M)

  • 视图对象可以响应用户操作,并懂得如何将自己展现在屏幕上.
  • 虽然视图对象和模型对象之间关系密切,但是在MVC应用程序中他们之间没有耦合,除非因为性能原因(比如视图需要对数据进行缓存)
  • 视图对象可以与许多不同的模型对象合作,所以视图类可以在不同的地方复用并保持一致.UIKit提供了各种视图类,可复用于我们的App.

C-控制器:联系其模型和视图

  • 控制器对象就像视图对象和模型对象的中间人. 作为中间人或者协调人,它建立起沟通的渠道,使视图得以知晓模型的变更而给予响应.
  • 控制器还可以执行其他操作,比如管理其他对象的生命周期,进行设置和协调

复合设计模式MVC:由其他设计模式组合而成

  • 在MVC中,基本设计模式相互配合,确定了各功能之间的写作,这是MVC应用程序的特性.
  • Cocoa中MVC用到的模式有:组合(Composite),命令(Command),中介者(Mediator),策略(Strategy)和观察者(Observer)
  • 组合-视图对象之间可以协作的方式构成一个视图层次体系,其中既可以有复合视图(比如表格视图), 也可以有独立视图(比如文本框或者按钮). 每个层次的每个视图节点都可以响应用户的操作并把自己绘制到屏幕上.
  • 命令-这是一种"目标-动作"机制,视图对象可以推迟其他对象(比如控制器)的执行, 让其他对象等到发生了某些事件后再执行. 这一机制构成了命令模式.
  • 中介者-控制器对象起了中间人的作用,而这个中间人则采用了中介者模式,它构成了在模型和视图对象之间的传递数据的双向通道. 应用程序的控制器对象将模型的变更传达给视图对象.
  • 策略-控制器可以是视图对象的一个'策略'. 视图对象将自身隔离,以期维持其作为数据展示器的唯一职责,而将一切应用程序特有的界面行为的决定委派给它的'策略'对象
  • 观察者-模型对象向它所关注的控制器等对象发出内部状态的变化通知

图1-1展示了虚构场景下的这些模式是如何协同工作的


图1-1虚构场景下的这些模式是如何协同工作的

iOS中的一些设计原则

针对接口编程,而不是针对实现编程

  • 关注点在于接口(Interface)和类(Class)的设计,而不是沉迷于功能的实现
  • 具体的做法是:客户端(在你设计的类的调用端)代码中不声明特定具体类的变量,而只使用协议或抽象类定义的接口,这种思想非常重要是对设计模式的一种规律总结
  • 这是由Gof提出的面向对象软件设计原则
  • 类继承和接口继承(subtyping)的区别
    • 接口定义了某种合约,是比类型Class更高的抽象,接口的继承(subtyping)可以让一个对象被另一个对象代替.
    • 类继承是通过复用父类的功能或者简单地共享代码和表述,来定义对象的实现和类型的一种机制
  • 定义具有相同接口的类群很重要,因为多态是基于接口的.
    • OC中通过实现协议(protocol)使得对象共享相同的借口
    • 子类型的所有对象都可以针对协议或者抽象类的接口的请求作出应答,体现了多态
  • 面向接口编程的好处
    • 只要对象符合客户端所要求的接口,客户端就不必在意所使用对象的确切类型
    • 客户端只知道定义接口的协议或者抽象类,因此客户端对对象的类一无所知(低耦合)

协议(protocol)和抽象基类

定义

  • 协议是只定义了抽象行为的"接口",实现协议的类定义了这些方法的实现以执行真正的操作.
  • 通过定义抽象基类,可以生成一些其他子类可以共享的默认行为.抽象基类与通常的类相似,只是预留了一些可以或应该由子类重载的行为

区别

  • 变更定义好了的协议,所有相关的类都需要变更,唯一的例外是使用@optional标识部分方法
  • 抽象基类在变更接口方面要灵活点,我们可以向抽象基类中随意追加新的方法,而不会破坏继承链的其他部分.而且对于子类可能用到的占位方法(stubbed-out method,那些需要被重载的方法)中定义的默认行为,我们可以随意地进行追加/删除或分解

对象组合和类继承

类继承或者子类化可以使得用其他的类来定义新类的实现. 子类化常被称为白箱复用(white-box reuse),因为父类的内部描述与细节通常对子类是可见的.
对象组合可以代替类继承.对象组合要求被组合的对象具有定义良好的接口,并且通过从其他对象得到引用在运行时动态定义.对象组合可以构建更加复杂的功能,对象组合是黑箱复用(black-box reuse)

类继承的优缺点
优点:

  • 类继承简单直接,因为关系在编译时静态定义;
  • 被复用的实现易于修改

缺点:

  • 因为类继承在编译时定义,所以无法在运行时变更从父类继承来的实现
  • 子类的部分描述常常定义在父类中
  • 子类直接面对父类实现细节,因此破坏了封装
  • 父类实现的任何变更都会强制子类也进行变更,因为它们的实现联系在了一起
  • 因为新的问题场景下,继承来的实现已过时或不适用,所以必须重写父类或继承来的实现

由于类继承中类的实现依存关系,对子类进行复用可能会有问题.有个解决办法是:只从协议或抽象基类继承,因为它们只有很少的实现,而协议则没有实现

对象组合优缺点
对象组合让我们同时使用多个对象,而每个对象都是假定其他对象的接口正常运行.因此为了在系统中正常运行,它们的接口都需要经过精心的设计.

优点:

  • 不会破坏封装性,因为只通过接口来访问对象
  • 大大减少实现的依存关系,因为对象的实现是通过接口来定义
  • 可以在运行时将任意对象替换为其他同类型的对象
  • 有助于保持类的封装以专注于单一任务
  • 类及其层次结构能保持简洁,不至于过度膨胀而无法管理

缺点:

  • 设计中涉及较多的对象
  • 系统的行为将依赖于不同对象间的关系,而不是定义于单个类中
  • 理想情况下,不需要创建新的组件就能实现复用,很少能通过对象组合,仅仅对已有的组件组合就能得到所需的全部功能,实际中,现成的组件总是不够用

尽管对象组合缺点很多,但对象组合仍能带来许多好处.我们可以通过在某些部分使用类继承来克服这些去缺点,使得利用已有组件创建新的组件较为容易

优先使用对象组合而不是类继承

  • 并不是说完成不使用类继承,需要根据具体情况对如何复用类和对象作出清晰的判断
  • 在设计时,通常倾向于考虑对象组合,然后寻找出冗余行为,进行设计细化.如果找到冗余行为,也许意味着此处应该使用类继承.
  • 通常在设计系统时,类继承和对象组合可以相互配合
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容