Python面向对象之Part05.接口类和抽象类

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.接口类和抽象类不能实例化;

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值