资讯专栏INFORMATION COLUMN

面向协议编程

zhkai / 2401人阅读

摘要:上面的协议中,我们除了声明一些人类共有的特质没有做任何其他的事情。这里我们仅仅是为了更加全面的介绍中协议所包含的各种能力。当然我们也可是同时遵循多个协议,这在某种程度上来说相当于语言中类的多继承的变通版本。

Swift语言由于先天的后发优势吸收了很多好的编程概念和特性,这些特性在给开发者带来新可能的同时也进一步促进了语言本身的进化。这也是经历三次Swift从入门到重学也不离不弃的原因?。Swift语言的优势和特性大抵如下:

跨平台。Linux平台的服务端正在发力,框架也在快速发展中。

开源给这门语言带来了无限可能。

OOP、POP、函数式这些编程理念全支持

这篇文章将会对其中的POP概念进行简单讲解。POP概念的传播起点大概就是在“喜新厌旧”的苹果在2015年WWDC上鼓励使用Value Type来替换Reference Type。但是我们需要明白一点:开发世界没有银弹。POP作为一个理念和特性有其适用场景并不能完全替代OOP,后者存在几十年是有理由的。

值类型与引用类型

上面说了POP兴起于Value Type被鼓励推崇后,那么我们就有必要理解两者的区别。值类型和引用类型最根本的区别就在于复制后的两者的表现。做个类比:值类型复制动作相当于克隆了自己,你和克隆的对象之间是相互独立的;引用类型复制动作后两者的关系相当于自己和影子。类比不是很贴切,但是不妨碍理解。下面用代码来说明:

Class HumanClass {
    var name: String
    
    init(name: String) {
        self.name = name
    }
}

var classyHuman = HumanCalss(name: "Bob")
classyHuman.name //Bob

var newClassyHuman = classyHuman    //复制一份

newClassyHuman.name = "Bobby"
classyHuman.name        //"Bobby"

当我们改变newClassyHuman对象的name属性后,类对象classyHuman也跟着发生了变化。

接下来看值类型:

struct HumanStruct {
    var name: String 
}

var humanStruct = HumanStruct(name: "Bob")
var newHumanStruct = humanStruct        //同样复制

newHumanStruct.name = "Bobby"
humanStruct.name                                //"Bob"

拷贝对象的属性改变并没有影响到原对象。

OOP的缺陷

作为几十年前的一种理念,OOP可以说已经在现代被用烂了,几乎所有的编程语言都支持这一特性。Java、Ruby等语言的设计理念中几乎将一切事物都看作对象,对象即中心、对象即真理。但是我们反过头来看OOP,其实可以很清晰的发现一些固有的缺陷。

继承机制要求你在开始之前就能设计好整个程序的框架、结构、事物间的连接关系。这要求开发者必须有很好的分类设计能力,因为结构天生对改动有抵抗特性。这也是为什么OOP领域中所有程序员都对重构讳莫如深,有些框架到最后代码量急剧膨胀变得难以维护从而失控。

继承机制带来的另一个问题就:子类中会存在无用的父类属性和方法,而这些冗余代码给子类带来的一定的风险,而且对于层级很深的代码结构来说Bug修复将会成为难题。

对象的状态不是我们的编码的好友,相反是我们的敌人。对象固有的状态在分享和传递过程中是很难追踪调试的,尤其在并行程序编码中问题就更加明显。OOP所带来的可变、不确定、复杂等特征完全与并行编程中倡导的小型化、核心化、高效化完全背离。而免费午餐时代已经结束、摩尔定律的吃力表现意味着接下来的世界是属于多核、并行、并发编程的。

这里我们顺便看下Apple用OOP思想完成的UIKit框架:

整体结构设计其实非常的清晰,但是如果让你在Apple对这个框架进行维护你有多少的自信能够出色完成任务?别说框架维护了,其实我们大部分开发者都仅仅停留在框架的语言应用层面并没有很大的耐心去厘清这个结构清晰的OOP框架。

欢迎来到POP的世界

你应该能够猜到了与OOP以引用类型Class为基础不同,POP理念的核心是值类型Struct。OOP是一种类金字塔的架构来搭建世界,POP则是一个扁平、非嵌套的代码世界。

"A protocol defines a blueprint of methods, properties… The protocol can then be adopted by a class, structure, or enumeration" - Apple

上面是Apple对协议的定义说明,其中最关键的字眼莫过于“blueprint"。其实Protocal类似于篮球教练,他告诉球员们如何执行战术、如何赢得比赛,但是他本人可能并不知道如何完成一个漂亮的大风车扣篮。

初识POP

首先,我们为人类建立一个特征蓝图。

protocol Human {
    var name: String {get set }
    var  carrer: String {get set }
    func sayHi() 
}

上面的协议中,我们除了声明一些人类共有的特质没有做任何其他的事情。其中的{get set }仅仅只是表面这些属性是可读写的,下面我们让运动员遵循该协议:

struct Athlete: Human {
    var name: String = "Kobe Bryant"
    var carrer:   String - "Basketball Player"
    
