设计模式-创建型
创建型设计模式包含:单例模式、原型模式、工厂方法模式、抽象工厂模式、建造者模式
单例模式
单例模式在开发中也是最常见的一种设计模式之一,系统原生提供的很多类的设计都采用了单例模式,例如:
FileManager.default
UserDefaults.standard
NotificationCenter.default
UIApplication.shared
URLSession.shared
其目的是为了节省内存资源并保证数据内容的一致性,需要让某些类只能创建一个实例。单例模式有如下特点:
- 单例类只有一个实例对象
- 单例类的实例对象由自己创建
- 需要对外提供一个访问其实例对象的接口
在软件设计中,有关全局共享的资源数据,大型通用的管理类等都可以使用单例模式,例如登录用户的用户信息类、全局的计时器、程序的日志管理类
Swift 单例
class ClassA {
static let share = ClassA()
}
Objective-C 单例
static XXClassManager *_defaultManager;
+ (instancetype)shareInstance {
if (!_defaultManager) {
_defaultManager = [[self alloc] init];
}
return _defaultManager;
}
+ (instancetype)allocWithZone:(struct _NSZone *)zone {
if (!_defaultManager) {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_defaultManager = [super allocWithZone:zone];
});
}
return _defaultManager;
}
- (id)copyWithZone:(NSZone *)zone{
return _defaultManager;
}
- (id)mutableCopyWithZone:(NSZone *)zone{
return _defaultManager;
}
原型模式
以一个已经创建的实例作为原型,通过复制该原型对象来创建出对象,在使用对象时,使用者无需关心对象创建的细节。在iOS开发中:copy
方法就是对原型设计模式的一种实现。主要是提供了一种大量创建复杂对象的方法。
重构前
import Foundation
class Computer {
var cpu: String
var host: String
var screen: String
var uuid: String
init(cpu: String, host: String, screen: String) {
self.cpu = cpu
self.host = host
self.screen = screen
self.uuid = UUID().uuidString
}
func logUUID() {
print(uuid)
}
}
let computer1 = Computer(cpu: "Intel core i7 7700K", host: "GY088-GDF-60", screen: "3008 x 1692")
computer1.logUUID()
此时若希望创建一台相同配置的电脑则只能使用重复的创建方法
let computer2 = Computer(cpu: "Intel core i7 7700K", host: "GY088-GDF-60", screen: "3008 x 1692")
重构后
import Foundation
class Computer {
...
func copy() -> Computer {
return Computer(cpu: self.cpu, host: self.host, screen: self.screen)
}
}
新增一个 copy() 方法,此时再创建相同配置的电脑只需调用原型的 copy() 方法即可,省去了配件的创建过程。
使用原型模式,一旦第一个对象被创建,后面的对象创建都将变得非常容易。其中,作为模板对象被称为原型,创建出来的对象拥有和模板对象一致的属性和方法。
工厂方法模式
工厂方法设计模式注重于将对象的创建过程封闭起来,通过定义抽象的工厂接口和商品接口来隐藏负责对象创建的具体类
对上述 Computer 类进行重构
重构后
enum Level {
case low
case high
}
protocol ComputerFactoryProtol {
static func getComputer(level: Level) -> ComputerProtol
}
protocol ComputerProtol {
var cpu: String { get }
var host: String { get }
var screen: String { get }
var uuid: String { get }
func logUUID()
}
class Computer: ComputerProtol {
var cpu: String
var host: String
var screen: String
var uuid: String
init(cpu: String, host: String, screen: String) {
self.cpu = cpu
self.host = host
self.screen = screen
self.uuid = UUID().uuidString
}
func logUUID() {
print(uuid)
}
}
class ComputerFactory: ComputerFactoryProtol {
static func getComputer(level: Level) -> ComputerProtol {
switch level {
case .low:
return Computer(cpu: "Intel core i5 3300K", host: "GY088-GDF-10", screen: "1920 x 1080")
case .high:
return Computer(cpu: "Intel core i7 7700K", host: "GY088-GDF-60", screen: "3008 x 1692")
}
}
}
引入的 ComputerFactory 即工厂设计模式的具体体现,外界不再指明具体的配置信息,只需要根据 level 即可创建指定配置的 Computer,
创建高配电脑,例如:
let computer3 = ComputerFactory.getComputer(level: .high)
如果新增加了一种创建方式完全不同的计算机,我们只需要新建一个遵守 ComputerProtol
的计算机类,之后在 ComputerFactory
中统一处理这种新增的计算机类型即可,对使用者完全隐藏。
抽象工厂模式
抽象工厂是对工厂模式的一种升级,核心思路是为各种类型的对象提供一组统一的创建接口,使用者无需关心这些对象具体是如何创建的。
还是上述代码,若我们工厂方法即生产 Computer
又可以生产 TV
重构后
enum Level {
case low
case high
}
protocol ComputerFactoryProtol {
static func getComputer(level: Level) -> ComputerProtol
static func getTV() -> TVProtol
}
protocol TVProtol {
var name: String { get }
func logName()
}
class TV: TVProtol {
var name: String
init(name: String) {
self.name = name
}
func logName() {
print(self.name)
}
}
protocol ComputerProtol {
...
}
class Computer: ComputerProtol {
...
}
class ComputerFactory: ComputerFactoryProtol {
static func getTV() -> TVProtol {
return TV(name: "海尔")
}
static func getComputer(level: Level) -> ComputerProtol {
...
}
}
重构后工厂类可以创建不同的对象,对于使用者无需关心创建的细节,抽象工厂将对象的创建和使用进行了完全分离。
建造者模式
建造者模式用于复杂对象的创建,使代码聚合性更强,逻辑更加清晰。建造者模式通常与工程模式配合使用,工厂着重于对象的创建,建造者着重于创建复杂对象过程中组成对象的每一部分创建和最终组装。
核心在于将复杂的对象拆解成多个简单对象,通过一步步构建简单对象最终组合成复杂对象。
重构后
enum Foodtype {
case a
case b
}
enum Drink {
case cola
case juice
}
enum Staple {
case hamburger
case chickenRoll
}
class FoodPackage {
var drink: Drink?
var staple: Staple?
}
class BuildA {
var foodPackage = FoodPackage()
func build() -> FoodPackage {
foodPackage.drink = .cola
foodPackage.staple = .hamburger
return foodPackage
}
}
class BuildB {
var foodPackage = FoodPackage()
func build() -> FoodPackage {
foodPackage.drink = .juice
foodPackage.staple = .chickenRoll
return foodPackage
}
}
class FoodFactory {
static func buildFood(type: Foodtype) -> FoodPackage {
switch type {
case .a:
return BuildA().build()
case .b:
return BuildB().build()
}
}
}
let foodPackage = FoodFactory.buildFood(type: .a)
其中,一个完整的套餐对象由饮料对象、主食对象组成,FoodFactory
为工厂方法,其中根据套餐类型创建不同的套餐对象,具体的套餐对象的组成则是由 BuildA
和 BuildB
来完成。 BuildA
和 BuildB
是建造者模式的核心类,充当建造者的角色。