协议与面向对象编程的介绍指南

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

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

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