Swift 2中的面向协议的编程

介绍

随着Swift 2的发布,Apple在Swift编程语言中添加了一系列新功能。 但是,最重要的一项是对协议进行全面检查。 Swift协议提供的改进功能允许一种新型的编程,即面向协议的编程。 这与我们许多人习惯的更为常见的面向对象的编程风格形成鲜明对比。

在本教程中,我将向您展示Swift中面向协议编程的基础知识以及它与面向对象编程的区别。

先决条件

本教程要求您正在运行Xcode 7或更高版本,其中包括对Swift编程语言的版本2的支持。

1.协议基础

如果您还不熟悉协议,则可以使用它们来扩展现有类或结构的功能。 可以将协议视为定义了一组属性和方法的蓝图或接口。 需要使用符合协议的类或结构来分别用值和实现填充这些属性和方法。

还应该注意,这些属性和方法中的任何一个都可以指定为可选的,这意味着实现它们不需要符合类型。 Swift中的协议定义和类一致性可能看起来像这样:

protocol Welcome {
    var welcomeMessage: String { get set }
    optional func welcome()
}

class Welcomer: Welcome {
    var welcomeMessage = "Hello World!"
    func welcome() {
        print(welcomeMessage)
    }
}

2.一个例子

首先,打开Xcode并为iOS或OS X创建一个新的Playground。一旦Xcode创建了Playground,请将其内容替换为以下内容:

protocol Drivable {
    var topSpeed: Int { get }
}

protocol Reversible {
    var reverseSpeed: Int { get }
}

protocol Transport {
    var seatCount: Int { get }
}

我们定义了三个协议,每个协议包含一个属性。 接下来,我们创建一个符合这三个协议的结构。 将以下代码添加到游乐场:

struct Car: Drivable, Reversible, Transport {
    var topSpeed = 150
    var reverseSpeed = 20
    var seatCount = 5
}

您可能已经注意到,我们没有创建符合这些协议的类,而是创建了一个结构。 我们这样做是为了避免面向对象编程固有的典型问题之一,即对象引用

例如,假设您有两个对象A和B。A自己创建一些数据并保留对该数据的引用。 然后,A通过引用与B共享此数据,这意味着两个对象都引用了同一对象。 在A不知道的情况下,B以某种方式更改了数据。

虽然这似乎不是一个大问题,但可能是A没想到数据会被更改。 对象A可能会找到不知道如何处理或处理的数据。 这是对象引用的常见风险。

在Swift中,结构是通过而不是通过引用传递的。 这意味着,在以上示例中,如果将A创建的数据打包为结构而不是对象打包并与B共享,则将复制数据而不是通过引用共享。 然后,这将导致A和B都拥有它们自己相同数据的唯一副本。 B所做的更改不会影响A管理的副本。

DrivableReversibleTransport组件分解为单独的协议,与传统的类继承相比,还可以提供更高级别的自定义。 如果您已经阅读了有关 iOS 9中新GameplayKit框架的第一篇教程 ,那么这种面向协议的模型与GameplayKit框架中使用的Entities and Components结构非常相似。

通过采用这种方法,自定义数据类型可以从多个源而不是单个超类继承功能。 记住到目前为止的内容,我们可以创建以下类:

  • 具有DrivableReversible协议的组件的类
  • 具有DrivableTransportable协议的组件的类
  • 具有Reversible和可Transportable协议的组件的类

对于面向对象的编程,创建这三个类的最合乎逻辑的方法是从一个包含所有三个协议的组件的超类继承。 但是,这种方法导致超类比需要的更加复杂,并且每个子类都继承了比其需要更多的功能。

3.协议扩展

自2014年发布以来,到目前为止,我向您展示的所有内容都可以在Swift中实现。这些相同的面向协议的概念甚至可以应用于Objective-C协议。 由于以前在协议上存在局限性,因此只有在第2版的Swift语言中添加了许多关键功能之后,才可能进行真正的面向协议的编程。其中最重要的功能之一是协议扩展 ,包括条件扩展

首先,让我们扩展Drivable协议并添加一个函数,以确定特定的Drivable是否比另一个Drivable更快。 将以下内容添加到您的游乐场:

extension Drivable {
    func isFasterThan(item: Drivable) -> Bool {
        return self.topSpeed > item.topSpeed
    }
}

