设计模式 结合Alamofire
单例模式
保证一个类仅有一个实例。
单例一旦创建,对象指针保存在静态区,单例对象在堆中分配的内存空间只有等程序结束才能释放,所以过多的单例会增大内存的小号。如果不是应用程序的生命周期短,就不应该使用单例。一般是伴随着程序的出生和结束的,所以一般使用单例模式来封装网络请求。
public let AF = Session.default
网络状态监听管理器
public static let `default` = NetworkReachabilityManager()
public static let `default`: HTTPHeaders = [.defaultAcceptEncoding,
.defaultAcceptLanguage,
.defaultUserAgent]
适配器模式
类适配器中适配器继承于被适配者,适配器方法中调用父类的方法进行适配
监听请求的整体流程,EventMonitor统一对外回调我们关心的接口,只需要继承EventMonitor,调用里面的函数接口,不需要知道代码的实现逻辑
class GitNetworkLogger: EventMonitor {
/// 请求完成,开始解析响应数据
func requestDidFinish(_ request: Request) {
print(request.description)
}
}
let networkLogger = GitNetworkLogger()
return Session(
configuration: configuration,
interceptor: interceptor,
cachedResponseHandler: responseCacher,
eventMonitors: [networkLogger]
)
桥接模式
将抽象部分与它的实现部分分离,使它们都可以独立地变化。paramsEncoder是一个很好的例子
/// 参数编码,有些情况需要把参数编码到URL中,包含了转义相关的知识
public protocol ParameterEncoder {
/// 把Parameters类型的参数编码进URLRequest中,但是要求Parameters类型必须符合Encodable协议
func encode<Parameters: Encodable>(_ parameters: Parameters?, into request: URLRequest) throws -> URLRequest
}
在URLEncodedFormParameterEncoder编码url query string数据
// MARK: URLEncodedFormParameterEncoder编码url query string数据
open class URLEncodedFormParameterEncoder: ParameterEncoder {
/// 实现协议的编码参数方法,把编码参数丢入body或URL上
open func encode<Parameters: Encodable>(_ parameters: Parameters?,
into request: URLRequest) throws -> URLRequest {
在JsonEncoder来编码数据,可以控制json的格式
/// 若编码的参数为符合Encodable类型的字典时,使用两种编码方式都ok。比如parameter = ["a": 1, "b": 2]这样的参数
open class JSONParameterEncoder: ParameterEncoder {
// 实现协议的编码方法,把参数编码成JSONData
open func encode<Parameters: Encodable>(_ parameters: Parameters?,
into request: URLRequest) throws -> URLRequest {
组合模式
将对象组合成树形结构以表示部分-整体
的层次结构,组合模式使得用户对单个对象和组合对象的使用具有一致性,用户可以统一的使用组合结构中的所有对象。
最简单的最常见的例子就是UIView,典型的树形结构。
在alamofire也有用到,组合模式最大的优点是他的节点可以自由增加,且调用节点方便
AF.request("https://httpbin.org/get")
.responseString { response in
print("Response String: \(response.value)")
}
.responseJSON { response in
print("Response JSON: \(response.value)")
}
装饰模式
其实Swift 的 extension
就是装饰模式的一种,类应该接纳扩展,但避免修改。
外观模式
向现有的系统添加一个接口,来隐藏系统的复杂性。
只需要知道HTTPMethod的
public struct HTTPMethod: RawRepresentable, Equatable, Hashable {
/// `CONNECT` method.
public static let connect = HTTPMethod(rawValue: "CONNECT")
/// `DELETE` method.
public static let delete = HTTPMethod(rawValue: "DELETE")
/// `GET` method.
public static let get = HTTPMethod(rawValue: "GET")
/// `HEAD` method.
public static let head = HTTPMethod(rawValue: "HEAD")
/// `OPTIONS` method.
public static let options = HTTPMethod(rawValue: "OPTIONS")
/// `PATCH` method.
public static let patch = HTTPMethod(rawValue: "PATCH")
/// `POST` method.
public static let post = HTTPMethod(rawValue: "POST")
/// `PUT` method.
public static let put = HTTPMethod(rawValue: "PUT")
/// `TRACE` method.
public static let trace = HTTPMethod(rawValue: "TRACE")
public let rawValue: String
public init(rawValue: String) {
self.rawValue = rawValue
}
}
享元模式
如果存在可以复用的对象,那么对象将被共享而不是创建新的对象。享元模式的最佳实践就是UITableView
的复用机制——超出屏幕外的单元格统一被回收放到一个复用队列之中,等待着需要新的单元格时进行复用。
享元模式可以再次创建对象 也可以取缓存对象
单例模式则是严格控制单个进程中只有一个实例对象
代理模式
为其他对象提供一种代理以控制对这个对象的访问。
/// 把各个状态事件派发给事件监听器对象
open class SessionDelegate: NSObject {
///持有一个强引用EventMonitor协议对象, 用来接收请求中的各个状态事件
var eventMonitor: EventMonitor? (声明)
需要调用的话嵌入
// 收到需要验证证书的回调
open func urlSession(_ session: URLSession,
task: URLSessionTask,
didReceive challenge: URLAuthenticationChallenge,
completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
//告知事件监听器
eventMonitor?.urlSession(session, task: task, didReceive: challenge)
继承代理,实现代理的内容
class GitNetworkLogger: EventMonitor {
///收到响应数据
func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive data: Data) {
print(data)
}
}
职责链模式
避免请求发送者与接收者耦合在一起,让多个对象都有可能接收请求,将这些对象连接成一条链,并且沿着这条链传递请求,直到有对象处理它为止。职责链模式是一种对象行为型模式。
Ps: 点击事件:如果给定的响应者对象 .isUserInteractionEnabled = false
就把信息传递给下一个响应者
命令模式
请求对象将一或多个动作绑定在特定的接收者上。
func allAction() {
action1()
action2()
action3()
}
解释器模式
可以将一个需要解释执行的语言中的句子表示为一个抽象语法树;一些重复出现的问题可以用一种简单的语言来进行表达;一个语言的文法较为简单。option + command + /
迭代器模式
迭代器模式可以让用户通过特定的接口巡访容器中的每一个元素而不用了解底层的实现。常见用在数组
ps:数组 .append .remove 就是迭代器的一种
中介者模式
用一个中介对象来封装一系列的对象交互。中介者使各对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互。
session就是alamofire的中介者
备忘录模式
在不破坏封装的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,这样可以在以后将对象恢复到原先保存的状态。
alamofire的缓存就是备忘录模式
/// 先修改数据,再缓存新的数据,参数为修改数据的闭包,改闭包返回可选的新缓存数据
let responseCacher = ResponseCacher(behavior: .modify { _, response in
let userInfo = ["date": Date()]
return CachedURLResponse(
/// 与实例关联的URL响应对象。
response: response.response,
/// 缓存响应的数据
data: response.data,
/// 缓存响应的用户信息字典
userInfo: userInfo,
/// 硬盘和内存没有限制
storagePolicy: .allowed)
})
观察者模式
一个对象的状态发生变化时,其它具有依赖关系的对象可以自动地被通知和更新
KVO NSKeyValueObservation
通知 notification
var stuName: String = "" { willSet { print("姓名即将修改,新值为:\(newValue)") } didSet { print("姓名已经修改,旧值为:\(oldValue)") } }
状态模式
允许一个对象在其内部状态改变时改变它的行为。
Alamofire 的Request的State
public enum State { /// Initial state of the `Request`. /// Request初始状态 case initialized /// 调用resume()的时候更新为该状态, 同时对所有自己创建的task调用resume()方法 case resumed /// 类似上面resumed case suspended /// 类似上面,不同的是,一旦调用了canceled,Request就不再能转变为其他状态了 case cancelled /// 当响应解析全部完成,并且回调被清楚后更新为该状态 case finished
开始发送请求的判断
request.withState { state in switch state { // 初始化或者请求完成,什么都不干 case .initialized, .finished: // Do nothing. break // 发送请求 case .resumed: task.resume() //告知request task开始请求 rootQueue.async { request.didResumeTask(task) } // 请求挂起 case .suspended: task.suspend() //告知request task挂起请求 rootQueue.async { request.didSuspendTask(task) } // 请求取消 case .cancelled: // Resume to ensure metrics are gathered. //先恢复task 再取消, 保证task被取消 task.resume() task.cancel() //告知request task取消请求 rootQueue.async { request.didCancelTask(task) } } }
策略模式
定义一系列的算法,把它们一个个封装起来, 并且使它们可相互替换。本模式使得算法可独立于使用它的客户而变化。swift的常见用法就是定义协议protocol
,让需要的类遵守该协议
模板方法模式
模板方法模式使子类可以重定义一个算法中的特定步骤,而不需要改变算法的结构。
定义一个超类,继承这个超类
典型的模板方法模式为override func
Alamofire重定义请求状态
/// 重置请求状态 func reset() { error = nil uploadProgress.totalUnitCount = 0 uploadProgress.completedUnitCount = 0 downloadProgress.totalUnitCount = 0 downloadProgress.completedUnitCount = 0 $mutableState.write { state in state.isFinishing = false state.responseSerializerCompletions = [] } }
/// 重置请求时要把已下载的data清空 override func reset() { super.reset() mutableData = nil }
访问者模式
表示一个作用于某对象结构中的各元素的操作。它使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作。访问者不同的一般的设计模式,开发中的实际场景相对较少
定义访问类
class PlaceVisitor { func visitor(boss:Boss) {} func visitor(employee:Employee) {}}
元素基类为Person
class Person { func accept(visitor:PlaceVisitor) {}}
Employee继承Person
class Employee:Person { override func accept(visitor: PlaceVisitor) { visitor.visitor(employee: self) } }
定义访问行为
class PlaceVisitor { func visitor(employee:Employee) {}}class HouseVisitor:PlaceVisitor { override func visitor(employee: Employee) { print("员工在家看电视聊天") }}
调用
let employee:Employee = Employee()let houseVisitor:PlaceVisitor = HouseVisitor()employee.accept(visitor: houseVisitor)
工厂方法模式
提供一个接口,用于创建与某些对象相关或依赖于某些对象的类家族,而又不需要指定它们的具体类。
Alamofire 使用大量的工厂模式例如
输入的是URLConvertible,其实是String -> URL
open func request(_ convertible: URLConvertible
String来继承URLConvertible
extension String: URLConvertible { /// Returns a `URL` if `self` can be used to initialize a `URL` instance, otherwise throws. /// /// - Returns: The `URL` initialized with `self`. /// - Throws: An `AFError.invalidURL` instance. public func asURL() throws -> URL { guard let url = URL(string: self) else { throw AFError.invalidURL(url: self) } return url }}
在URLRequest的初始化里,转换为URL
public init(url: URLConvertible, method: HTTPMethod, headers: HTTPHeaders? = nil) throws { let url = try url.asURL() self.init(url: url)
我们只需要输入String就能转换为URL,转换失败也会返回AFError的错误提示
AF.request("https://www.baidu.com").responseString { resp in
建造者模式
将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。建造者模式是一种对象创建型模式。
Product & bulider
Alamofire的一个例子 参数编码
//参数编码,有些情况需要把参数编码到URL中,包含了转义相关的知识public protocol ParameterEncoder { func encode<Parameters: Encodable>(_ parameters: Parameters?, into request: URLRequest) throws -> URLRequest}
leader
struct RequestEncodableConvertible<Parameters: Encodable>: URLRequestConvertible {let encoder: ParameterEncoderreturn try parameters.map { try encoder.encode($0, into: request) } ?? request
原型模式
使用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。原型模式是一种对象创建型模式。
原型模式创建新对象的过程中是拷贝,具体实现由深拷贝和浅拷贝之分.
func clone() -> AnyObject? { return nil}
class Book:Product { var name:String? var price:Float = 0.0 override func clone() -> AnyObject? { let book:Book = Book() book.name = self.name book.price = self.price return book }}let book:Book = Book()let temp:Book = book.clone() as! Book