设计模式-创建型

设计模式-创建型

创建型设计模式包含:单例模式、原型模式、工厂方法模式、抽象工厂模式、建造者模式

单例模式

单例模式在开发中也是最常见的一种设计模式之一,系统原生提供的很多类的设计都采用了单例模式,例如:

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 为工厂方法,其中根据套餐类型创建不同的套餐对象,具体的套餐对象的组成则是由 BuildABuildB 来完成。 BuildABuildB 是建造者模式的核心类,充当建造者的角色。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,684评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,143评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,214评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,788评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,796评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,665评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,027评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,679评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,346评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,664评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,766评论 1 331
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,412评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,015评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,974评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,073评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,501评论 2 343

推荐阅读更多精彩内容