0%

34、面向对象-多态.md

一、前提概要

Python是否支持多态的问题争论已久,在面向对象语言中,有三大特性(封装 继承 多态)Python作为典型的面向对象语言,怎么可能会不支持多态呢?

产生这个问题的原因在于Python是一门动态编程语言,在运行的时候可以更改自己的结构。在java等面向对象语言中,定义一个变量,强制要求首先声明他的数据类型;而在Python中,这个步骤是完全可以忽略的。由于Python动态语言的特性,Python天生就支持多态,不需要像其他面向对象的语言那样使用了多态语法来实现多态的特性。大家争论Python是否支持多态,其实都是纠结在Python没有多态的语法。

  • 在Java中,如果一个变量被声明是int类型,如果被赋值为一个字符串对象,那一定会报错。在像Java这种强类型的语言中,一个变量被声明数据类型时候,只允许被这个类或这个类的派生类赋值。
  • 而在Python中,声明一个变量,你可以给他赋任何类型的值(对象)

多态可以简单的理解为多种形态,多种类型。在Python中,不需要特殊的多态语法来实现多态的特性

不管Python支不支持多态其实对我们普通的程序员并不是那么重要,关键还是要看能不能解决我解决我们在世界开发中的一些问题。套用一句广告词,广告好不好不重要,关键看疗效!!!

二、多态

1、概念

面向对象程序设计最有趣的特性是多态,它是是让大多数人犯晕的特性。多态意思是有多种形式。指的是一类事物有多种形态。

例如:

  1. 动物有多种形态:鼠,牛,虎,兔,猪,狗,牛,羊,
  2. 序列类型有多种形态:字符串,列表,元组

注: 在静态语言里多态的概念依赖于继承

2、举个栗子

  1. 栗子1

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    class Animal(object): #在定义角度来讲
    def __init__(self, name):
    self.name = name
    def talk(self):
    raise NotImplementedError("Subclass must implement abstract method")

    class Cat(Animal):#动物形态1 猫
    pass
    class Dog(Animal):#动物形态2 狗
    pass
    class Duck(Animal):
    pass
  2. 栗子2

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    class File(): #同一类事物:文件
    def click(self):
    pass
    class Text(File): #文件的形态之一:文本文件
    def click(self):
    pass
    class ExeFile(File): #文件的形态之二:可执行文件
    def click(self):
    pass
    class ImageFile(File): #文件的形态之二:图片形式的文件
    def click(self):
    pass

三、鸭子类型

1、概念

python是一种动态语言,崇尚鸭子类型。以下是维基百科中对鸭子类型得论述

在程序设计中,鸭子类型(英语:duck typing)是动态类型的一种风格。在这种风格中,一个对象有效的语义,不是由继承自特定的类或实现特定的接口,而是由当前方法和属性的集合决定。这个概念的名字来源于由James Whitcomb Riley提出的鸭子测试,“鸭子测试”可以这样表述:“当看到一只鸟走起来像鸭子、游泳起来像鸭子、叫起来也像鸭子,那么这只鸟就可以被称为鸭子。”
在鸭子类型中,关注的不是对象的类型本身,而是它是如何使用的。例如,在不使用鸭子类型的语言中,我们可以编写一个函数,它接受一个类型为鸭的对象,并调用它的走和叫方法。在使用鸭子类型的语言中,这样的一个函数可以接受一个任意类型的对象,并调用它的走和叫方法。如果这些需要被调用的方法不存在,那么将引发一个运行时错误。任何拥有这样的正确的走和叫方法的对象都可被函数接受的这种行为引出了以上表述,这种决定类型的方式因此得名。
鸭子类型通常得益于不测试方法和函数中参数的类型,而是依赖文档、清晰的代码和测试来确保正确使用。从静态类型语言转向动态类型语言的用户通常试图添加一些静态的(在运行之前的)类型检查,从而影响了鸭子类型的益处和可伸缩性,并约束了语言的动态特性。

