[Python学习日记-65] 抽象类
简介
抽象类是由继承演变而来的,他可以很好的规范子类当中的统一函数属性,在不同的语言当中也会有类似的用法,下面我们会先讲讲什么是接口与归一化设计,然后再介绍什么是抽象类,我们在 Python 当中应该如何使用抽象类来帮助我们规范化子类的开发。
接口与归一化设计
一、什么是接口
接口是一个定义了一组方法的抽象类型,这些方法在接口中声明但没有具体实现。接口可以被其他类实现,实现类必须提供接口中定义的所有方法。接口可以用来定义一些规范或约束,让不同的类实现相同的行为。
在开发过程中可能你会听到你的同事会经常说给他开个什么什么接口之类的话语,例如开个查询接口之类的,此时的接口指的就是自己提供给使用者来调用自己功能的方式\方法\入
口,在 java 中的 interface 就是如此,它是这样使用的
==========第一部分:Java 语言中的接口很好的展现了接口的含义:IAnimal.java
/*
* Java 的 Interface 接口的特征:
* 1)是一组功能的集合,而不是一个功能
* 2)接口的功能用于交互,所有的功能都是 public,即别的对象可操作
* 3)接口只定义函数,但不涉及函数实现
* 4)这些功能是相关的,都是动物相关的功能,但光合作用就不适置放到 IAnimal 里面了 */
package com.oo.demo;
public interface IAnimal{
public void eat();
public void run();
public void sleep();
public void speak();
}
==========第二部分:Pig.java “猪”的类设计,实现了 IAnimal 接口
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 leg, back leg");
}
public void sleep(){
System.out.println("Pig sleep 16 hours every day");
}
public void speak(){
System.out.println("Pig can't speak");
}
}
==========第三部分:Person.java
/*
* 实现了 IAnimal 的“人”,有几点说明一下:
* 1)同样都实现了 IAnimal 的接口,但“人”和“猪”的实现不一样,为了避免太多代码导致影响问读,这里的代码简化成一行,但输出的内容不一样的
* 2)这里同样是“人”这个类,但和前面介绍类时定义的“人”的类完全不一样,这是因为同样的逻辑概念,在不同的应用场景下,具备的属性和功能是完全不同的*/
package com.oo.demo;
public class Person 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 day");
}
public void speak(){
System.out.println("Hello world, I am a person");
}
}
==========第四部分:Tester.java
package com.oo.demo;
public class Tester{
public static void main(String[] args){
System.out.println("===This is a person===");
IAnimal person = new Person();
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():
}
}
以上就是 java 中的接口。
二、为什么要用接口
接口提取了一群类共同的函数,可以把接口当做一个函数的集合,然后让子类去实现接口中的函数。这么做的意义在于归一化,什么叫归一化呢?归一化就是只要是基于同一个接口实现的类,那么所有的这些类产生的对象在使用时,从用法上来说都一样。归一化的好处如下:
- 归一化让使用者无需关心对象的类是什么,只需要知道这些对象都具备某些功能就可以了,这极大地降低了使用者的使用难度
- 归一化使得高层的外部使用者可以不加区分的处理所有接口兼容的对象集合
- 就好象 linux 的泛文件概念一样,所有东西都可以当文件处理,不必关心它是内存、磁盘、网络还是屏幕(当然,对底层设计者而言,当然也可以区分出“字符设备”和“块设备”,然后做出针对性的设计,至于细致到什么程度,要视需求而定)
- 再例如:我们有一个汽车接口,里面定义了汽车所有的功能,然后有本田汽车的类、奥迪汽车的类、大众汽车的类,他们都实现了汽车接口,这样就好办了,大家只需要学会了怎么开汽车,那么无论是本田、奥迪和大众我们都会开了,开的时候根本无需关心我开的是哪一类车,操作手法(函数调用)都一样
三、模仿 interface
前面我们借 java 中的 interface 来说明了接口的概念,这是因为 Python 中根本就没有接口的概念,更不会有一个叫做 interface 的关键字,如果非要去模仿接口的概念,可以借助第三方模块:https://pypi.org/project/zope.interface/
除了引入第三方模块我们也可以使用继承来达成这一效果,其实继承有两种用途:
- 继承父类(基类)的方法,并且做出自己的改变或者扩展(代码重用):实践中,继承的这种用途意义并不很大,甚至常常是有害的。因为它使得子类与父类出现强耦合
- 声明某个子类兼容于某基类,定义一个接口类(模仿 java 的 interface),接口类中定义了一些接口名(就是函数名)且并未实现接口的功能,子类继承接口类,并且实现接口中的功能,如下
class Interface: # 定义接口 Interface 类来模仿接口的概念,Python 中压根就没有 interface 关键字来定义一个接口
def read(self): # 定接口函数 read
pass
def write(self): # 定义接口函数 write
pass
class Txt(Interface): # 文本,具体实现 read 和 write
def read(self):
print("文本数据的读取方法")
def write(self):
print("文本数据的写入方法")
class Sata(Interface): # 磁盘,具体实现 read 和 write
def read(self):
print("硬盘数据的读取方法")
def write(self):
print("硬盘数据的写入方法")
cLass Process(Interface):
def read( self):
print("进程数据的读取方法")
def write(self):
print("进程数据的写入方法")
上面的代码只是看起来像接口,其实并没有起到接口的作用,子类完全可以不用去实现接口,这就用到了抽象类。
抽象类
一、什么是抽象类
与 java 一样,Python 也有抽象类的概念但是同样需要借助 abc 模块实现,抽象类是一个特殊的类,它的特殊之处在于只能被继承,不能被实例化。
二、为什么要有抽象类
如果说类是从一堆对象中抽取相同的内容而来的,那么抽象类就是从一堆类中抽取相同的内容而来的,内容包括数据属性和函数属性。例如我们有香蕉的类、苹果的类、桃子的类等,从这些类抽取相同的内容就是水果这个抽象的类,你在吃水果时,要么是吃一个具体的香蕉,要么是吃一个具体的桃子之类的,而你永远无法吃到一个叫做水果的东西。
从设计角度去看,如果类是从现实对象抽象而来的,那么抽象类就是基于类抽象而来的。
从实现角度来看,抽象类与普通类的不同之处在于:抽象类中只能有抽象方法(没有实现功能),该类不能被实例化,只能被继承,而且子类必须实现抽象类的方法,而这一点与接口有点类似,但其实并不相同。
三、如何实现抽象类
import abc # 抽象类的模块 Python没有interface的关键字,需要引入模块abc来实现限制的功能
# 抽象类 统一化子类当中的方法名 metaclass=abc.ABCMeta是规定写法
# 抽象类是由继承演变而来的,实际上是做了子类归一化的功能,把所有的接口(函数名)都规范起来了,可以降低使用者的使用复杂度
class Animal(metaclass=abc.ABCMeta): # 只能被继承,不能被实例化
@abc.abstractmethod # run = abc.abstractmethod(run)
def run(self):
pass
@abc.abstractmethod
def eat(self):
pass
class People(Animal): # 需要继承抽象类
def run(self):
print('People is walking')
def eat(self):
print('People is eating')
class Pig(Animal):
def run(self):
print('Pig is walking')
def eat(self):
print('Pig is eating')
class Dog(Animal):
def run(self):
print('Dog is walking')
def eat(self):
print('Dog is eating')
peo1 = People()
pig1 = Pig()
dog1 = Dog()
peo1.eat()
pig1.eat()
dog1.eat()
代码输出如下:
如果我现在定义一个新的 Cat 类,不写抽象类中定义好的函数会如何呢?
class Cat(Animal):
pass
cat1 = Cat()
代码输出如下:
从输出可以看出会直接报错提示没有定义 eat 和 run 函数,那如果我们只定义其中一个函数会如何呢?
class Cat(Animal):
def run(self):
print('Cat is walking')
cat1 = Cat()
代码输出如下:
可以看到只提示 eat 函数没有定义了,这样抽象类就规范了子类一定要包含抽象类当中强制要包含的几种函数了,从而达到归一化设计,最后还有一个点,抽象类到底能不能实例化,我们直接使用代码尝试一下,看一下是什么效果,如下
ani1 = Animal()
代码输出如下:
标签:Python,self,接口,eat,65,抽象类,public,def From: https://blog.csdn.net/zjw529507929/article/details/143451622