• day24-抽象类与接口类


    接口类

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

    2、例子:

    第一步:每定义一种支付类,就通过实例化对象调用相应的支付方法,这样虽然也可以实现QQ支付和支付宝支付,但代码风格不统一
    class QQPay():
        def pay(self, money):
            print('QQ支付了%s元' %money)
            
    class AliPay():
        def pay(self, money):
            print('支付宝支持了%s元' %money)
    qq1 = QQPay()
    ali1 = AliPay()
    qq1.pay(100)
    ali1.pay(200)
    
    结果:
    QQ支付了100元
    支付宝支持了200元
    
    第二步:定义一个统一支付的函数,通过将实例化对象作为参数传递给这个函数,由函数来执行实例化对象的pay方法
    class QQPay():
        def pay(self, money):
            print('QQ支付了%s元' %money)
            
    class AliPay():
        def pay(self, money):
            print('支付宝支持了%s元' %money)
    
    def pay(obj, money):
        obj.pay(money)
    
    qq1 = QQPay()
    ali1 = AliPay()
    
    pay(qq1, 100)
    pay(ali1, 200)
    结果:
    QQ支付了100元
    支付宝支持了200元
    
    第三步:如果代码后期需要增加新的支付方式,而这时开发人员已经更换,新的开发人员并没有依照原来的代码风格进行统一编写,虽然也可以执行,但又破坏了代码统一性
    class WechatPay(payment):
        def fuqian(self, money):
            print('微信支付了%s元' %money)
    
    wechat1 = WechatPay()
    结果:微信支付了300元
    
    第四步:我们先定义一个父类,什么都不写,只是要求继承我的所有类有一个pay方法,这样就制定了一个规范,这就叫做接口类,或者抽象类.
    class payment:
        def pay(self):
            pass
    
    class QQPay(payment):
        def pay(self, money):
            print('QQ支持了%s元' %money)
            
    class AliPay(payment):
        def pay(self, money):
            print('支付宝支持了%s元' %money)
            
    class WechatPay(payment):
        def pay(self, money):
            print('微信支付了%s元' %money)
    
    def pay(obj, money):
        obj.pay(money)
    
    qq1 = QQPay()
    ali1 = AliPay()
    wechat1 = WechatPay()
    
    pay(qq1, 100)
    pay(ali1, 200)
    pay(ali2, 300)
    
    结果:
    QQ支持了100元
    支付宝支持了200元
    微信支付了300元
    
    但是这样如果新增的方法WechatPay仍然没有遵循父类中的格式,还是写成了下面这样也还是可以执行的
    class WechatPay(payment):
        def fuqian(self, money):
            print('微信支付了%s元' %money)
    wechat1 = WechatPay()
    wechat1.fuqian(300)
    
    第五步:那么如何强制让新增的类遵循统一格式呢,需要使用@abstractmethod方法
    from abc import ABCMeta, abstractmethod
    
    class payment(metaclass=ABCMeta):
        @abstractmethod
        def pay(self):
            pass
    
    class QQPay(payment):
        def pay(self, money):
            print('QQ支持了%s元' %money)
            
    class AliPay(payment):
        def pay(self, money):
            print('支付宝支持了%s元' %money)
            
    class WechatPay(payment):
        def fuqian(self, money):
            print('微信支付了%s元' %money)
    
    def pay(obj, money):
        obj.pay(money)
    
    qq1 = QQPay()
    ali1 = AliPay()
    wechat1 = WechatPay()
    
    pay(qq1, 100)
    pay(ali1, 200)
    wechat1.fuqian(300)
    这时如果WechatPay里面方法名称不是pay,那么结果会报错,TypeError: Can't instantiate abstract class WechatPay with abstract methods pay
    所以这时就必须要求WechatPay里面存在pay方法,程序才能正确执行,这样就可以使用统一的pay函数进行统一调用对象,
    代码修改如下:
    class WechatPay(payment):
        def pay(self, money):
            print('微信支付了%s元' %money)
    
    qq1 = QQPay()
    ali1 = AliPay()
    wechat1 = WechatPay()
    
    pay(qq1, 100)
    pay(ali1, 200)
    pay(wechat1, 300)
    
    备注:经测试,其实子类中只要有父类中的方法pay即可,即使写成下面这样也还是可以执行。。。
    class WechatPay(payment):
        def fuqian(self, money):
            print('微信支付了%s元' %money)
        def pay(self):
            pass
    
    wechat1 = WechatPay()
    wechat1.fuqian(300)
    
    
    也可以将对象放在一个字典中进行循环调用
    def pay(obj, money):
        obj.pay(money)
    
    qq1 = QQPay()
    ali1 = AliPay()
    wechat1 = WechatPay()
    
    pay_dict = {qq1: 100, ali1: 200, wechat1: 300}
    for i in pay_dict:
        pay(i, pay_dict[i])
    
    QQ支持了100元
    支付宝支持了200元
    微信支付了300元
    View Code

    实践中,继承的第一种含义意义并不很大,甚至常常是有害的。因为它使得子类与基类出现强耦合。

    继承的第二种含义非常重要。它又叫“接口继承”。

    接口继承实质上是要求“做出一个良好的抽象,这个抽象规定了一个兼容接口,使得外部调用者无需关心具体细节,可一视同仁的处理实现了特定接口的所有对象”——这在程序设计上,叫做归一化。

    归一化使得高层的外部使用者可以不加区分的处理所有接口兼容的对象集合

    依赖倒置原则:
    1)高层模块不应该依赖低层模块,二者都应该依赖其抽象;

    2)抽象不应该依赖细节,细节应该依赖抽象。换言之,要针对接口编程,而不是针对实现编程

    在python中根本就没有一个叫做interface的关键字,上面的代码只是看起来像接口,其实并没有起到接口的作用,子类完全可以不用去实现接口 ,如果非要去模仿接口的概念,可以借助第三方模块:
    http://pypi.python.org/pypi/zope.interface
    twisted的twistedinternetinterface.py里使用zope.interface
    文档https://zopeinterface.readthedocs.io/en/latest/
    设计模式:https://github.com/faif/python-patterns

    接口提取了一群类共同的函数,可以把接口当做一个函数的集合,然后让子类去实现接口中的函数。
    这么做的意义在于归一化,就是只要是基于同一个接口实现的类,那么所有的这些类产生的对象在使用时,用法都一样。

    归一化,让使用者无需关心对象的类是什么,只需要知道这些对象都具备某些功能就可以了,这极大地降低了使用者的使用难度。

    比如:我们定义一个动物接口,接口里定义了有跑、吃、呼吸等接口函数,这样老鼠的类去实现了该接口,松鼠的类也去实现了该接口,由二者分别产生一只老鼠和一只松鼠送到你面前,即便是你分别不出哪只是什么鼠你肯定知道他俩都会跑,都会吃,都能呼吸。

    再比如:我们有一个汽车接口,里面定义了汽车所有的功能,然后由本田汽车的类,奥迪汽车的类,大众汽车的类,他们都实现了汽车接口,这样就好办了,大家只需要学会了怎么开汽车,那么无论是本田,还是奥迪,还是大众我们都会开了,开的时候根本无需关心我开的是哪一类车,操作手法(函数调用)都一样

    抽象类

    1、什么是抽象类
    与java一样,python也有抽象类的概念但是同样需要借助模块实现,抽象类是一个特殊的类,它的特殊之处在于只能被继承,不能被实例化

    2、为什么要有抽象类
    如果说类是从一堆对象中抽取相同的内容而来的,那么抽象类就是从一堆类中抽取相同的内容而来的,内容包括数据属性和函数属性。
    比如我们有香蕉的类,有苹果的类,有桃子的类,从这些类抽取相同的内容就是水果这个抽象的类,你吃水果时,要么是吃一个具体的香蕉,要么是吃一个具体的桃子。。。。。。你永远无法吃到一个叫做水果的东西。

    从设计角度去看,如果类是从现实对象抽象而来的,那么抽象类就是基于类抽象而来的。
    从实现角度来看,抽象类与普通类的不同之处在于:抽象类中有抽象方法,该类不能被实例化,只能被继承,且子类必须实现抽象方法。这一点与接口有点类似,但其实是不同的

    3、抽象类与接口类
    抽象类的本质还是类,指的是一组类的相似性,包括数据属性(如all_type)和函数属性(如read、write),而接口只强调函数属性的相似性。
    抽象类是一个介于类和接口之间的一个概念,同时具备类和接口的部分特性,可以用来实现归一化设计
    在python中,并没有接口类这种东西,即便不通过专门的模块定义接口,我们也应该有一些基本的概念。

  • 相关阅读:
    学习之路-前端-笔记-一、HTML笔记
    抄写例题作业1
    郭霖
    java遍历HashMap的高效方法
    Add Two Numbers II 两个数字相加之二
    基于socket的简单p2p聊天项目
    SimpleScalar Course Project
    Dijkstra Java
    PCA vs Linear Regression 可视化理解
    机器学习中的范数规则化之(一)L0、L1与L2范数
  • 原文地址:https://www.cnblogs.com/dxnui119/p/9981633.html
Copyright © 2020-2023  润新知