【《Pro Swift》阅读笔记】08 - 设计模式

书籍链接:《Pro Swift》 (链接需要梯子才能打得开)。

一、面向协议编程 (protocol-oriented programming(POP))

Swift给我们带来了一种新的设计模式,面向协议编程(后面用POP表示)。他继承了面向对象(后面用OOP表示)的封装和多肽特性,但是没有继承特性。POP让我们以横向的方式构建应用,而不是纵向:通过实现协议来添加方法或者属性,而不是通过继承。

二、协议扩展细节

1. 为协议方法提供默认的实现

在创建了一个协议之后,如果我们想给协议的某个方法提供默认的实现,可以用扩展来实现:

protocol Payable {
   func calculateWages() -> Int
}

extension Payable {
   func calculateWages() -> Int {
      return 10000
   }
}

2. Objective-C无法访问协议的默认实现

例如,刚刚那个例子,我们在协议加上@objc,让Objective-C上可以访问到Payable协议:

@objc protocol Payable {
    func calculateWages() -> Int
}

extension Payable {
    func calculateWages() -> Int {
        return 10000
    }
}

虽然我们用扩展为calculateWages()提供了默认实现,但是这个实现在Objective-C中是访问不到的,Objective-C必须自己实现这个方法。

3. 一个容易出现的错误

我们先看代码:

我们把协议里面的calculateWages()注释掉,然后扩展Payable实现了calculateWages()方法;定义了Surgeon并用遵循Payable协议,用扩展重写PauyablecalculateWages()方法;最后创建了两个实例gregorydoogie。结果是gregory.calculateWages()返回20000,而doogie.calculateWages()返回10000

即使gregorydoogie都是Surgeon的实例,但是doogie是以Payable的类型存储的。因为我们在payable协议的创建里把calculateWages()注释掉了,所以Swift在调用calculateWages()的时候是以他们存储的类型为准的,gregory的存储类型是Sugreon,所以调用Sugreon的方法,返回20000;而doogie是以Payable的类型存储的,所以调用Payable的方法,返回10000

如果我们恢复payable协议的calculateWages(),他们的结果都返回20000

三、横向思考

文章开始我们提到POP让我们以横向的方式构建应用,而不是纵向。纵向就意味着继承,先有一个基类,然后再不断地创建子类;而横向则是通过创建协议,然后通过实现协议的规定,添加特定的方法。我们可以实现多个协议,这听起来就像多继承。

四、POP练习

首先我们先定义六个协议,每个协议有一个方法,并且都提供了默认的实现:

protocol Payable {
    func calculateWages() -> Int
}

extension Payable {
    func calculateWages() -> Int {
        return 10000
    }
}

// 提供治疗
protocol ProvidesTreatment {
    func treat(name: String)
}

extension ProvidesTreatment {
    func treat(name: String) {
        print("I have treated \(name)")
    }
}

// 提供诊断
protocol ProvidesDiagnosis {
    func diagnose() -> String
}

extension ProvidesDiagnosis {
    func diagnose() -> String {
        return "He's dead, Jim"
    }
}

// 进行手术
protocol ConductsSurgery {
    func performSurgery()
}

extension ConductsSurgery {
    func performSurgery() {
        print("Success!")
    }
}

// 休息
protocol HasRestTime {
    func takeBreak()
}

extension HasRestTime {
    func takeBreak() {
        print("Time to watch TV")
    }
}

// 学习
protocol NeedsTraining {
    func study()
}

extension NeedsTraining {
    func study() {
        print("I'm reading a book")
    }
}

再创建四个医院里的角色:

struct Receptionist { } // 接待员
struct Nurse { }        // 护士
struct Doctor { }       // 医生
struct Surgeon { }      // 外科医生

然后让刚刚创建的角色遵循合适的协议:

extension Receptionist: Payable, HasRestTime, NeedsTraining {}

extension Nurse: Payable, HasRestTime, NeedsTraining, ProvidesTreatment {}

extension Doctor: Payable, HasRestTime, NeedsTraining, ProvidesTreatment, ProvidesDiagnosis {}

extension Surgeon: Payable, HasRestTime, NeedsTraining, ProvidesDiagnosis, ConductsSurgery {}

但是我们可以看到,所有的角色都遵循了PayableHasRestTimeNeedsTraining,上面的代码就重复了,所以我们可以再创建一个新的协议把那三个重复的协议组合起来:

protocol Employee: Payable, HasRestTime, NeedsTraining {}

extension Receptionist: Employee {}
extension Nurse: Employee, ProvidesTreatment {}
extension Doctor: Employee, ProvidesDiagnosis,ProvidesTreatment {}
extension Surgeon: Employee, ProvidesDiagnosis, ConductsSurgery{}

对扩展进行约束

例如,我们想在Employee添加一个方法:

extension Employee {
   func checkInsurance() {
      print("Yup, I'm totally insured")
   }
}

但是checkInsurance()方法并不是所有遵循了Employee的类型都适合的,所以我们要限制那些类型可以使用checkInsurance()方法。例如我们只想让ProvidesTreatment这个类型拥有checkInsurance()方法,则可以用where来限制:

extension Employee where Self: ProvidesTreatment {
   func checkInsurance() {
      print("Yup, I'm totally insured")
   }
}

五、MVC和MVVM

作者还另外介绍了MVC和MVVM,关于这两个概念的文章已经非常多,我就不在这写了。大家可以自行了解。

有任何问题,欢迎大家留言!

欢迎加入我管理的Swift开发群:536353151,本群只讨论Swift相关内容。

原创文章,转载请注明出处。谢谢!

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

推荐阅读更多精彩内容

  • 发现 关注 消息 iOS 第三方库、插件、知名博客总结 作者大灰狼的小绵羊哥哥关注 2017.06.26 09:4...
    肇东周阅读 12,104评论 4 62
  • #每天三件事#14/53 第一件事:感谢大树今天一早分享的学习方法,在车上仔细阅读过后,再带着自己的情况又阅读了一...
    封笔ing阅读 122评论 2 0
  • 终于懂了,那些所谓的失眠的夜,才不是因为想念某个人,只不过是因为穷和无聊!以及知道明天还会过着,一如往常一般单调的生活!
    沈时晴阅读 358评论 0 0
  • JACK放弃生命 沉入了海底 变成了鱼 他想念ROSE 所以有了鱼香肉丝。
    茶渔阅读 498评论 0 49
  • 苏玛丽醒来的时候,床上只有她一个人,她慵懒地把糟乱的头发堆在脸上,接着把太空被拉过头顶,窒息感慢慢袭来,她多想就这...
    离别奏阅读 441评论 0 0