协议真的是超类的替代品吗?



我观看了WWDC15的面向协议的编程视频。看完这个视频后,我感到困惑。谁能给我一个相关的例子来说明这个想法?

更多的协议扩展是运营商重载的真正替代。

在动态类型语言(Ruby,Python,Javascript等)中,存在"鸭子类型"的概念,它本质上说,只要对象响应某些方法,对象的实际类型并不重要。而不是检查instance_of?,您可以在使用检查来确定是否可以调用方法时检查哪个更相关responds_to?

协议只是鸭子类型的正式声明。既然你要求了一个示例(代码是 Ruby,它是动态类型的——如果你不熟悉 Ruby,只需将其视为伪代码,并想象所有键入为 id 和返回值都是void):

想象一下,我们正在构建一个程序来模拟交通。我们可能有几种不同的交通方式:

class Bicycle
  def goto(x, y)
    # Implementation details
  end
end
class Car
  def goto(x, y)
    # Implementation details
  end
end
class Boat
  def goto(x, y)
    # Implementation details
  end
end
class Jetpack
  def goto(x, y)
    # Implementation details
  end
end

所有这些类都成为Vehicle父类的子类可能没有意义,因为Jetpack的属性和实现细节与Bicycle非常不同。但请注意,所有这些类都响应 goto(x, y) 方法。创建另一个也响应此方法的类(例如Helicopter)很容易。

现在假设我们正在使用以下类之一:

class Person
  def travel(vehicle, destination)
    vehicle.goto(destination.x, destination.y)
  end
end

无论vehicle是将来定义的BicycleBoat还是其他类,此代码都将起作用,因为此代码调用的是协议方法而不是类型方法

A.基本问题

想想这种情况:

您有与其他实例交互的类A实例。 A必须知道其他实例所属类的 API。有两种方法可以实现此目的:

  • 其他实例属于(可能是虚拟的)基类BA知道类B(通过导入或其他方式)。在这种情况下,A可以依靠B的能力。
  • 其他实例B实现协议,A知道协议B(通过导入或其他方式)。在这种情况下,A也可以依靠B的能力。

解决方案 1 的缺点是A指示其他实例的(基)类。这可能会导致一个问题:首先,基类B不适合。此外,也许B应该充当许多类的"助手",而不仅仅是A。这将导致多重继承。不,不,不,没有人想要这样。

多协议实现没有问题。

B. 子类化与委托+协议作为专业化的模式

在许多情况下,您会发现一个基类A,出于某些原因(即数据访问和提供)应该专门化。在基于类的编程语言中,您将找到一个(虚拟)基类A并对其进行子类化。除了A)下讨论的问题之外,您还会发现其他一些问题:

    子类
  • 是白盒:子类比其他类知道得更多。
  • 基类包含许多方法。应该覆盖的方法集是什么?
使用协议(

和委托),您可以更改它:每当基类想要专用化时,它都会将方法放入协议中,并在需要专用信息时"调用"实现协议的实例(向该协议的实现者发送消息)。另一个类可以(可选)实现此协议并充当专用器。

这称为委托,使用协议实现并替换子类。

三.更抽象

你可以用更抽象的方式看到这一点:

  • 协议声明一组方法,一个API。
  • 类声明一组方法、一个 API,实现它们。

因此,两者之间的区别在于类是实现器。

所以有一个经验法则:如果你关心实现某些东西,请使用子类,因为你可以从基类继承很多代码。如果您关心声明 API,请选择一个协议(并在类而不是子类中实现它)。

最新更新