let sedan = Car()
let sportsCar = Car(topSpeed: 250, reverseSpeed: 25, seatCount: 2)

sedan.isFasterThan(sportsCar)

您可以看到,执行操场的代码时,它输出的值为false   因为您的sedan的默认topSpeed150 ,小于sportsCar

扩展输出

您可能已经注意到,我们提供了函数定义而不是函数声明 。 这似乎很奇怪,因为协议仅应包含声明。 对? 这是Swift 2中默认行为的协议扩展的另一个非常重要的功能。 通过扩展协议,您可以为函数和计算的属性提供默认实现,从而不必遵守协议的类。

接下来,我们将定义另一个Drivable协议扩展,但是这次我们只为也符合Reversible协议的值类型定义它。 然后,此扩展程序将包含一个函数,该函数确定哪个对象具有更好的速度范围。 我们可以通过以下代码实现:

extension Drivable where Self: Reversible {
    func hasLargerRangeThan(item: Self) -> Bool {
        return (self.topSpeed + self.reverseSpeed) > (item.topSpeed + item.reverseSpeed)
    }
}

sportsCar.hasLargerRangeThan(sedan)

Self关键字(大写字母“ S”)用于表示符合协议的类或结构。 在上面的示例中, Self关键字表示Car结构。

运行操场的代码后,Xcode将在右侧的侧栏中输出结果,如下所示。 请注意, sportsCarsedan距离更大。

条件扩展输出

4.使用Swift标准库

虽然定义和扩展自己的协议可能非常有用,但在使用Swift标准库时,协议扩展的真正功能就可以显示出来。 这使您可以向现有协议添加属性或函数,例如CollectionType (用于数组和字典等)和Equatable (能够确定两个对象何时相等)。 使用条件协议扩展,您还可以为符合协议的特定对象类型提供非常特定的功能。

在我们的操场上,我们将扩展CollectionType协议并创建两种方法,一种用于获取Car数组中汽车的平均最高速度,另一种用于平均倒车速度。 将以下代码添加到您的游乐场:

extension CollectionType where Self.Generator.Element: Drivable {
    func averageTopSpeed() -> Int {
        var total = 0, count = 0
        for item in self {
            total += item.topSpeed
            count++
        }
        return (total/count)
    }
}

func averageReverseSpeed<T: CollectionType where T.Generator.Element: Reversible>(items: T) -> Int {
    var total = 0, count = 0
    for item in items {
        total += item.reverseSpeed
        count++
    }
    return (total/count)
}

let cars = [Car(), sedan, sportsCar]
cars.averageTopSpeed()
averageReverseSpeed(cars)

定义averageTopSpeed方法的协议扩展利用了Swift 2中的条件扩展。相比之下,我们直接在下面定义的averageReverseSpeed函数是利用Swift泛型实现相似结果的另一种方法。 我个人更喜欢看上去更干净的CollectionType协议扩展,但这取决于个人喜好。

在这两个函数中,我们遍历数组,将总数相加,然后返回平均值。 请注意,我们手动对数组中的项目进行计数,因为当使用CollectionType而不是常规Array类型的项目时, count属性是Self.Index.Distance类型的值,而不是Int

一旦操场执行完所有这些代码,您应该会看到输出平均最高速度183和平均反向速度21

标准库扩展

5.班级的重要性

尽管面向协议的编程是一种在Swift中管理代码的非常有效且可扩展的方式,但是在Swift中进行开发时仍然有使用类的完全合理的理由:

向后兼容

大多数iOS,watchOS和tvOS SDK都是使用面向对象的方法用Objective-C编写的。 如果需要与这些SDK中包含的任何API进行交互,则必须使用这些SDK中定义的类。

引用外部文件或项目

Swift编译器根据对象的使用时间和位置来优化它们的生命周期。 基于类的对象的稳定性意味着您对其他文件和项目的引用将保持一致。

对象引用

有时,对象引用正是您所需要的,例如,如果您要将信息馈入特定对象(例如图形渲染器)中。 在此类情况下,使用具有隐式共享的类非常重要,因为您需要确保将数据发送到的渲染器仍与以前的渲染器相同。

结论

希望在本教程结束时,您可以看到Swift中面向协议编程的潜力以及如何将其用于简化和扩展代码。 尽管这种新的编码方法不会完全替代面向对象的编程,但确实带来了许多非常有用的新可能性。

