1.几点说明
1.不管是接口类还是规范类,都是面向对象的开发规范;
2.且只在 python 中这两个概念类似,python原生支持抽象类,且原生不支持接口类,但是由于因为python原生支持多继承,所以python中的接口类我们可以使用多继承来实现;
说明:
python中没有接口类,但是java里有接口interface这个概念:
- python中自带多继承,所以我们直接使用class的多继承来实现接口类;
- java中不支持多继承,都是单继承,所以抽象类解决了单继承需求中的 规范问题;
- 对于多继承的需求,由于java本身语法不支持,所以创建了interface这个概念来解决多继承规范问题;
3.接口类和抽象类不能实例化;
2.规范的概念
有如下代码:Wechat 和 Alipay 中都有用于支付功能的方法,且方法名都叫做pay
class Wechat:
def pay(self,money):
print('付钱了.')
class Alipay:
def pay(self,money):
print('付钱了.')
def pay(pay_obj,money): # 将对象作为参数传递
pay_obj.pay(money) # 函数内部是对象调用方法
p = Alipay()
p1 = Wechat()
pay(p,100) # 无论对象是 Wechat类 还是 Alipay类,都直接使用 pay 函数即可
pay(p1,100)
我们可以看到,无论对象是Wechat的对象,还是Alipay的对象,或者是其他类的对象,只要有类中有pay方法,我们就可以统一使用 pay 函数来执行对象的pay方法;
PS: 由于 python 是动态强类型语言,因此不需要再定义一个父类进行类型的统一,而在java这样的强类型语言中,上面的代码需要还需要定义一个父类 例如:Payment,Wechat 和 Alipay 继承 Payment,这样在pay函数传参时,可以 def pay(Payment pay_obj, float money)。
但是,如果现在需要新添加一个 Applepay 类,但是编写程序的人并不知道支付时使用的方法都叫做pay,所以他将 Applepay 中的方法命名为 fuqian,因此,Applepay 中的支付方法不叫做 pay 了而叫做 fuqian,如下:
class Wechat:
def pay(self,money):
print('付钱了.')
class Alipay:
def pay(self,money):
print('付钱了.')
class Applepay:
def fuqian(self,money):
print('付钱了.')
def pay(pay_obj,money):
pay_obj.pay(money)
p = Applepay()
pay(p,100) # 由于 Applepay 中的方法是fuqian时,pay()函数就不能再使用了
这样由于 Applepay 中没有 pay 方法,我们在使用 pay 函数如果传递的参数是 Applepay 的对象,那么执行就会出错,那么我们如何避免这种情况,让人在编写程序时都使用相同的名字,此时,我们就需要一个规范,这个规范让我们在写程序时能够知道我们该遵循什么规则:
如下:
from abc import abstractmethod,ABCMeta
class Payment(metaclass=ABCMeta): # 继承元类 ABCMeta
# 此时 Payment 就成为了以一种规范类,其子类中若是没有 pay 方法,则在实例化对象的过程中就会报错
@abstractmethod # 使用装饰器
def pay(self,money):
pass
# def test(self):
# print('test')
class Wechat(Payment):
def pay(self,money):
print('付钱了.')
class Alipay(Payment):
def pay(self,money):
print('付钱了.')
class Applepay(Payment):
# def pay(self,money):
# print('付钱了.')
def fuqian(self,money):
print('付钱了.')
def pay(pay_obj,money):
pay_obj.pay(money)
p = Applepay() # 我们在实例化对象的时候就会报错
pay(p,100)
当继承了 Payment 的 三个子类无论哪个中没有pay方法的话,在使用此类进行实例化时就会报错,例如 Applepay 中没有pay方法时,我们使用 Applepay 进行实例化时就会报错,这样根据报错信息我们就知道我们的方法应该如何命名:
因此,Payment 就像个标准一样,规范着它的子类;
Payment 就是其子类的接口类 或 抽象类,则要写几个类的 接口类 有2个固定的参数:
- class 接口类名(metaclass=ABCMeta) 参数是必须的
- @abstractmethod 将此装饰器放在你想规范的方法上;
需要注意的有两点:
1.接口类 默认多继承;
2.接口类中的所有方法都不能实现;
抽象类:
1.不支持多继承;
2.抽象类中的方法可以有一些代码的实现;
3.接口类的多继承
由于python原生就支持多继承,因此python中可以使用多继承来实现接口类,由于java是不支持多继承的,因此java中有接口类 interface 的概念,用来实现多继承,需要注意的是:接口类只是一个规范,内部的函数实际上并没有真正的代码实现;
有如下代码:
from abc import abstractmethod,ABCMeta
class Walk_Animal(metaclass=ABCMeta): # 会走的动物类,其中含有 walk 方法
@abstractmethod
def walk(self):
pass
class Fly_Animal(metaclass=ABCMeta): # 会飞的动物类,其中含有 fly 方法
@abstractmethod
def fly(self):
pass
class Swing_Animal(metaclass=ABCMeta): # 会游的动物类,其中含有 swing 方法
@abstractmethod
def swing(self):
pass
# 子类在继承时就必须按照父类的规范来写,同时如子类中未实现的父类中的某个函数也会报错,
class Tiger(Walk_Animal,Swing_Animal): # 老虎类,既会走也会游,因此继承 2 个类
def walk(self):
pass
def swing(self):
pass
class Owl(Fly_Animal,Walk_Animal): # 老鹰类,既会走也会飞
def fly(self):
pass
def walk(self):
pass
class Swan(Walk_Animal,Fly_Animal,Swing_Animal): # 天鹅类,既会走也会游也会飞,继承三个类
def fly(self):
pass
def walk(self):
pass
# def swing(self):
# pass
tiger = Tiger()
owl = Owl()
swan = Swan()
则如果我们子类中没有实现某个继承的父类的方法,那么在实例化对象时就会报错;
在继承抽象类的过程中,我们应该尽量避免多继承;
而在继承接口的时候,反而鼓励多继承接口;
接口隔离原则:
使用多个专门的接口,而不使用单一的总接口,
4.抽象类
抽象类的概念:
如果说类是从一堆对象中抽取相同的内容而来的,那么抽象类就是从一堆类中抽取相同的内容而来的;
说明:
1.抽象类也是一种规范
2.抽象类一般都是单继承 - 能实现的功能都是一样的,所以在父类中可以有一些简单的基础实现
例如 有如下代码:
import abc #利用abc模块实现抽象类
class All_file(metaclass=abc.ABCMeta): # 继承元类
@abc.abstractmethod #定义抽象方法,无需实现功能
def read(self):
'子类必须定义读功方法'
# 在read函数中可以写一些代码,比如文件操作都需要首先打开文件,那么就可以把打开文件的操作写在父类的方法中;
# with open('filename') as f:pass
pass
@abc.abstractmethod #定义抽象方法,无需实现功能
def write(self):
'子类必须定义写方法'
pass
class Txt(All_file): #子类继承抽象类,但是必须定义read和write方法
def read(self):
print('读方法')
def write(self):
print('写方法')
t = Txt()
# class Txt(All_file):
# pass
# t1=Txt() #报错,子类没有定义抽象方法
# a = All_file() # 实例化一个抽象类时会报错
因此:
1.不管是接口类还是规范类,都是面向对象的开发规范;
2.接口类和抽象类不能实例化;