    func satHi() { print("Hi,I"m (name)" ) }
}

一旦Struct遵循了Human协议,它就必须按照规则实现所有的协议属性和方法。当然Xcode同学会提醒你协议中的那些是你需要必须实现的,所以你不必害怕遗忘了其中的部分内容。

协议的继承

在Protocol的世界中,我们可以使用OOP中的继承概念对协议进行继承形成协议树。需要注意的是这同样会带来OOP中的恶果,不宜滥用。这里我们仅仅是为了更加全面的介绍POP中协议所包含的各种能力。

我们在Human协议基础上实现SuperHuman的协议。

protocol SuperHuman: Human {
    var canFly: Bool { get set } }
    func punch()
}

如果现在有一个Struct遵循了SuperHuman协议,那么除了SuperHuman协议中的内容,我们同时也要实现Human协议中的内容。

struct SuperSaiyan: SuperHuman {
    var name: String = "Goku"
     var race: String = "Asian"
     var canFly: Bool = true
    func sayHi() { print("Hi, I"m (name)") }
    func punch() { print("Puuooookkk") } 
}

当然我们也可是同时遵循多个协议,这在某种程度上来说相当于C++语言中类的多继承的变通版本。

struct SuperSaiyan: SuperHuman, ProtocolAnother { }
协议拓展

协议拓展(Protocol Extension)是协议使用过程中最强大的武器,下面我们直接上码:

// 会说英语的动物
protocol SuperAnimal {
    func speakEnglish() 
}

接下来我们对其进行拓展:

extension SuperAnimal {
    func speakEnglish() {
        print("I speak English, pretty coo;, huh?")
    }
}

最后我们看看效果如何:

struct Donkey: SuperAnimal{

}

var ramon = Donkey()
ramon.speakEnglish()        //  "I speak English, pretty cool, huh?"

从上面的演示效果我们可以发现:通过协议拓展我们给协议的遵循者一些默认的方法、属性的实现。

作为Type的Protocol

如果我告诉你可以在数组里面同时保存Struct和Class对象而不用进行任何形式的类型转换,你会作何感想?
是不是觉得不可思议,这确实有点突破常规,但同时在Swift中也是真实存在的。

直接上码:

protocol Fightable {
    func legKick() 
}

struct StructKangaroo: Fightable {
     func legKick() { print("Puuook") }
 }
 
 class ClassKangaroo: Fightable { 
     func legKick() {print("Pakkkk") } 
}

let structKang = StructKangaroo()
let classKang = ClassKangaroo()

var kangaroos: [Fightable] = [structKang, classKang]

for kang in kangaroos { 
    kang.legKick() 
}
// "Puuook"
// "Pakkkk"

我们将同时采用Fightable协议的Class、Struct对象保存到了[Fightable]类型的数组中,并且可以按照正常的数组一样进行操作,是不是很神奇。

结语

编程世界没有银弹,每一种理念都有其存在的价值。这篇文章中我简单的介绍了POP的概念以及Protocol世界中的一些语法糖,真正的POP需要你自己在这些基础知识和语法糖的上层去应用。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/16697.html

相关文章

  • fir.im Weekly - 揭秘 iOS 面向协议编程

    摘要:本期重点推荐关于面向协议编程相关文章,还有多线程安全进阶应用框架蓝牙实践等技术文章分享和工具源码分享开发分享面向协议编程与的邂逅面向协议编程,以下简称是在年上提出的的一种编程范式。相比与传统的面向对象编程,显得更加灵活。 本期 fir.im Weekly 重点推荐关于 iOS 面向协议编程相关文章,还有 iOS 多线程安全、Swift 进阶、Android MVVM 应用框架、Andr...

    ispring 评论0 收藏0
  • fir.im Weekly - 揭秘 iOS 面向协议编程

    摘要:本期重点推荐关于面向协议编程相关文章,还有多线程安全进阶应用框架蓝牙实践等技术文章分享和工具源码分享开发分享面向协议编程与的邂逅面向协议编程,以下简称是在年上提出的的一种编程范式。相比与传统的面向对象编程,显得更加灵活。 本期 fir.im Weekly 重点推荐关于 iOS 面向协议编程相关文章,还有 iOS 多线程安全、Swift 进阶、Android MVVM 应用框架、Andr...

    ls0609 评论0 收藏0
  • python网络编程

    摘要:在任何类型的通信开始之前,网络应用程序必须创建套接字。基于文件的套接字,家族名又名基于网络的套接字,家族名在和后续的版本中,支持的套接字有,,,。中的网络编程在中主要是用模块来实现基于套接字的网络通信。 python学习记录--网络编程 1、套接字介绍 一台机器上的不同进程之间进行通信可以利用队列,管道等,但是不同机器之间的进程进行通信用队列是不行的,解决这个问题就是网络套接字。 套接...

    xuhong 评论0 收藏0
  • Java网络编程探究|乐字节

    摘要:换句话说,套接字起到通信端点的作用。单个套接字是一个端点,而一对套接字则构成一个双向通信信道,使非关联进程可以在本地或通过网络进行数据交换。 大家好,我是乐字节小乐,上次给大家讲述了Java中的IO流之输出流|乐字节,本文将会给大家讲述网络编程。 主要内容如下: 网络 网络分层 列表项目 IP位置 端口port 网络编程 showImg(https://segmentfault.c...

    Kahn 评论0 收藏0
  • Python 网络编程之 UDP 协议

    摘要:创建创建通信接受套接字的数据,与类似,但返回值是。发送数据,将数据发送到,形式为,指定远程地址发送,返回值是发送的字节数发送的报文是类型,发送的报文是类型,在发送前要记得编码。 UDP 和 TCP 的区别   TCP UDP 连接性 面向连接 面向无连接 传输可靠性 可靠 不可靠 传输模式 流 数据报 应用场景 传输大量的数据 少量数据 速度 慢 快 T...

    waterc 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<