【5.1】Python面向对象之抽象类

【一】什么是接口

【1】IAnimal.java

  • Java 语言中的接口很好的展现了接口的含义: IAnimal.java

  • Java的Interface接口的特征

    • 是一组功能的集合,而不是一个功能

    • 接口的功能用于交互,所有的功能都是public,即别的对象可操作

    • 接口只定义函数,但不涉及函数实现

    • 这些功能是相关的,都是动物相关的功能,但光合作用就不适宜放到IAnimal里面了

package com.oo.demo;
public interface IAnimal {
    public void eat();
    public void run(); 
    public void sleep(); 
    public void speak();
}

【2】Pig.java

  • Pig.java:猪的类设计,实现了IAnnimal接口
package com.oo.demo;
public class Pig implements IAnimal{ //如下每个函数都需要详细实现
    public void eat(){
        System.out.println("Pig like to eat grass");
    }

    public void run(){
        System.out.println("Pig run: front legs, back legs");
    }

    public void sleep(){
        System.out.println("Pig sleep 16 hours every day");
    }

    public void speak(){
        System.out.println("Pig can not speak"); }
}

【3】Person2.java

  • 实现了IAnimal的“人”,有几点说明一下
    • 同样都实现了IAnimal的接口,但“人”和“猪”的实现不一样,为了避免太多代码导致影响阅读,这里的代码简化成一行,但输出的内容不一样,实际项目中同一接口的同一功能点,不同的类实现完全不一样
    • 这里同样是“人”这个类,但和前面介绍类时给的类“Person”完全不一样,这是因为同样的逻辑概念,在不同的应用场景下,具备的属性和功能是完全不一样的
package com.oo.demo;
public class Person2 implements IAnimal { 
    public void eat(){
        System.out.println("Person like to eat meat");
    }

    public void run(){
        System.out.println("Person run: left leg, right leg");
    }

    public void sleep(){
        System.out.println("Person sleep 8 hours every dat"); 
    }

    public void speak(){
        System.out.println("Hellow world, I am a person");
    } 
}

【4】Tester03.java

package com.oo.demo;

public class Tester03 {
    public static void main(String[] args) {
        System.out.println("===This is a person==="); 
        IAnimal person = new Person2();
        person.eat();
        person.run();
        person.sleep();
        person.speak();
        
        System.out.println("\n===This is a pig===");
        IAnimal pig = new Pig();
        pig.eat();
        pig.run();
        pig.sleep();
        pig.speak();
    } 
}

【5】小结

  • PS:hi boy,给我开个查询接口。。。此时的接口指的是:自己提供给使用者来调用自己功能的方式\方法\入口

【二】为何要用接口

  • 接口提取了一群类共同的函数,可以把接口当做一个函数的集合。

  • 然后让子类去实现接口中的函数。

  • 这么做的意义在于归一化,什么叫归一化,就是只要是基于同一个接口实现的类,那么所有的这些类产生的对象在使用时,从用法上来说都一样。

  • 归一化的好处

    • 归一化让使用者无需关心对象的类是什么,只需要的知道这些对象都具备某些功能就可以了,这极大地降低了使用者的使用难度
    • 归一化使得高层的外部使用者可以不加区分的处理所有接口兼容的对象集合
      • 就好象linux的泛文件概念一样,所有东西都可以当文件处理,不必关心它是内存、磁盘、网络还是屏幕(当然,对底层设计者,当然也可以区分出“字符设备”和“块设备”,然后做出针对性的设计:细致到什么程度,视需求而定)。
      • 再比如:我们有一个汽车接口,里面定义了汽车所有的功能,然后由本田汽车的类,奥迪汽车的类,大众汽车的类,他们都实现了汽车接口,这样就好办了,大家只需要学会了怎么开汽车,那么无论是本田,还是奥迪,还是大众我们都会开了,开的时候根本无需关心我开的是哪一类车,操作手法(函数调用)都一样

【三】模仿interface

【1】继承的两种用途

  • 继承基类的方法,并且做出自己的改变或者扩展(代码重用):实践中,继承的这种用途意义并不很大,甚至常常是有害的。因为它使得子类与基类出现强耦合。

  • 声明某个子类兼容于某基类,定义一个接口类(模仿java的Interface),接口类中定义了一些接口名(就是函数名)且并未实现接口的功能,子类继承接口类,并且实现接口中的功能

【2】代码演示

# 定义接口Interface类来模仿接口的概念,python中压根就没有interface关键字来定义一个接口。
class Interface:
    # 定接口函数read
    def read(self):
        pass

    # 定义接口函数write
    def write(self):
        pass


