zoukankan      html  css  js  c++  java
  • 面向对象之类的约束

    先来看一个例子:如果我们要写一个支付接口,怎么做呢

    版本一:

    class QQpay:
        def pay(self, money):
            print("此次消费%s" % money)
    
    
    class Alipay:
        def pay(self, money):
            print("此次消费%s" % money)
    
    
    a1 = QQpay()
    a2 = Alipay()
    a1.pay(100)
    a2.pay(200)

    版本一虽然完成了支付功能,但是不同的支付没有统一,使用QQ支付时调用的是QQpay类的pay方法,使用Alipay支付的时候又变成调用Alipay类的pay方法,有没有办法使之统一呢,来看版本二。

    版本二:

    class QQpay:      
        def pay(self, money):
            print("此次消费%s" % money)
    
    
    class Alipay:
        def pay(self, money):
            print("此次消费%s" % money)
    
    def pay(obj, money): # 统一规范 obj.pay(money) a1 = QQpay() a2 = Alipay() pay(a1, 100) pay(a2, 200)

    版本二通过在类外面定义了一个pay方法,然后通过pay方法去调用QQpay类和Alipay类的方法,这样就统一了接口,但是这里有一个问题,如果程序之后遇到升级,需要新加入一个微信支付的功能,但是接手这个项目的人这样写........

    class Alipay:
        def pay(self, money):
            print("此次消费%s" % money)
    
    
    class Wechatpay:      # 野生程序员写的
        def zhifu(self, money):
            print("此次消费%s" % money)
    
    
    def pay(obj, money):    # 统一规范
        obj.pay(money)
    
    
    a1 = QQpay()
    a2 = Alipay()
    a3 = Wechat()
    pay(a1, 100)
    pay(a2, 200)
    pay(a3, 300)   # 报错

    很明显,执行pay(a3, 300)时会报错,因为Wechatpay里面并没有pay方法。我们当然可以通过事后更改代码的方法来解决这个问题,但是有没有从程序设计的层面上解决这个问题的方法呢,答案是有的

    版本三:

    class Pay:    # 定义一个基类Pay,所有支付的类都继承这个类
        def pay(self, money):
            pass
    
    
    class QQpay(Pay):       
        def pay(self, money):
            print("此次消费%s" % money)
    
    
    class Alipay(Pay):
        def pay(self, money):
            print("此次消费%s" % money)
    
    
    class Wechatpay(Pay):      
        def pay(self, money):
            print("此次消费%s" % money)
    
    
    def pay(obj, money):
        obj.pay(money)
    
    
    a1 = QQpay()
    a2 = Wechatpay()
    a3 = Alipay()
    pay(a1, 100)
    pay(a2, 200)
    pay(a3, 300)

    版本三解决了支付名字不统一带来的报错问题,但是如果接手的程序员不按规定在自己写的类里定义pay方法,程序虽然不会报错但也不会正常支付,确切地说,版本三只是弱约束,正经的程序员看到了定义了一个基类Pay,其他支付的类都继承了Pay,就会知道这个Pay是统一接口用的,在自己的类里要定义一个pay方法,但是有些程序员比较有个性,就要取别的名字,这时版本三就无能无力了,因此我们对版本三进行了升级

    版本四:

    class Pay:
        def pay(self, money):
            raise NotImplementedError("未定义pay方法")   # 抛出异常
    
    
    class QQpay(Pay):       # 正规写法
        def pay(self, money):
            print("此次消费%s" % money)
    
    
    class Alipay(Pay):
        def pay(self, money):
            print("此次消费%s" % money)
    
    
    class Wechatpay(Pay):      # 野生写法
        def pay(self, money):
            print("此次消费%s" % money)
    
    
    class Unionpay(Pay):
        def zhifu(self, money):
            print("此次消费%s" % money)
    
    
    def pay(obj, money):
        obj.pay(money)
    
    
    a1 = QQpay()
    a2 = Wechatpay()
    a3 = Alipay()
    a4 = Unionpay()
    pay(a1, 100)
    pay(a2, 200)
    pay(a3, 300)
    pay(a4, 400)     # NotImplementedError: 未定义pay方法

    这里我们在基类的pay方法里面加上 raise Exception("未定义pay方法"),当执行pay(a4, 400)时,会先在Unionpay里面找,很显然找不到,之后会在其父类里面找,然后执行父类的pay方法,这时就会执行raise Exception("未定义pay方法"),这句话的意思是,抛出异常,异常的名字是Exception,异常的内容是"未定义pay方法"。版本四的核心就是在父类里定义一个pay方法,方法里只有抛出错误的语句,各子类继承父类,子类里必须定义名字相同的pay方法,否则执行时就会报错。还有一种从Java和C#继承过来的方法:运用抽象类(接口类)来解决

    版本五:

    from abc import ABCMeta, abstractmethod
    
    
    class Pay(metaclass=ABCMeta):    # 这个父类定义了一个约束、规范,规定子类一定要有pay方法
        """
        抽象类(接口类),制定一个规范,强制执行
        """
        @abstractmethod
        def pay(self, money):
            pass
    
    
    class Alipay(Pay):
        def pay(self, money):
            print("此次消费%s" % money)
    
    
    class Wechatpay(Pay):
        def zhifu(self, money):
            print("此次消费%s" % money)
    
    
    def pay(obj, money):
        obj.pay(money)
    
    
    a1 = Alipay()
    a2 = Wechatpay()  # TypeError: Can't instantiate abstract class Wechatpay with abstract methods pay
    pay(a1, 100)
    pay(a2, 200)

    总结:

    1. 约束就是父类对子类的约束,子类必须要写XXX方法

    2. 在python中实现约束有两种方法

      (1)人为抛出异常的方法,并且尽量抛出的是NotImplementedError. 这样比较专业, ⽽且错误比较明确.(推荐)

      (2)使用抽象类和抽象方法,由于该方案来源于Java和C#,所以还是用的比较少

  • 相关阅读:
    Dubbo之SPI实现原理详解
    Java SPI详解
    Java是如何实现自己的SPI机制的
    Dubbo的负载均衡原理解析
    Dubbo公开课
    【todo】什么是沟子函数
    一步一图,带你走进 Netty 的世界!
    https://github.com/xiaojiaqi/k8seasy_release_page
    mysql 8.0导致5.6数据后 :ERROR 1449 (HY000): The user specified as a definer ('mysql.infoschema'@'localhost') does not exist
    Ansible 日常使用技巧
  • 原文地址:https://www.cnblogs.com/zzliu/p/10284298.html
Copyright © 2011-2022 走看看