Swift -POP( 面向协议编程)与OOP(面向对象编程)
面向协议编程(Protocol Oriented Programming,简称POP),是Swift的一种编程范式,Apple于2015年WWDC提出的,如果大家看Swift的标准库,就会看到大量POP的影子。
同时Swift也是一门面向对象的编程语言(Object Oriented Programming,简称OOP),在Swift开发中,OOP和POP是相辅相成的,任何一方并不能取代另一方。
今天我们重点讲解下面向协议编程(POP)在Swift下的使用
回顾OOP
OOP的三大特性:封装、继承、多态
继承的经典使用场合
当多个类(比如A、B、C类)具有很多共性时,可以将这些共性抽取到一个父类(比如D类),最后A、B、C类继承D类

OOP的不足
但有些问题,使用OOP并不能很好的解决问题,比如如何将BVC、DVC的公共方法run抽取出来?
class BVC: UIViewController{
func run() {
print("run")
}
}
class DVC: UITableViewController{
func run() {
print("fun")
}
}
基于OOP想到的一些解决方案?
- 将run方法放到另一个对象A中,然后BVC、DVC拥有A属性--多了一些额外的依赖关系
- 将run方法增加到UIViewController分类中--UIViewController会越来越臃肿,而且会影响它的其它所有子类
- 将run方法抽取到新的父类,采用多继承?Swift不支持多继承-(C++支持多继承)

POP的解决方案
protocol Runnable {
func run()
}
extension Runnable {
func run() {
print("run")
}
}
class BVC: UIViewController, Runnable{}
class DVC: UITableViewController, Runnable{}
POP的注意点
- 优先考虑创建协议,而不是父类(基类)
- 优先考虑值类型(struct, enum),而不是引用类型(class)
- 巧妙利用协议拓展功能
- 不要为了面向协议而实用协议
实例-使用协议实现前缀效果
统计字符串有几个数字出现,例如1234dafdaf1234,应该返回数字8?
1、如果在平常一处用到,可能大家直接会写一个对象方法,然后调用一下,即可计算出,如下:
func numberCount(_ str: String) -> Int {
var count =
for c in str where (""..."").contains(c) {
count +=
}
return count
}
通过调用self.numberCount("1234dafdaf1234")得出结论

2、通过上面需求,可以得出是字符串的拓展功能,因此想到另外一种对字符串进行拓展extension String,计算属性相当于方法
extension String {
///计算属性===方法,下面两种完全等价
//方法
func numberCount() -> Int {
var count =
for c in self where(""..."").contains(c) {
count +=
}
return count
}
//计算属性
var numberCount1: Int {
var count =
for c in self where (""..."").contains(c) {
count +=
}
return count
}
}
print("1234dafdaf1234".numberCount())
3、通过上面的已经可以很好的解决问题啦,对于要求很高的团队,上面还是有一些问题的,比如,上面是对系统的String进行拓展,如果定义的计算属性和系统的属性名字相同咋办,针对这个问题,可以有,在numberCount前面加入项目简称----(计算属性的本质是方法,要与存储属性分别开,不能为extension添加存储属性,如果要想添加,建立关联添加)
extension String {
///计算属性===方法,下面两种完全等价
//方法
func hcc_NumberCount() -> Int {
var count =
for c in self where(""..."").contains(c) {
count +=
}
return count
}
//计算属性
var hccNumberCount1: Int {
var count =
for c in self where (""..."").contains(c) {
count +=
}
return count
}
}
print("1234dafdaf1234".hccNumberCount1)
可以解决上面遇到的问题,但是不够优雅,也不符合Swift的风格,Swift中有大量协议的使用,如果有协议的加入,可以比较优雅的实现
是否可以实现"1234dafdaf1234".hcc.numberCount?
(因为是“”.hcc,所以对字符串拓展了一个属性hcc,而hcc.numberCount又是hcc类的一个属性,所以如下)
struct HCC {
var string: String
init(_ str: String) {
self.string = str
}
var numberCount: Int {
var count =
for c in string where (""..."").contains(c) {
count +=
}
return count
}
}
extension String {
var hcc: HCC {return HCC(self)}//传值self字符串
}
print("1234dafdaf1234".hcc.numberCount)
4、上面已经完成对字符串的拓展功能的系列,也已经很好的很优雅的解决了问题,但是如果相对字符串拓展一个功能的话,这就OK啦
如果想对数组进行拓展一个类似的方法,还要在HCC里面增加array属性和初始化以及拓展Array功能,就会发现冗余代码太多,且不够封装,不够通用
这时候泛型的作用就来啦,如下
struct HCC<Base> {
var base: Base
init(_ base: Base) {
self.base = base
}
}
extension String {
var hcc: HCC<String> {HCC(self)}
}
class Person{}
extension Person {
var hcc: HCC<Person> {HCC(self)}
}
extension HCC where Base == String {
var numberCount: Int {
var count =
for c in base where(""..."").contains(c){
count +=
}
return count
}
}
extension HCC where Base == Person {
func run() {
print("run")
}
}
"1234dafdaf1234".hcc.numberCount
Person().hcc.run()
效果图如下

