欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Python学习日记(二十五) 接口类、抽象类、多态

程序员文章站 2023-11-13 23:23:10
接口类 继承有两种用途:继承基类的方法,并且做出自己的改变或扩展(代码重用)和声明某个子类兼容于某基类,定义一个接口类interface,接口类中定义了一些接口名(就是函数名)且并未实现接口的功能,子类继承接口类,并且实现接口的功能 比如说一种支付方式有三种不同的途径:Alipay、Applepay ......

接口类

继承有两种用途:继承基类的方法,并且做出自己的改变或扩展(代码重用)和声明某个子类兼容于某基类,定义一个接口类interface,接口类中定义了一些接口名(就是函数名)且并未实现接口的功能,子类继承接口类,并且实现接口的功能

比如说一种支付方式有三种不同的途径:alipay、applepay、wechatpay

如果现在只有两种支付方式alipay和wechatpay,我们该如何去实现支付的方法呢?

class wechat:
    def pay(self,money):
        print('已经用了微信支付了%s元'%money)
class alipay:
    def pay(self,money):
        print('已经用了支付宝支付了%s元'%money)
wechat = wechat()
wechat.pay(200)             #已经用了微信支付了200元
ali = alipay()
ali.pay(150)                #已经用了支付宝支付了150元

但是这样做有一点不好就是用户要去关心他在支付的时候是用什么方式去pay的,而我们只需要传一个支付的对象和钱就好了

def pay(obj_pay,money):     #定义一个支付函数
    obj_pay.pay(money)
class wechat:
    def pay(self,money):
        print('已经用了微信支付了%s元'%money)
class alipay:
    def pay(self,money):
        print('已经用了支付宝支付了%s元'%money)
wechat = wechat()
pay(wechat,300)             #已经用了微信支付了300元
ali = alipay()
pay(ali,250)                #已经用了支付宝支付了250元

这样写虽然可以,但是假设在之后添加了一个新的类applepay的付款方式,里面的方法名和pay名不同就会导致报错

from abc import abstractmethod,abcmeta
class payment(metaclass=abcmeta):
    @abstractmethod
    def pay(self,money):
        raise notimplemented

class wechat(payment):
    def pay(self,money):
        print('已经用了微信支付了%s元'%money)
class alipay(payment):
    def pay(self,money):
        print('已经用了支付宝支付了%s元'%money)
class apple(payment):
    def paymoney(self,money):
        print('已经用了支付宝支付了%s元'%money)

wechat = wechat()
ali = alipay()
apple = apple()         #can't instantiate abstract class apple with abstract methods pay

这样的话如果开发人员写的方法名和pay不同时,程序在实例化对象就会报错就直接给给开发人员提示了要用规范的方法去写。如果我们再把apple类中的方法给改回pay的方法名,那么就不会报错了

class apple(payment):
    def pay(self,money):
        print('已经用了支付宝支付了%s元'%money)

apple = apple()

接口的多继承

如果我们归纳下面三种动物的行为,老虎能走路、游泳;天鹅能飞、走路、游泳;老鹰能走路、飞,我们该如何用接口的方法去表示呢?

from abc import abstractmethod,abcmeta
class swim_behavior(metaclass=abcmeta):
    @abstractmethod
    def swim(self):
        pass
class walk_behavior(metaclass=abcmeta):
    @abstractmethod
    def walk(self):
        pass
class fly_behavior(metaclass=abcmeta):
    @abstractmethod
    def fly(self):
        pass

class tiger(swim_behavior,walk_behavior):
    def walk(self):
        print('can walk!')
    def swim(self):
        print('can swim!')

class swan(swim_behavior,walk_behavior,fly_behavior):
    def walk(self):
        print('can walk!')
    def swim(self):
        print('can swim!')
    def fly(self):
        print('can fly!')

class hawk(walk_behavior,fly_behavior):
    def walk(self):
        print('can walk!')
    def fly(self):
        print('can fly!')