# 文本,具体实现read和write
class Txt(Interface):
    def read(self):
        print('文本数据的读取方法')

    def write(self):
        print('文本数据的读取方法')


# 磁盘,具体实现read和write
class Sata(Interface):
    def read(self):
        print('硬盘数据的读取方法')

    def write(self):
        print('硬盘数据的读取方法')


class Process(Interface):
    def read(self):
        print('进程数据的读取方法')

    def write(self):
        print('进程数据的读取方法')
  • 上面的代码只是看起来像接口,其实并没有起到接口的作用,子类完全可以不用去实现接口 ,这就用到了抽象类

【四】什么是抽象类

  • 与java一样,python也有抽象类的概念但是同样需要借助模块实现,抽象类是一个特殊的类,它的特殊之处在于只能被继承,不能被实例化

【五】为什么要有抽象类

  • 如果说类是从一堆对象中抽取相同的内容而来的,那么抽象类是从一堆中抽取相同的内容而来的,内容包括数据属性和函数属性。
  • 比如我们有香蕉的类,有苹果的类,有桃子的类,从这些类抽取相同的内容就是水果这个抽象的类,你吃水果时,要么是吃一个具体的香蕉,要么是吃一个具体的桃子。。。。。。你永远无法吃到一个叫做水果的东西。
  • 从设计角度去看,如果类是从现实对象抽象而来的,那么抽象类就是基于类抽象而来的。
  • 从实现角度来看,抽象类与普通类的不同之处在于:抽象类中只能有抽象方法(没有实现功能),该类不能被实例化,只能被继承,且子类必须实现抽象方法。这一点与接口有点类似,但其实是不同的,即将揭晓答案

【六】在python中实现抽象类

【0】导入模块

# 一切皆文件
# 利用abc模块实现抽象类
import abc  

【1】不重写抽象类方法

# 一切皆文件
import abc  # 利用abc模块实现抽象类


class All_file(metaclass=abc.ABCMeta):
    all_type = 'file'

    # 定义抽象方法,无需实现功能
    @abc.abstractmethod
    def read(self):
        '子类必须定义读功能'
        pass

    # 定义抽象方法,无需实现功能
    @abc.abstractmethod
    def write(self):
        '子类必须定义写功能'
        pass


class Txt(All_file):
    pass


t1 = Txt()  # 报错,子类没有定义抽象方法

r'''
Traceback (most recent call last):
  File "E:\PythonProjects\10面向对象\05组合.py", line 131, in <module>
    t1=Txt() #报错,子类没有定义抽象方法
TypeError: Can't instantiate abstract class Txt with abstract methods read, write
'''

【2】重写抽象类方法

# 一切皆文件
# 利用abc模块实现抽象类
import abc  


class All_File(metaclass=abc.ABCMeta):
    all_type = 'file'

    # 定义抽象方法,无需实现功能
    @abc.abstractmethod
    def read(self):
        '子类必须定义读功能'
        pass

    # 定义抽象方法,无需实现功能
    @abc.abstractmethod
    def write(self):
        '子类必须定义写功能'
        pass

    
# 子类继承抽象类,但是必须定义read和write方法
class Txt(All_File):
    def read(self):
        print('文本数据的读取方法')

    def write(self):
        print('文本数据的读取方法')


# 子类继承抽象类,但是必须定义read和write方法
class Sata(All_File):
    def read(self):
        print('硬盘数据的读取方法')

    def write(self):
        print('硬盘数据的读取方法')


# 子类继承抽象类,但是必须定义read和write方法
class Process(All_File):
    def read(self):
        print('进程数据的读取方法')

    def write(self):
        print('进程数据的读取方法')


test_file = Txt()

video_file = Sata()

process_file = Process()

# 这样大家都是被归一化了,也就是一切皆文件的思想
test_file.read()
video_file.write()
process_file.read()

print(test_file.all_type)
print(video_file.all_type)
print(process_file.all_type)

# 文本数据的读取方法
# 硬盘数据的读取方法
# 进程数据的读取方法
# file
# file
# file

【七】抽象类与接口

  • 抽象类的本质还是类,指的是一组类的相似性,包括数据属性(如all_type)和函数属性(如read、write),而接口只强调函数属性的相似性。
  • 抽象类是一个介于类和接口直接的一个概念,同时具备类和接口的部分特性,可以用来实现归一化设计
posted @ 2023-11-30 14:21  Chimengmeng  阅读(47)  评论(0编辑  收藏  举报
/* */