概述
多态(
Polymorphism
)按字面的意思就是"多种状态"
. 在面向对象语言中, 接口的多种不同的实现方式
即为多态. 多态性是允许你将父对象设置成为一个或更多的他的子对象相等的技术, 赋值之后, 父对象就可以根据当前赋值给它的子对象的特性以不同的方式运作. 简单的说, 就是一句话: 允许将子类类型的指针赋值给父类类型的指针. 多态性在Object Pascal和C++中都是通过虚函数实现的.
多太是单一接口接受不同类型的技术. 根本上, 它允许不同的数据类型适用于相同的函数. 不同类型的
相同函数形态完成相同的行为
. Elixir 适用协议(Protocols
)实现多太.
下面以一个温度的不同表示形式来说明如何在开发过程中使用多太.
# 开尔文
defmodule Kelvin do
defstruct name: "Kelvin", symbol: "K", degree: 0
end
# 华氏温度
defmodule Fahrenheit do
defstruct name: "Fahrenheit", symbol: "°F", degree: 0
end
# 摄氏温度
defmodule Celsius do
defstruct name: "Celsius", symbol: "°C", degree: 0
end
# 温度协议(接口, 只有函数定义, 没有函数实现)
defprotocol Temperature do
@doc """
Convert Kelvin and Fahrenheit to Celsius degree
"""
def to_celsius(degree)
end
# 开尔文, 实现了Temperature 协议(接口)
defimpl Temperature, for: Kelvin do
@doc """
Deduct 273.15
"""
def to_celsius(kelvin) do
celsius_degree = kelvin.degree - 273.15
%Celsius{degree: celsius_degree}
end
end
# 华氏摄氏度实现
defimpl Temperature, for: Fahrenheit do
@doc """
Deduct 32, then multiply by 5, then divide by 9
"""
def to_celsius(fahrenheit) do
celsius_degree = (fahrenheit.degree - 32) * 5 / 9
%Celsius{degree: celsius_degree}
end
end
下面是实际的运行结果
iex> fahrenheit = %Fahrenheit{degree: 45}
%Fahrenheit{degree: 45, name: "Fahrenheit", symbol: "°F"}
iex> celsius = Temperature.to_celsius(fahrenheit)
%Celsius{degree: 7.22, name: "Celsius", symbol: "°C"}
iex> kelvin = %Kelvin{degree: 300}
%Kelvin{degree: 300, name: "Kelvin", symbol: "K"}
iex> celsius = Temperature.to_celsius(kelvin)
%Celsius{degree: 26.85, name: "Celsius", symbol: "°C"}
上面的代码, 并没有实现摄氏温度模块. 你可以试着自己实现.
iex> Temperature.to_celsius(%{degree: 12})
** (Protocol.UndefinedError) protocol Temperature not implemented for %{degree: 12}
iex:11: Temperature.impl_for!/1
iex:15: Temperature.to_celsius/1
如果想深入了解Elixir的多态, 可以参考Elixir内置模块 String.Char 和 Enum 的实现.
通过阅读 Enum 模块的源码, 你可以了解到, Enum 模块是如何处理不同的数据类型的.
结论
多态本质上是一种运行时动态技术, 可以想象一下变量的概念, 如果编程语言中没有变量(多态, 接口), 只有常量(具体实现类), 那编程会是一种什么样的体验?
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。