zoukankan      html  css  js  c++  java
  • python-抽象-接口-多态

    抽象类

    什么是抽象类
    与java一样,python也有抽象类的概念但是同样需要借助模块实现,抽象类是一个特殊的类,它的特殊之处在于只能被继承,不能被实例化。抽象类是将一堆的类中抽象抽取相同的内容,其其中包括了数据的属性和函数的属性。
    python中实现的抽象的类
    看下面的代码:

    class Wechatpay:
        def __init__(self, name, money):
            self.name = name
            self.money = money
    
        def pay(self):
            print('%s通过微信支付了%s元' % (self.name, self.money))
    
    
    class Alipay:
        def __init__(self, name, money):
            self.name = name
            self.money = money
    
        def pay(self):
            print('%s通过支付宝支付了%s元' % (self.name, self.money))
    
    
    # 为了归一化设计
    def pay(person):  # 直接传入一个对象,对象调用pay方法 ,不管的alipay和Wechatpay
        person.pay()
    
    
    # 实列化对象
    ali = Alipay("Tom", 10000)
    wch = Alipay("Jack", 100)
    
    pay(ali)
    pay(wch)
    
    

    上述这样调用是没有任何的问题,但是某天,为了需求,需要添加applepay的功能,但是在定义的applepay中
    没有定义pay方法,而是定义成为中文的汉语拼音fuqian的方法如下所示:

    class ApplePay:
        def __init__(self, name, money):
            self.name = name
            self.money = money
    
        def fuqian(self):
            print('%s通过apple pay支付了%s元' % (self.name, self.money))
    
    app = ApplePay("Tom", 1000)
    app.fuqian()
    

    上述通过ApplePay实例化的对象,调用的fuqian方法是没有任何的问题,当时为了归一化的设计,我们
    在使用applyPay实例化的对象,将对象传入到pay函数中,则会出现下面的报错信息,没有pay的方法

    pay(app)  # AttributeError: 'ApplePay' object has no attribute 'pay'
    

    那怎么样处理这样的问题?
    处理只要的问题,只能从规范的程度进行处理,在定义函数的时候,就必须设置相同的函数名,就如上述中ApplePay中方法fuqian应该改成和Alipay和WechatPlay中的pay,怎样在进行归一化的设计的时候,就不会出现找不到该方法了。在python中是使用abc模块来进行规范的,具体的使用方法如下所示:

    from abc import ABCMeta,abstractmethod
    class Payment(metaclass=ABCMeta):    # 抽象类
    
        @abstractmethod   # 如果我必须要实现pay方法,那么我需要给pay加一个装饰器
        def pay(self):
            pass   # 创建的这个pay并没有内容,
                   # 之所以写一个pay是为了提醒所有子类你一定要实现一个pay方法
    
        @abstractmethod
        def back(self):
            pass
    
    class Wechatpay(Payment):
        def __init__(self,name,money):
            self.name = name
            self.money = money
        def pay(self):
            print('%s通过微信支付了%s元'%(self.name,self.money))
    
    class Alipay(Payment):
        def __init__(self,name,money):
            self.name = name
            self.money = money
        def pay(self):
            print('%s通过支付宝支付了%s元'%(self.name,self.money))
    
    class ApplePay(Payment):
        def __init__(self, name, money):
            self.name = name
            self.money = money
        def pay(self):
            print('%s通过apple pay支付了%s元' % (self.name, self.money))
        def back(self):
            print('退款')
    
    # 归一化设计
    def pay(person):
        person.pay()
    
    ApplePay('alex',20000)
    

    特别注意的是,在类Payment中被语法糖装饰的函数,如果没有在子类中进行创建实现,那么在子类的实例化的时候,就会导致报错。如下所示:

    from abc import ABCMeta,abstractmethod
    class Payment(metaclass=ABCMeta):    # 抽象类
    
        @abstractmethod   # 如果我必须要实现pay方法,那么我需要给pay加一个装饰器
        def pay(self):
            pass   # 创建的这个pay并没有内容,
                   # 之所以写一个pay是为了提醒所有子类你一定要实现一个pay方法
    
        @abstractmethod
        def back(self):
            pass
    
    class Wechatpay(Payment):
        def __init__(self,name,money):
            self.name = name
            self.money = money
        def pay(self):
            print('%s通过微信支付了%s元'%(self.name,self.money))
    
    class Alipay(Payment):
        def __init__(self,name,money):
            self.name = name
            self.money = money
        def pay(self):
            print('%s通过支付宝支付了%s元'%(self.name,self.money))
    
    class ApplePay(Payment):
        def __init__(self, name, money):
            self.name = name
            self.money = money
        # def pay(self):  
        #     print('%s通过apple pay支付了%s元' % (self.name, self.money))
        # def back(self):
        #     print('退款')
    
    # 归一化设计
    def pay(person):
        person.pay()
    
    ApplePay('alex',20000)
    

    上述的代码中,在ApplePay将pay方法进行注释了,在进行ApplePay('alex',20000)实例化的时候,出现了下面的错误:

    TypeError: Can't instantiate abstract class ApplePay with abstract methods back, pay
    

    总结:

    抽象类 :Payment这个类是一个抽象类
    抽象类做什么事儿 : 约束所有的子类 必须实现被abstractmethod装饰的方法名
    给我们的代码指定规范
    特点 : 抽象类不能实例化,只是作为具体的类的规范
    抽象类长什么样

    class 类名(metaclass = 'ABCMeta'):
    
        @abstractmethod
        def 规定的方法名(self):pass
    
        @abstractmethod
        def 规定的方法名(self):pass
    
        @abstractmethod
        def 规定的方法名(self):pass
    

    接口类

    类只能单继承,所以抽象类 只能是所有的子类只有一个规范
    java 当中没有多继承的类
    接口 接口可以多继承
    在python里没有接口的专用语法
    我们只是通过类的多继承模仿接口的效果

    from abc import ABCMeta,abstractmethod
    class NormalAnnimal(metaclass=ABCMeta):
        @abstractmethod
        def eat(self):pass
    
        @abstractmethod
        def drink(self):pass
    class FlyAnimal(metaclass=ABCMeta):
        @abstractmethod
        def fly(self):pass
    
    class SwimAnimal(metaclass=ABCMeta):
        @abstractmethod
        def swim(self):pass
    
    class WalkAnimal(metaclass=ABCMeta):
        @abstractmethod
        def walk(self):pass
    
    

    和抽象类一样,基类多装饰的方法,子类中都必须去实现它,在java中,基类所定义的方法,通常只是定义,而不能实现,而在python中就没有那么对限制,可以去实现,但是一般也是只是定义方法,在子类中去实现。

    总结:

    • 抽象类 是单继承的规范
    • 接口类 是多继承的规范

    java中

    • 接口里面定义的所有的方法 都不能写具体的实现 pass
    • 抽象类里面定义的所有的抽象方法 内部是可以完成一些简单的代码

    多态

    多态指的是一类事物有多种形态
    动物有多种形态:人,狗,猪

    import abc
    class Animal(metaclass=abc.ABCMeta): #同一类事物:动物
        @abc.abstractmethod
        def talk(self):
            pass
    
    class People(Animal): #动物的形态之一:人
        def talk(self):
            print('say hello')
    
    class Dog(Animal): #动物的形态之二:狗
        def talk(self):
            print('say wangwang')
    
    class Pig(Animal): #动物的形态之三:猪
        def talk(self):
            print('say aoao')
    

    文件有多种形态:文本文件,可执行文件

    import abc
    class File(metaclass=abc.ABCMeta): #同一类事物:文件
        @abc.abstractmethod
        def click(self):
            pass
    
    class Text(File): #文件的形态之一:文本文件
        def click(self):
            print('open file')
    
    class ExeFile(File): #文件的形态之二:可执行文件
        def click(self):
            print('execute file')
    

    多态性

    peo=People()
    dog=Dog()
    pig=Pig()
    
    #peo、dog、pig都是动物,只要是动物肯定有talk方法
    #于是我们可以不用考虑它们三者的具体是什么类型,而直接使用
    peo.talk()
    dog.talk()
    pig.talk()
    
    #更进一步,我们可以定义一个统一的接口来使用
    def func(obj):
        obj.talk()
    

    鸭子类型
    Python崇尚鸭子类型,即‘如果看起来像、叫声像而且走起路来像鸭子,那么它就是鸭子’

    # 二者都像鸭子,二者看起来都像文件,因而就可以当文件一样去用
    class TxtFile:
        def read(self):
            pass
    
        def write(self):
            pass
    
    class DiskFile:
        def read(self):
            pass
        def write(self):
            pass
    

    总结:

    # 鸭子类型
        # python当中写程序的一种特殊的情况
        # 其他语言中 正常的我们说一个数据类型具有某个特点,通常是通过继承来实现
            # 继承迭代器类,来证明自己本身是个迭代器
            # 继承可哈希的类,来证明自己本事是可哈希的
        # 但是所有的这些都不是通过继承来完成的
            # 我们只是通过一种潜规则的约定,如果具有__iter__,__next__就是迭代器
            # 如果具有__hash__方法就是可哈希
            # 如果具有__len__就是可以计算长度的
        # 这样数据类型之间的关系并不仅仅是通过继承来约束的
        # 而是通过约定俗成的关系来确认的
    
    # 多态
        # 在传递参数的时候,如果要传递的对象有可能是多个类的对象
            # 我们又必须在语言中清楚的描述出到底是那一个类型的对象
            # 我们就可以使用继承的形式,有一个父类作为这些所有可能被传递进来的对象的基类
            # 基础类型就可以写成这个父类
            # 于是所有子类的对象都是属于这个父类的
        # 在python当中,因为要传递的对象的类型在定义阶段不需要明确,所以我们在python中处处都是多态
            # 数据的类型不需要通过继承来维护统一
    
    
  • 相关阅读:
    Com组件的两种复用方式:包容与集合的区别
    LAPACK/CLAPACK超级无敌算法库
    转:.h头文件 .lib库文件 .dll动态链接库文件关系
    python中类的变量与对象的变量
    重温:Martin Fowler的持续集成
    转:OOD的五个设计原则
    文章资源分享
    代码奔腾 Code Rush
    非ie6、ie7和ie8中iframe在dom中位置改变会引起iframe的指向重新加载
    前端开发利器webStorm
  • 原文地址:https://www.cnblogs.com/yangchangjie150330/p/10615522.html
Copyright © 2011-2022 走看看