t = tiger()
s = swan()
h = hawk()

接口类本身的方法不实现只是起到规范的作用

接口隔离原则:

使用多个专门的接口,而不使用单一的总接口。即客户端不应该依赖那些不需要的接口

专门的接口指的是上面的动物能walk就用walk的接口,能fly就用fly的接口,能swim就用swim的接口

不使用单一的接口指的是不应该使用一个接口里面既能有walk的行为又有fly的行为等,只有这样把每一个功能都隔离开,我们在后面用到这个功能就能够继承到它所有相关变量名和方法名

即客户端不应该依赖那些不需要的接口指的是创建了一个tiger类不应该要那些自己本身没有的类,比如fly

 

抽象类

抽象类是一个特殊的类,它的特殊之处在于只能被继承,不能被实例化

如果说类是从一堆对象中抽取相同的内容而来的,那么抽象类就是从一堆类中抽取相同的内容而来的,内容包括数据属性和函数属性

#在操作系统中一切皆文件
from abc import abstractmethod,abcmeta
class all_file(metaclass=abcmeta):
    all_type = 'file'               #所有的类型都是文件
    @abstractmethod                 #定义一个抽象方法无需实现功能
    def write(self):
        pass
    @abstractmethod                 #定义一个抽象方法无需实现功能
    def read(self):
        pass

class txt(all_file):                #定义一个txt类,子类继承抽象类,但是必须定义一个write和read的方法
    def write(self):
        print('write something...')
    def read(self):
        print('read something...')

class sata(all_file):               #定义一个sata类,子类继承抽象类,但是必须定义一个write和read的方法
    def write(self):
        print('write something...')
    def read(self):
        print('read something...')

txt = txt()
sata = sata()

txt.read()                      #read something...
txt.write()                     #write something...
sata.read()                     #read something...
sata.write()                    #write something...
print(txt.all_type)             #file
print(sata.all_type)            #file

抽象类是一种规范,一般情况下单继承能实现的功能都是一样的,所以在父类中可以有一些简单的基础实现;多继承情况由于功能比较复杂,所以不容易抽象出相同的功能,具体实现写在父类中

 

接口类和抽象类总结

在python中没有接口类,但有抽象类;abc模块中的metaclass = abcmeta,@abstractmethod它的本质是做代码的规范用的,希望子类中能实现父类名字完全一样的方法

接口类和抽象类:

从java的角度上看是有区别的,java本来就支持单继承所以就有了抽象类;java没有多继承,所以为了接口隔离原则,设计了接口这个概念,支持多继承了

而python它既支持单继承也支持多继承,所以对于接口类和抽象类的区别就不会那么明显了,甚至在python中没有内置接口类

 

多态

多态指的是一类事物有多种形态

python天生支持多态

from abc import abstractmethod,abcmeta
class payment(metaclass=abcmeta):               #支付方式类
    @abstractmethod
    def pay(self,money):
        pass

class wechat(payment):                          #支付方式---微信支付
    def pay(self,money):
        print('已经用了微信支付了%s元'%money)
class alipay(payment):                          #支付方式---支付宝支付
    def pay(self,money):
        print('已经用了支付宝支付了%s元'%money)
class apple(payment):                           #支付方式---苹果支付
    def pay(self,money):
        print('已经用了支付宝支付了%s元'%money)

多态性

就是虽然是一类东西但是它们执行的是相同的方法但是做的是不同的事,比如微信它用的是微信支付、支付宝它用的是支付宝支付、苹果支付它用的是苹果支付...

鸭子类型

python语言里面有一个鸭子类型的概念,而在某些其他的属于强类型语言,用的是多态

鸭子类型:不崇尚根据继承所得来的相似,我只是自己实现我自己的代码就可以了,如果有两个类它们刚好相似,并不产生父类的子类的兄弟关系,那这就是鸭子类型。像list、tuple这种相似,是自己写代码的时候约束的,而不是通过父类约束的