设计模式是一种特定的解决问题的方法,是基于软件设计原则的具体实现。设计模式是从多种场景中提取出来的、经过实践验证的解决方案,通常提供了具体的代码实现和设计架构。常见的设计模式有单例模式、工厂模式、观察者模式、策略模式等等,这些模式为开发人员提供了特定场景下的具体解决方案,帮助开发人员实现更为优秀的应用程序。 最为知名的是GOF模式,GOF是Gang of Four的缩写,由四个著名的软件工程师在1994年出版书中总结。
经典的GOF设计模式有23个,分为创建型、结构型、行为三大类模式,这里主要介绍创建型模式。 结构型模式分为以下5种设计模式,这类模式提供创建对象的机制, 能够提升已有代码的灵活性和可复用性。
一、 工厂方法(Factory Method)
核心思想:定义创建对象的接口,但由子类决定实例化哪个类
将对象的创建延迟到子类中,父类只定义创建对象的接口。
下面以一个集成多个人脸识别SDK功能为例,需求是客户端集成多个厂商渠道SDK后要实现后台控制分流比例。 工厂方法模式做法:
- 定义产品协议:创建的目标(即具体产品类)需要遵守的协议
FaceSession,协议中的具体方法是比较统一的人脸识别需要的步骤,比如字节人脸、商汤人脸、旷视人脸。 - 定义各个厂商产品类: 需遵守并根据自己厂商的逻辑实现
FaceSession协议的方法,底层会依赖各个厂商SDK。 - 定义工厂协议:各个工厂类需要遵守的协议
FaceFactory, 里面有创建方法返回FaceSession类型. - 定义具体工厂类:遵守
FaceFactory,并在创建方法中封装具体的产品类的具体细节。
使用方:
=》拉取后台的分流数据,此时可以确定目前是哪个具体工厂类`AAAFactoy`.
=》由工厂类`AAAFactoy`创建对应的`FaceSession`(外部只需要知道是FaceSession类型不需要知道具体类).
=》根据它的需要拉取此次人脸需要的数据作为参数.
=》调用`FaceSession`中人脸方法.
=》真实`FaceSession`类型调用对应厂商SDK的方法发起人脸
=》接收识别结果及用户操作回调等处理
收益:
- 开闭原则:主体功能逻辑在新增或者更换人脸识别厂商时不需要改动,只需要变更对应的工厂类和产品类。
- 职责单一:各司其职,使用方不需要关心具体的工厂和产品,只需要知道有协议中方法满足需求。
- 可插拔:移除厂商SDK时不需要改动其他代码,移除对应类即可;新增厂商SDK时只需要新增对应的工厂和产品类,对已有流程无修改。
由简单工厂模式演变而来,由于简单工厂模式并未被认定为GOF经典设计模式, 所以没有列在这里。
二、抽象工厂(Abstract Factory)
核心思想:创建一系列相关或相互依赖的对象族,无需指定它们的具体类。相比工厂方法可创建多个产品组成的产品族。
抽象工厂模式通过引入一个抽象工厂接口,该接口声明了一组用于创建不同类型产品的方法。具体的产品创建由实现了抽象工厂接口的具体工厂类负责。通过使用抽象工厂模式,客户端可以创建一系列相关的产品,而无需关心每个具体产品的创建细节。
主要角色:
- 抽象产品接口:定义了产品的公共方法。
- 具体产品类:实现了抽象产品接口。
- 抽象工厂接口:定义了创建一系列相关产品的方法。
- 具体工厂类:实现了抽象工厂接口,负责创建一系列相关产品。
相比工厂方法,抽象工厂方法模式的工厂能创建一系列相关的产品。
三、生成器模式(Builder Pattern)
将一个复杂对象的构造过程分解成多个简单的步骤,可以灵活地组合这些步骤来创建不同的对象变体。
核心思想:“分步构建复杂对象,让构建过程和表示分离”
实例
import Foundation
// 产品:网络请求配置
struct NetworkRequest {
let url: URL
let method: HTTPMethod
let headers: [String: String]
let body: Data?
let timeout: TimeInterval
let cachePolicy: URLRequest.CachePolicy
enum HTTPMethod: String {
case get = "GET"
case post = "POST"
case put = "PUT"
case delete = "DELETE"
}
}
// Builder
class NetworkRequestBuilder {
private var url: URL?
private var method: NetworkRequest.HTTPMethod = .get
private var headers: [String: String] = [:]
private var body: Data?
private var timeout: TimeInterval = 30.0
private var cachePolicy: URLRequest.CachePolicy = .useProtocolCachePolicy
func setURL(_ urlString: String) -> Self {
self.url = URL(string: urlString)
return self
}
func setMethod(_ method: NetworkRequest.HTTPMethod) -> Self {
self.method = method
return self
}
func addHeader(key: String, value: String) -> Self {
headers[key] = value
return self
}
func setJSONBody<T: Encodable>(_ body: T) -> Self {
self.body = try? JSONEncoder().encode(body)
addHeader(key: "Content-Type", value: "application/json")
return self
}
func setTimeout(_ timeout: TimeInterval) -> Self {
self.timeout = timeout
return self
}
func setCachePolicy(_ policy: URLRequest.CachePolicy) -> Self {
self.cachePolicy = policy
return self
}
func build() -> NetworkRequest? {
guard let url = url else {
print("URL不能为空")
return nil
}
return NetworkRequest(
url: url,
method: method,
headers: headers,
body: body,
timeout: timeout,
cachePolicy: cachePolicy
)
}
func buildURLRequest() -> URLRequest? {
guard let networkRequest = build() else { return nil }
var request = URLRequest(url: networkRequest.url)
request.httpMethod = networkRequest.method.rawValue
request.allHTTPHeaderFields = networkRequest.headers
request.httpBody = networkRequest.body
request.timeoutInterval = networkRequest.timeout
request.cachePolicy = networkRequest.cachePolicy
return request
}
}
// 使用示例
class APIClient {
func login(username: String, password: String) {
let loginBody = ["username": username, "password": password]
guard let request = NetworkRequestBuilder()
.setURL("https://api.example.com/login")
.setMethod(.post)
.setJSONBody(loginBody)
.addHeader(key: "Accept", value: "application/json")
.setTimeout(15)
.buildURLRequest()
else { return }
URLSession.shared.dataTask(with: request) { data, response, error in
// 处理响应
}.resume()
}
}
四、原型模式(Prototype Pattern)
不需要知道对象的具体类型,只需要实现复制自身的能力。当直接创建对象成本较高时,通过复制现有对象来快速获得新实例。
核心思想:“以原型实例为基础,通过复制(克隆)来创建新对象”
类比iOS中的NSCopying协议,定义这样一个协议,协议中有copy对象的实例方法。当一个类需要有复制功能时,可以遵守该协议并写自己的实现。
五、单例模式
全局只存在一个实例。
- 提供一个静态的构建方法,如shared;
- 私有化实例初始化方法。