鸡问题(面向协议的编程)

大家好

在本文上,我们来讨论协议扩展和面向协议的编程(POP)。 关于这个主题有很多讨论,Swift协议扩展和多重继承之间有很多比较。 因此,让我们讨论两者之间的区别以及POP听起来为什么更可靠的原因。

鸡问题

我喜欢用这个例子来说明一个小问题如何变成大规模开发和实际应用。 首先让我们看一下问题,然后再讨论。

想象一下我们需要构造鸟类的“对象/实体”的应用程序。 乍一看,我们将拥有Perrots,Sparrows和Falcons。 现在,让我们为此创建一个漂亮而智能的代码。

OOP和多重继承

所有这些鸟类共享许多东西,例如“喙”,“羽毛”,并且它们都可以“飞行”。 因此,让我们考虑以下Birds App的体系结构。

看起来很棒! 在这一点上,我们作为开发人员对我们的创作感到非常自豪。 它干净,可靠,我们只编写了一次代码,只是“ fly”方法的一种实现,这是一种非常复杂的算法。

现在,我们制作了该产品的版本1 。 此时,客户(Bird应用程序的所有者)说:“嘿,您知道吗,我注意到我的客户也希望拥有Chicken,所以请向此应用程序中添加Chickens,一旦您将它变得非常简单告诉我您有一个非常灵活的体系结构与OOP一起使用”

好的,这很容易……鸡是鸟,所以它将成为鸟的一个子类……但是等等……鸡不能飞! 因此,在这一点上,我是否需要重写此“ fly()”方法,并从“ Bird”中取消我所有漂亮的算法?

等等,这样做不仅是在重写代码,但是如果我心爱的客户决定明天他将发明一种新型的能飞的超级鸡肉,我该怎么办? 将“鸡”否定为“ fly()”的新“鸡”子类?

如果我的客户决定将应用程序移至南极并创建企鹅? 企鹅没有羽毛!

OMG…我刚刚意识到我的整个体系结构对我的客户来说不够灵活! 我应该改变它吗? 我应该重写我的整个应用程序吗? 提出V2? 我应该更换我的客户吗? 我是否应该换一个鸟类完美的星球,它们都具有相同的特征?

好吧好吧让我们冷静一下 让我们尝试考虑可能的解决方案,毕竟,OOP很棒,并且确实可以反映现实世界的复杂性。

好吧,不完全是。 我们可以尝试使用OOP解决方案来奋斗。 我不会深入探讨我们可以尝试的失败解决方案:

  • 创建两个基类:“鸟”和“飞鸟”(失败:如果客户决定购买飞机怎么办?)
  • 使用协议/接口定义飞行方法(失败:重写很多代码)
  • 将“ fly()”定义为接收可以飞行的对象的静态方法(失败:如果我有数百万个飞行对象怎么办?并发,多线程)

我与数百名不同的开发人员进行了此练习,让他们尝试许多解决方案。 简而言之,在OOP中解决此问题的唯一可能解决方案是使用多重继承,但是众所周知,这很危险。 只有很少的编程语言允许这种功能,并且在其自身的实现中有许多警告。 Pearl和Python使用一个有序列表进行多重继承,Java 8尝试使用编译器来避免错误,C ++实际上是真正在其完整扩展中真正实现多重继承的唯一语言之一。

因此,如果您不想仅在应用程序中创建C ++模块来解决该问题,就让我们现在尝试使用Swift功能来解决Chicken Chicken问题。

Swift —协议扩展

简而言之,当两个或多个“对象/实体”具有某些共同特征但又完全不同时,“小鸡问题”只是软件项目中一个非常常见问题的隐喻。 尤其是在当前的移动项目场景中,与Agile合作,获得用户的不断反馈,客户每天都会更改其应用程序,这意味着在产品维护期间可能会发生很多事情。 因此,作为开发人员,我们需要构建足够灵活的体系结构以应对此类更改。

在这一点上,使用好的平台或编程语言可以帮助您摆脱那些陷阱。 到那时,Swift凭借其协议扩展功能来到了桌面。 在许多方面,它都可以与多重继承进行比较,但是没有多重继承的所有危险。 由于此Swift功能中有一个细节,称为默认实现。 这意味着我们可以为协议属性和方法提供默认实现。

 协议MyProtocol { 
func methodOnProtocol()
}
MyProtocol扩展名{
func methodOnProtocol(){
print(“ \(#function)的默认实现”)
}
func newMethodOnExtension(){
print(“ \(#function)的默认实现”)
}
}

知道了这一点,我们可以回到“鸡问题”并将其重写,以使我们只编写一次代码,仍然可以满足Birds的所有特定需求。

看看这有多灵活。 鸟仍然可以是超一流的,不用担心。 但是“ fly()”和“羽毛”成为具有默认实现的协议。 这意味着我们只需编写一次代码,就可以编写各种鸟类,而无需重写任何代码。

请注意,即使我们的客户发疯说:“您知道吗,我的Birds应用程序知道需要飞机,风筝和各种飞行物体!” 不用担心,我们构建的体系结构足够灵活,可以解决这一问题,因为现在,我们不再需要像多态方法(更具体地讲是子类型化多态)中的单个层次结构链那样工作,我们现在可以自由自在地考虑使用Lego块。

面向协议的编程(POP)

协议扩展是一个新功能,非常强大,我们尚不知道是否会充分使用它,是的,它涉及一些警告。 为了控制该技术,我们必须进行大量练习。 在某些方面看起来像多重继承,但更为复杂。

有史以来最好的WWDC视频之一是Crusty视频,Apple解释了什么是协议扩展和面向协议的编程。 我强烈建议您观看此视频:
https://developer.apple.com/videos/play/wwdc2015/408/

从OOP到POP的思维模式需要“信念的飞跃”,我们可能会发现自己尝试使用OOP解决问题,深吸一口气,从一开始就尝试将其视为POP,尝试使用POP创建架构在开始编码之前。

结论

鸡不会飞,因此“鸡问题”代表软件开发中的一个常见问题,即对象/实体开始共享相同的功能,但是在某些时候它们开始分化,成为一个完全不同的实体。

在这一点上,传统的多态性及其单一继承链已无济于事。 因此,在这一点上,我们需要变得聪明,并使用诸如协议扩展之类的功能并将思维方式更改为面向协议的编程可以极大地帮助创建更灵活的体系结构,并避免因为客户端添加了意外功能而重构整个应用程序。

这就是当今敏捷世界的方式,我们必须快速适应和改变,尤其是在移动软件开发领域。

ya