5、上面实现了通过类的对象调用,可不可以实现通过类本身来调用呢,因为我在使用类.hcc的时候,并不想出现类对象的属性,只想出现类型本身的方法和属性,这就需要用到static来修饰
struct HCC<Base> {
var base: Base
init(_ base: Base) {
self.base = base
}
}
extension String {
var hcc: HCC<String> {HCC(self)}
static var hcc: HCC<String>.Type {HCC<String>.self}
}
class Person{}
extension Person {
var hcc: HCC<Person> {HCC(self)}
}
extension HCC where Base == String {
var numberCount: Int {
var count =
for c in base where(""..."").contains(c){
count +=
}
return count
}
static func test() {
print("test")
}
}
extension HCC where Base == Person {
func run() {
print("run")
}
}
"1234dafdaf1234".hcc.numberCount
Person().hcc.run()
String.hcc.test()
完成上面需求!
6、但是如果要再次增加一个Dog类,也要在Dog类中有
var hcc: HCC<String> {HCC(self)}
static var hcc: HCC<String>.Type {HCC<String>.self}
这些代码,增加其他,会导致代码还是会有点冗余,这样就发现了POP的好处-是面向协议编程,将公共的地方抽出来(协议只能声明一些东西,想扩充一些东西,就是在extension加入)
///前缀类型
struct HCC<Base> {
var base: Base
init(_ base: Base) {
self.base = base
}
}
///利用协议扩展前缀属性
protocol HCCCompatible {}
extension HCCCompatible {
var hcc: HCC<Self> {HCC(self)}
static var hcc: HCC<Self>.Type {HCC<Self>.self}
}
///给字符串扩展功能
//让String拥有前缀属性
extension String: HCCCompatible {}
//给string.hcc以及String().hcc前缀扩展功能
extension HCC where Base == String {
var numberCount: Int {
var count = 0
for c in base where("0"..."9").contains(c){
count += 1
}
return count
}
static func test() {
print("test")
}
}
class Person{}
extension Person: HCCCompatible{}
class Dog{}
extension Dog: HCCCompatible{}
extension HCC where Base == Person {
func run() {
print("run")
}
}
这样就比较顺利较完美的解决了问题,又很好的拓展了功能!!!
总结
以后要给某一个类扩展功能,可采取下面步骤
- 定义一个前缀类型(如上面的hcc等)
- 定义一个协议(protocol)
- 遵守该协议即可
Swift -POP( 面向协议编程)与OOP(面向对象编程)的更多相关文章
- 为什么说swift是面向协议编程--草稿
为什么说swift是面向协议编程 public protocol ReactiveCompatible { /// Extended type associatedtype CompatibleTyp ...
- Python黑帽编程2.9 面向对象编程
Python黑帽编程2.9 面向对象编程 我个人认为,计算机语言的发展,有两个方向,一个是从低到高的发展过程,在这个过程中,语言的思考和解决问题的方式是面向硬件的.硬件本质上处理的是信号,在此基础上, ...
- Dart编程实例 - Dart 面向对象编程
Dart编程实例 - Dart 面向对象编程 class TestClass { void disp() { print("Hello World"); } } void main ...
- Swift中面向协议的编程
什么是面向协议的编程? 面向协议的编程,是一种编程范式. 编程范式,是一个计算机科学用语.维基百科中的解释是,计算机编程的基本风格或典型模式.通俗来说,就是解决某一个问题的方法不同方法和思路. 像大家 ...
- Java实现OOP(面向对象编程)
一.对象的综述 面向对象编程(OOP)具有多方面的吸引力.对管理人员,它实现了更快和更廉价的开发与维护过程.对分析与设计人员,建模处理变得更加简单,能生成清晰.易于维护的设计方案.对程序员,对象模型显 ...
- 用C实现OOP面向对象编程(1)
如摘要所说,C语言不支持OOP(面向对象的编程).并这不意味着我们就不能对C进行面向对象的开发,只是过程要复杂许多.原来以C++的许多工作,在C语言中需我们手动去完成. 博主将与大家一起研究一下如下用 ...
- 一百零六、SAP的OOP面向对象编程,OO-ALV的简介
面向对象编程,如图 基本概念: 1.对象(Object)是一个现实实体的抽象.一个对象可被认为是一个把数据(属性)和程序(方法)封装在一起的实体,这个程序产生该对象的动作或对它接受到的外界信号的反应. ...
- 为什么swift是面向协议的编程--对面向对象机制的改进
主要目标是提供抽象能力和解决值类型的多态问题 Actually, Abrahams says, those are all attributes of types, and classes are j ...
- (转)OOP(面向对象编程)的几大原则
文章转载自:http://blog.csdn.net/anders_zhuo/article/details/8949566 设计模式遵循的一般原则: 1.开-闭原则(Open-Closed Prin ...
随机推荐
- POI导出excel的三种方式
原文链接:https://www.cnblogs.com/zhaoblog/p/7661245.html poi导出excel最常用的是第一种方式HSSFWorkbook,不过这种方式数据量大的话会产 ...
- Kubernetes-Ingress资源详解
什么是Ingress #阿里云称之为ingress路由!在 Kubernetes 集群中,主要用于接入外部请求到k8s内部,Ingress是授权入站连接到达集群服务的规则集合,为您提供七层负载均衡能力 ...
- Codeforces Round #618 (Div. 2)
题库链接 https://codeforces.ml/contest/1300 A. Non-zero 一个数组,每次操作可以给某个数加1,让这个数组的积和和不为0的最小操作数 显然如果有0的话,必须 ...
- conCat()的应用
编写一个Java应用程序,从键盘读取用户输入两个字符串,并重载3个函数分别实现这两个字符串的拼接.整数相加和浮点数相加.要进行异常处理,对输入的不符合要求的字符串提示给用户: package com. ...
- 火狐的一个bug
发现这个bug是因为最近眼睛不太好,所以网页大小都是正常大小的140% 就发现火狐游览器好多网页上的输入框与按钮对不齐 测试代码 <!DOCTYPE html> <html lang ...
- C++ ABI之名字改编(以Qt为例)
在C++中,由于重载等技术的存在,编译器要将函数.结构体.类等等的信息传递给链接器,就不能像C语言那样简单地通过函数名来完成,它需要提供额外的参数信息,而还要和C语言共用链接器,这就需要用到名字改编( ...
- [Python]获取win平台文件的详细信息
import win32api def getFileProperties(fname): """ 读取给定文件的所有属性, 返回一个字典. ""&q ...
- Deep Learning for Chatbots(Introduction)
聊天机器人又被称为会话系统,已经成为一个热门话题,许多公司都在这上面的投入巨大,包括微软,Facebook,苹果(Siri),Google,微信,Slack.许多创业公司尝试通过多种方式来改变与消费者 ...
- 牛客练习赛39 B 选点(dfs序+LIS)
题意: 有一棵n个节点的二叉树,1为根节点,每个节点有一个值wi.现在要选出尽量多的点. 对于任意一棵子树,都要满足: 如果选了根节点的话,在这棵子树内选的其他的点都要比根节点的值大: 如果在左子树选 ...
- C/C++中的排序和查找
以下内容来自<C/C++程序设计实用案例教程> 1.排序 1.1使用qsort函数 C/C++库函数提供了快速排序函数qsort(q时quick的简写),需要引入头文件<stdlib ...