从默认行为到协议扩展,Swift中面向协议的编程将被许多未来的API所采用,并将完全改变我们对软件开发的思考方式。

与往常一样,请务必在下面的评论中留下您的评论和反馈。

翻译自: https://code.tutsplus.com/tutorials/protocol-oriented-programming-in-swift-2--cms-24979

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Swift面向协议编程(Protocol-Oriented Programming,简称POP)是Swift编程语言的一个重要特性。使用POP的主要场景包括: 1. 代码复用:使用协议可以将某些功能抽象成一个独立的模块,并使多个不同的类或结构体共享该模块的功能。 2. 增强类型安全:Swift是一种类型安全的编程语言,POP进一步提高了类型安全性,因为它强制规定每个类型都必须遵循相应的协议。 3. 扩展性:使用协议可以轻松地向现有类型添加功能。例如,可以通过扩展一个实现了某个协议的类型来实现对该类型的功能扩展。 4. 网络编程协议可以用于定义网络通信协议,例如TCP、UDP、HTTP等,方便网络编程。 5. 泛型编程Swift的泛型编程和POP密切相关。通过将协议作为类型参数传递,可以实现更灵活的泛型编程。 总之,使用POP可以提高代码的可读性、可维护性和可扩展性,同时也可以使代码更加清晰、简洁、易于测试和优化。 ### 回答2: Swift面向协议编程是一种软件开发方法论,它通过协议来定义一组需要实现的属性、方法和功能,实现了代码的模块化和复用,以及降低代码的耦合度。下面介绍一些Swift面向协议编程的使用场景。 1. 标准化和扩展:通过定义协议,可以规范一组对象需要实现的共同属性和方法。这样,不同的对象可以用相同的方式进行处理和操作,提高代码的可读性和维护性。另外,如果需要为已有类型添加新的功能,可以通过扩展协议来实现,而不需要修改原有的类型。 2. 运行时多态:Swift协议支持多继承,一个类型可以遵循多个协议。通过协议,可以实现运行时的多态,将不同的实现绑定到相同的协议类型上。这可以使得代码更加灵活,能够适应不同的场景和需求。 3. 依赖注入和测试驱动开发:面向协议编程可以方便地进行依赖注入,通过将依赖关系抽象为协议,可以在不同的环境进行替换。这对于测试驱动开发非常有用,可以提高代码的测试性和可测性。 4. UI 组件定制化:通过定义协议,可以将UI组件的定制化能力下放给使用者。例如,定义一个可定制的协议,使用者可以实现该协议,来定制按钮的外观、动画等。这种方式可以提高代码的重用性,同时也增加了代码的灵活性。 总之,Swift面向协议编程提供了一种模块化、可扩展和可定制化的开发方式,适用于各种需要代码复用和灵活性的场景,特别是在项目需要多态、依赖注入和定制化的情况下,面向协议编程可以发挥出其优势。 ### 回答3: Swift面向协议编程是一种重要的编程范式,它可以应用于许多不同的场景。以下是几个常见的使用场景: 1. 模块化和组件化:使用协议定义接口和方法,可以实现模块化和组件化的开发方式。不同的组件可以通过实现相同的协议来进行交互,降低了代码的耦合度,增加了代码的可复用性和可维护性。 2. 单元测试:使用协议可以将被测试的类与测试类进行解耦。通过实现相同的协议,可以用一个模拟的类来替代真实的类进行测试,从而更容易编写和执行单元测试。 3. 多继承:Swift不支持多继承,但是可以通过协议来实现类似的功能。一个类可以同时遵循多个协议,从而获取不同协议的功能和属性。这种方式可以在不引入类层次的情况下实现代码的复用。 4. 适配不同平台和框架:在跨平台开发和使用不同框架的情况下,使用协议可以更好地适应不同的平台和框架。通过定义统一的协议,不同的平台和框架可以通过实现这个协议来进行交互和兼容。 5. 插件系统:在一些应用程序,可能希望用户可以编写自己的插件来扩展应用的功能。使用协议可以定义插件接口,插件通过实现这个协议来与应用进行交互和扩展。 总之,Swift面向协议编程广泛应用于软件开发。它可以提高代码的可复用性、可扩展性和可维护性,同时也能够促进模块化开发和解耦。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值