协议与面向对象编程入门指南

这篇文章的目的是比较面向对象编程和面向协议编程在使用两种方法建模相同功能时的一些差异。面向对象的编程从20世纪70年代就已经出现了,而面向协议的编程直到最近几年才流行起来,尽管协议/接口已经出现了一段时间。这篇文章的目的不是要在这些体系结构中选出一个赢家,而是试图帮助您为您将要从事的项目类型选择最佳的解决方案。
面向对象编程
面向对象的编程范式是基于一个“对象”的概念,这在大多数编程语言定义的数据结构(例如类),其中包含的信息属性的属性,和执行的操作或一个对象的方法。这个范例允许我们将对象的属性和动作封装到一个单独的类型中,即我们试图在代码中表示的实体。
让我们创建一个基本的类图,展示如何为面向对象的设计设计一个动物类层次结构。

这张图显示我们有一个超类动物并命名了三个子类猫,鸟,和鱼,它将从超类继承所有的内部和公共属性和方法。
假设我们要开发一个电子宠物我们可以使用以下要求创造动物的游戏类型:
- 我们有三种不同的动物类别(陆地、空气和水)。
- 一个动物可以是多个类别的成员。
让我们从面向对象的设计开始:
- 创建一个AnimalEnvironment将被用来确定动物可以生存的地方的枚举。
- 创建一个动物超类,它将包含动物的所有属性。前三个属性是一个数组AnimalEnvironment动物的名字和年龄。其他三个属性将包含动物在每个环境下的速度。
- 创造方法,前三种方法是用来让我们的动物锻炼和燃烧卡路里,其他三种方法是让我们知道动物能做什么。
现在,让我们看看如何子类化动物类的猫,鸟,鱼在我们的图表中定义的类。
的猫、鸟和鱼类是动物类,然后我们通过为每个类创建一个初始化器来开始这些类。为猫子类,例如,我们指定动物环境是.land,和空速和waterSpeed是零因为猫无法在那种环境中生存。我们还覆盖了属于每个动物的函数,并添加了它们的实现。
正如您所看到的,来自超类的所有信息都公开给子类,即使不是所有的子类都需要所有的超类信息。很容易想象这样一种场景:越来越多的代码开始被添加到超类中,并且它变得更加难以维护。即使是最有经验的开发人员,也很容易在数组或速度属性中输入错误的值,从而导致意想不到的行为。
好处
- 通过继承实现代码的可重用性。
- 多态性的灵活性。
- 封装。
缺点
- Swift是一种单一的继承语言,对于动物类我们只能有一个超类,这个超类将需要包含三个类别中每一个所需的代码。
- 类型不需要的功能的继承。它可能导致臃肿的超类,因为我们可能需要包含只有少数子类需要的功能。
- 我们不能在超类中创建可以由子类设置的常量。
- 在Swift中,值类型不能使用继承,只能使用引用类型。
- 突破的机会太阳能发电(Liskov代换原则)如果设计不好。
Protocol-Oriented编程
与面向对象的设计一样,让我们创建一个图表,展示如何以面向协议的方式设计动物类型。

正如我们所看到的,面向协议的设计侧重于实现一个关注需求而不是面向对象设计中所设计的细节的协议。这是个很好的例子ISP(接口隔离原则),客户端不需要知道他们不使用的属性和方法,并且浸(依赖倒置原则),即设计依赖于抽象而不是具体。
让我们开始面向协议的设计:
- 创建一个动物包含其他协议可以利用的共享需求的协议。
- 创建一个陆地动物,空气动物和水动物协议,这些协议都将从动物协议,并为它们每个添加一个速度属性。
该图向我们展示了协议使用的两种技术:
协议继承:当一个协议可以从一个或多个协议继承需求时。这类似于面向对象编程中的类继承,但不是继承功能,而是继承需求。
协议构成:它允许类型遵循多个协议,我们可以在鸟结构。这在面向对象编程中也是可以实现的,在面向对象编程中,类可以有一个或没有继承,但遵循多个协议。
重要的是要注意,任何类型符合动物协议,或任何符合从动物协议中,将自动拥有访问的属性和方法。
现在,让我们看看如何实现猫,鸟,鱼图中定义的结构。正如我们所看到的,面向协议的设计只暴露了每个动物的必要需求,这是分离关注点的一个很好的例子。另外,没有必要创建自定义初始化项,因为这里我们使用的是结构体而不是类.
让我们也实现缺少的方法canRun,canFly,和canSwim就像我们在面向对象的设计中所做的那样,但这一次让我们扩展动物协议提供的方法使我们能够为所有符合类型提供公共实现。
注意,在Swift中,我们使用是关键字来检查实例是否具有特定类型,并且作为关键字将实例视为特定类型。如你所见,我们的猫结构可以访问所有的方法。
面向对象和面向协议的设计都为我们提供了使用多态性的能力,这是一个用于多种类型的单一接口。让我们看看这两种设计的效果。
正如您所看到的,在面向对象的设计中,这两种方法的多态处理看起来完全相同动物是否是一个超类并且是在面向协议的设计中动物是一个协议。
好处
- 面向协议的设计允许我们使用类、结构和枚举。
- 我们可以使用协议扩展来向符合协议的类型添加功能。
- 能够将任何属性定义为常量。
- 协议组合允许数据结构实现多种需求。
- 当与泛型结合使用时,协议变得非常强大。
- 更干净的代码。
- 更容易发现错误。
缺点
- 协议继承和协议扩展的滥用可能会导致一个复杂的系统。
结论
正如您所看到的,我们能够使用这两种范式(面向对象的编程和面向协议的编程)实现相同的目标。在一天结束的时候,正确地设计您的体系结构将为您提供一个可靠和稳定的系统,与您选择使用的方法无关。尽量收集您将从事的项目的所有需求,在纸上设计它,然后考虑哪种范式更适合您。
最初发表在https://tech.188bet金宝搏官网okcupid.com2020年10月30日。