目录
MVC/MVP/MVVM
MVC
介绍
将应用的 数据(Model)、界面(View) 和 业务逻辑/协调(Controller) 分离开来,从而降低耦合度
主要内容
Model(模型层)主要负责 数据承接 和 数据处理
View(视图层)负责显示数据和与用户进行交互,不关心数据来源。
Controller(控制器层):将model传递给view显示,处理view的用户交互事件,网络请求和业务逻辑。
好处
分层清晰,职责明确
天然适配UIKit,UIKit的设计思想就是mvc
坏处
当业务逻辑过多或UI较复杂时,大量的业务代码和UI更新代码会导致控制器会过大,形成巨型控制器。
解决思路: 使用 MVP、MVVM
MVP
介绍
MVP 是对 MVC 的改进,它的主要目的是 解决巨型控制器问题
主要内容
Model:数据承接 和 数据处理
View:将view和vc都看做view,把vc中业务逻辑和网络请求逻辑抽出,只保留UI相关的逻辑,完成瘦身。
Presenter:将抽出的业务逻辑和网络请求逻辑放到p层,当业务处理完成之后,调用view层对外提供的接口进行UI刷新
如果我们将view层的更新UI的相关接口,抽成一个协议,那么凡是实现了这个协议的view,都可以使用我们这个presenter进行更新,
那么一个presenter就可以对应多个不同样式的View,当app的页面改版的时候,我们的presenter就不用动
好处
P层是非ui相关的,便于复用和单元测试
App改版的时候,p层不需要改动,只要实现一套新的UI即可
坏处
UI更新需要手动进行
控制器扔不够精简
MVVM
介绍
MVVM 是对 MVP 的进一步演进。
主要内容
Model的职责不变跟mvp一样
View的职责也不变
ViewModel的职责也是处理业务逻辑和网络请求逻辑。只是在这个基础上增加一个数据绑定的逻辑,当viewmodel里的数据发生变化时,自动更新UI。
自动更新UI的逻辑可以通过kvo、block、代理等方式进行实现。
举个例子,比如viewmodel里有一个userName的属性,和一个userNameChange回调,在userName的set方法里调用这个回调
我们在view里持有viewmodel对象,并且通过viewModel.userNameChange传入回调的具体实现。当userName发生变化时,就会自动触发更新
好处
去除了复杂的手动更新逻辑
因为去除了UI更新的代码,进一步减少了vc的大小。
坏处
使程序设计过于复杂,不适用于简单业务
适配器模式
案例
设备管理类deviceManager的优化
主要内容
之前在做手环APP的时候我们也进行过一次代码优化。
在手环APP内有一个deviceManager的管理类。这个类有几个主要的职责:
1、负责手环的扫描、连接、断开自动重连。
2、负责手环基础数据的读取,比如闹钟数据、运动数据、睡眠数据,固件的下载更新。
3、负责交通卡的下发和刷卡逻辑。
4、负责银联卡的下发开发和支付逻辑。
我接手的时候已经有两个类型的手环,因为不同的手环由不同的生产商提供,配套不同的sdk。
所以SDK提供的接口签名不同,数据model也不相同,而且各自厂商都有自己的代理方法要实现,有的还有重名。
deviceManager类里边有大量的类型判断,// 然后手环读取数据的时候还不能并行,然后马上要接入第三款手环。
所以就对deviceManager这个类进行了优化
保留了跟厂商无关的扫描、连接、断开自动重连的逻辑。
然后把其余的deviceManager对外提供的方法接口,抽成一个Adapter协议。
然后创建三个不同的deviceAdapter类对应三个不同的厂商,遵守并实现协议。
比如手环的型号叫A、B、C,
在A_deviceAdapter里边我们只用调用A的方法接口,
获取到数据之后转换为对外提供的数据model结构
然后代理方法的实现也只在当前的AdeviceAdapter里边处理。
deviceManager类里边只需要持有一个遵守Adapter协议的delegate指针,
当手环连接成功之后,根据手环的型号初始化对应的deviceAdapter实例。
好处
1、对使用deviceManager的地方,不用做改动,因为方法签名没变
2、再接入新类型的手环的时候,只需要创建一个对应的deviceAdapter类就行
3、在调用delegate指针真正干事之前,我们可以对传入的参数进行统一校验,去掉一些非法参数或者添加权限校验限制某些功能的使用。
装饰器模式
介绍
装饰器模式:在不改变原有对象的基础上,动态的给对象添加功能
案例
大方电子名片
主要内容
我们有一个电子名片的功能,电子名片可以分享也可以保存到本地
电子名片的图片生成通过一个工具类叫ImageTool,中的getImageFromView方法,它负责将view转化为图片对象,然后用于保存或者分享
现在想将保存或者分享的图片加上方正证券的水印。
就可以使用装饰器模式
创建一个类ImageToolDecorator,它初始化的时候传入一个ImageTool对象,然后添加一个getImageFromView方法,这个方法保持跟ImageTool中的方法签名一致。
在这个方法内,调用imageTool 的 getImageFromView方法获取到图片,然后将图片和水印绘制到一块生成一个新的图片对象返回
然后在使用图片的地方,初始化一个imageToolDecorator对象,然后将[imageToo getImageFromView]修改为[imageToolDecorator getImageFromView]
好处
1、不需要通过创建子类给对象添加功能
2、后续添加别的功能时,可以叠加调用。如果使用创建子类的方式会面临类爆炸问题
坏处
调试不方便
中介者模式
介绍
中介者模式:用一个中介对象封装一系列的对象交互,减少类之间的耦合度。
案例
登录页面
主要内容
比如登录页面,有三个输入框,账号、密码、验证码 和一个登录按钮。当任意一个输入框为空时登录按钮不可用。
有一种写法是,在每一个输入框的输入回调里都要写这样的代码:先判断自己的输入框是否为空,再查看另外两个输入框是否为空,然后根据情况修改登录按钮的状态。
这样代码很多而且很乱,如果再增加一个短信验证码会更乱。
另外一个写法是使用中介者模式,我们在vc里边定义一个textChange方法,每个输入框的回调都调用这个方法,在这个方法里判断所有的输入框都不为空时按钮可用。
这样再增加新的输入框,代码改动也很小。如果觉得vc里代码太多,可以抽出一个单独的loginManager类来作为中介者
代理模式
案例
tableview和京东的折线图
主要内容
一个对象把想干的事情,交给另一个对象去干
在iOS开发中UITableview就是代理模式的典型应用
Tableview是被代理的对象,vc是代理对象,它实现了代理协议是真正干事的,比如cell的点击事件
好处
一个是解耦,tableview不需要知道vc的具体实现,
另外一个是可扩展,不同的代理可以实现不同的行为
京东金融的折现图,就是仿照tabview的代理模式进行封装的,设计了两个协议一个dataSource,一个delegate。
dataSource用来提供展示的数据,delegate用来处理事件
根据这个思路,我们可以想一下平时在封装一个view的时候,数据都是在构建或者初始化的时候传递进去的。
那么现在我们也可以通过协议去提供数据
工厂模式
案例
UIButton的创建
行者常至,为者常成!