2、举个栗子

  1. 栗子

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    class Bird(object):
    def walk(self):
    pass
    def swimming(self):
    pass

    class Duck(Bird):
    def walk(self):
    print('鸭子大摇大摆的走着!!!')
    def swimming(self):
    print('鸭子悠闲的在水里游着!!!')

    class Goose(Bird):
    def walk(self):
    print('鸭子大摇大摆的走着!!!')
    def swimming(self):
    print('鸭子悠闲的在水里游着!!!')

    class Person(object):
    def __init__(self, name):
    self.name = name
    def walk(self):
    print(self.name + '大摇大摆的走着!!!')
    def swimming(self):
    print(self.name + '悠闲的在水里游着!!!')

    class Test:
    @staticmethod
    def walk(animal):
    animal.walk()
    @staticmethod
    def swimming(animal):
    animal.swiming()
    if __name__ == '__main__':
    duck = Duck()
    person = Person('小明')
    Test.walk(duck)
    Test.walk(person)

    说明:

    这就是动态语言的“鸭子类型”,它并不要求严格的继承体系,一个对象只要“看起来像鸭子,走起路来像鸭子”,那它就可以被看做是鸭子。

    静态语言和动态语言

    • 对于静态语言(例如Java)来说,如果需要传入Animal类型,则传入的对象必须是Animal类型或者它的子类,否则,将无法调用walk()`方法。
  • 对于Python这样的动态语言来说,则不一定需要传入Animal类型。我们只需要保证传入的对象有一个walk()方法就可以了

鸭子类型通常得益于不检测方法和函数中参数的类型,而是依赖文档、清晰的代码和测试来确保正确使用。

四、多态性

1、概念

多态性是指具有不同功能的函数可以使用相同的函数名,这样就可以用一个函数名调用不同内容的函数。在面向对象方法中一般是这样表述多态性:向不同的对象发送同一条消息,不同的对象在接收时会产生不同的行为(即方法)。也就是说,每个对象可以用自己的方式去响应共同的消息。所谓消息,就是调用函数,不同的行为就是指不同的实现,即执行不同的函数。

多态意味着就算不知道变量所引用的对象类是什么

通俗的来讲可对不同类的对象使用同样的操作

2、举个栗子

  1. 栗子

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    class Bird(object):
    def walk(self):
    pass
    def swimming(self):
    pass
    class Duck(Bird):
    def walk(self):
    print('鸭子大摇大摆的走着!!!')
    def swimming(self):
    print('鸭子悠闲的在水里游着!!!')
    class Goose(Bird):
    def walk(self):
    print('鸭子大摇大摆的走着!!!')

    def swimming(self):
    print('鸭子悠闲的在水里游着!!!')
    class Person(object):
    def __init__(self, name):
    self.name = name
    def walk(self):
    print(self.name + '大摇大摆的走着!!!')
    def swimming(self):
    print(self.name + '悠闲的在水里游着!!!')
    class Test:
    @staticmethod
    def walk(animal):
    animal.walk()
    @staticmethod
    def swimming(animal):
    animal.swiming()
    if __name__ == '__main__':
    duck = Duck()
    person = Person('小明')
    Test.walk(duck)
    Test.walk(person)

3、为什么要用多态性

  1. 可替换性(substitutability)。多态对已存在代码具有可替换性。

  2. 可扩充性(extensibility)。多态对代码具有可扩充性。增加新的子类不影响已存在类的多态性、继承性,以及其他特性的运行和操作。实际上新加子类更容易获得多态功能

    软件设计原则中的 “开闭”原则:

    1. 对扩展开放:允许新增Animal子类;
    2. 对修改封闭:不需要修改依赖Animal类型的等函数。
  3. 灵活性(flexibility)。它在应用中体现了灵活多样的操作,提高了使用效率。

  4. 简化性(simplicity)。多态简化对应用软件的代码编写和修改过程,尤其在处理大量对象的运算和操作时,这个特点尤为突出和重要。