zoukankan      html  css  js  c++  java
  • 面向对象的三大特性:继承,封装,多态

    面向对象的三大特性:继承,封装,多态

    封装

    把很多数据封装到⼀个对象中. 把固定功能的代码封装到⼀个代码块, 函数, 对象, 打包成模块

    封装的原则

    • 将不需要对外提供的内容都隐藏起来
    • 把属性都隐藏起来,提供公共方法对其访问

    封装分为两种:广义的封装 / 狭义的封装

    • 广义的封装:实例化一个对象,给对象空间封装一些属性
    • 狭义的封装:私有制,只能被类的内部所访问

    封装的优点

    • 将变化隔离
    • 便于使用
    • 提高复用性
    • 提高安全性

    将内容封装到某处

    从某处调用被封装的内容

    • 通过对象直接调用
    class Foo:
    
        def __init__(self, name, age):
            self.name = name
            self.age = age
    
    
    obj1 = Foo('wupeiqi', 18)
    print(obj1.name)  # 直接调用obj1对象的name属性
    
    print(obj1.age)  # 直接调用obj1对象的age属性
    
    obj2 = Foo('alex', 73)
    print(obj2.name)
    # 直接调用obj2对象的name属性
    print(obj2.age)  # 直接调用obj2对象的age属性
    
    
    • 通过self间接调用
    class Foo:
    
        def __init__(self, name, age):
            self.name = name
            self.age = age
    
        def detail(self):
            print(self.name,self.age,sep="
    ")
    
    obj1 = Foo('wupeiqi', 18)
    obj1.detail()
    
    obj2 = Foo('alex', 73)
    obj2.detail() 
    
    

    对于面向对象的封装来说,其实就是使用构造方法将内容封装到 对象 中,然后通过对象直接或者self间接获取被封装的内容

    多态

    定义

    • 一类事物有多种形态,python中处处是多态、
    • 一种类型的多种形态,多个子类去继承父类,那么每一个子类都是这个父类的一种形态
    • 例 : python中 定义变量不用规定变量的类型.
    # 在java或者c#定义变量或者给函数传值必须定义数据类型,否则就报错
    def func(int a):
        print('a必须是数字')
    
    # 而类似于python这种弱定义类语言,a可以是任意形态(str,int,object等等)
    class F1:
        pass
    
    class S1(F1):
    
        def show(self):
            print(S1.show)
    
    class S2(F1):
    
        def show(self):
            print(S2.show)
            
    # 由于在Java或C#中定义函数参数时,必须指定参数的类型
    # 为了让Func函数既可以执行S1对象的show方法,又可以执行S2对象的show方法,所以,定义了一个S1和S2类的父类
    # 而实际传入的参数是:S1对象和S2对象
    
    def Func(obj):
        """Func函数需要接收一个F1类型或者F1子类的类型"""
        print(obj.show)
    
    
    
    s1_obj = S1()
    Func(s1_obj)  # 在Func函数中传入S1类的对象 s1_obj,执行 S1 的show方法,结果:S1.show
    
    s2_obj = S2()
    Func(s2_obj)  # 在Func函数中传入Ss类的对象 ss_obj,执行 Ss 的show方法,结果:S2.show
    Python伪代码实现Java或C  # 的多态
    

    鸭子类型

    # 鸭子类型:即‘如果看起来像、叫声像而且走起路来像鸭子,那么它就是鸭子’
    # python中有一句谚语说的好,你看起来像鸭子,那么你就是鸭子。
    # 对于代码上的解释其实很简答:
    
    class 鸭子类型:规范全凭自觉
    
    class A:
        def f1(self):
            print('in A f1')
    
        def f2(self):
            print('in A f2')
    
    
    class B:
        def f1(self):
            print('in A f1')
    
        def f2(self):
            print('in A f2')
    
    
    obj = A()
    obj.f1()
    obj.f2()
    
    obj2 = B()
    obj2.f1()
    obj2.f2()
    # A 和 B两个类完全没有耦合性,但是在某种意义上他们却统一了一个标准。
    # 对相同的功能设定了相同的名字,这样方便开发,这两个方法(A与B)就可以互成为鸭子类型。
    
    # 这样的例子比比皆是:str  tuple list 都有 index方法,这就是统一了规范。
    # str bytes 等等 这就是互称为鸭子类型。
    
    

    类的约束

    归一化设计

    # 支付功能 
    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)
    
    a = Alipay()
    b = QQpay()
    
    pay(a,100)
    pay(b,200)
    
    
    
    # 找了一个野生程序员
    class QQpay:
    
        def pay(self, money):
            print(f'利用qq支付了{money}')
    
    
    class Alipay:
    
        def pay(self, money):
            print(f'利用支付宝支付了{money}')
    
    
    class Wechatpay:
        def fuqian(self,money):    # 支付方法不统一 造成不便
            print(f'利用微信支付了{money}')
    
    
    # 支付功能 规划一下
    
    def pay(obj,money):  # 归一化设计
        obj.pay(money)
    
    obj1 = QQpay()
    obj2 = Alipay()
    
    pay(obj1,100)
    pay(obj2,200)
    
    obj3 = Wechatpay()
    obj3.fuqian(300)
    
    # 按照之前的代码,改进. 规划接口
    
    class QQpay:
    
        def pay(self, money):
            print(f'利用qq支付了{money}')
    
    
    class Alipay:
    
        def pay(self, money):
            print(f'利用支付宝支付了{money}')
    
    
    class Wechatpay:
        def pay(self,money):
            print(f'利用微信支付了{money}')
    
    
    # 支付功能 规划一下
    
    def pay(obj,money):  # 归一化设计
        obj.pay(money)
    
    obj3 = Wechatpay()
    pay(obj3, 300)
    
    # 在上面的情况下(在一些重要的逻辑,与用户数据相关等核心部分),我们要建立一种约束,避免发生此类错误.
    # 类的约束有两种解决方式:
    # 1. 在父类建立一种约束.
    # 2. 模拟抽象类(指定一种规范)的概念,建立一种约束.
    

    对类的约束有两种

    第一种约束 : 提取⽗类

    • 使⽤⼈为抛出异常的⽅案. 并且尽量抛出的是NotImplementError(不执行错误). 这样比较专业, ⽽且错误比较明确.(推荐)
    • 约束⼦类必须要重写父类的xxx⽅法 , 不然就⼈为抛出异常 / 沿用了父类的方法就会⼈为抛出异常
    • python推荐的一种约束方式.
    class Payment:
    
        def pay(self,money):  # 约定俗称定义一种规范,子类要定义pay方法.
            raise Exception('子类必须定义此方法')  # 子类不定义父类方法 就人为报错
    
    
    class QQpay(Payment):
    
        def pay(self, money):
            print(f'利用qq支付了{money}')
    
    
    class Alipay(Payment):
    
        def pay(self, money):
            print(f'利用支付宝支付了{money}')
    
    class Wechatpay(Payment):
        def pay(self,money):
            print(f'利用微信支付了{money}')
    
    # class Wechatpay(Payment):
    #     def fuqian(self,money):   #  为了避免发生此类错误
    #         print(f'利用微信支付了{money}')
    
    # 支付功能 规划一下
    
    def pay(obj,money,choice):  # 归一化设计
    
        obj.pay(money)
    
    choice = input('输入支付方式:QQ/zfb/wx').strip().upper()  # 最后只留一个选择支付接口
    if choice == "QQ":
        obj1 = QQpay()
        pay(obj1,100,choice)
    if choice == "ZFB":
        obj2 = Alipay()
        pay(obj2,200,choice)
    if choice == "WX":
        obj3 = Wechatpay()
        pay(obj3,300,choice)
    else:
        print('输入有误')
    

    第二种约束 : 抽象⽅法

    • 在元类中给出⼀个抽象⽅法. 这样⼦类就不得不给出抽象⽅法的具体实现. 也可以起到约束的效果
    • 模拟抽象类(指定一种规范)的概念,建立一种约束.
    • 使⽤抽象类 / , 由于该⽅案来源是java和c#. 使⽤频率少
    from abc import ABCMeta,abstractmethod
    
    class Payment(metaclass=ABCMeta):
                # 抽象类 接口类  规范和约束  metaclass指定的是一个元类
        @abstractmethod
        def pay(self, money):
            pass  # 抽象方法
    
    
    class QQpay(Payment):
    
        def pay(self, money):
            print(f'利用qq支付了{money}')
    
    
    class Alipay(Payment):
    
        def pay(self, money):
            print(f'利用支付宝支付了{money}')
    
    # class Wechatpay(Payment):
    #     def pay(self,money):
    #         print(f'利用微信支付了{money}')
    
    class Wechatpay(Payment):
        def fuqian(self,money):
            print(f'利用微信支付了{money}')
    
        # def pay(self,money):
        #     pass
    
    
    obj3 = Wechatpay()
    # 微信支付方法没有重新也没有继承父类 就会报错
    TypeError: Can't instantiate abstract class Wechatpay with abstract methods pay
        # 无法用抽象方法pay实例化抽象类微信支付 
    
    # 利用抽象类的概念: 基类如上设置,子类如果没有定义pay方法,在实例化对象时就会报错.
    

    super()深入了解

    super是严格按照类的继承顺序 mro序列 执行

    • super()严格意义上并不是执行父类的方法 / 必须按照继承顺序来执行
    • 严格按照self从属于的本类的mro执行顺序,执行S类的下一位父类

    单继承 : super()肯定是执行父类的方法

    class A:
        def f1(self):
            print('in A f1')
        
        def f2(self):
            print('in A f2')
    
    
    class Foo(A):
        def f1(self):
            super().f2() # 全写 super(Foo,self).f2() 
            # super().f2() ==  # 全写 super(Foo,self).f2()  执行父类的f2()
            print('in A Foo')
            
            
    obj = Foo()
    obj.f1()
    
    

    多继承 : super(S,self)严格按照self从属于的本类的 mro序列 执行顺序,执行S类的下一位父类

    class A:
        def f1(self):
            print('in A')
    
    class Foo(A):
        def f1(self):
            super().f1()
            print('in Foo')
    
    class Bar(A):
        def f1(self):
            print('in Bar')
    
    class Info(Foo,Bar):
        def f1(self):
            super().f1()
            print('in Info f1')
    
    obj = Info()
    obj.f1()
    
    '''
    in Bar
    in Foo
    in Info f1
    '''
    print(Info.mro())  # [<class '__main__.Info'>, <class '__main__.Foo'>, <class '__main__.Bar'>, <class '__main__.A'>, <class 'object'>]
    
    
    lass A:
        def f1(self):
            print('in A')
    
    class Foo(A):
        def f1(self):
            super().f1()
            print('in Foo')
    
    class Bar(A):
        def f1(self):
            print('in Bar')
    
    class Info(Foo,Bar):
        def f1(self):
            super(Foo,self).f1()  # 在本类中执行父类的父类
            print('in Info f1')
    
    obj = Info()
    obj.f1()
    
    
  • 相关阅读:
    awt
    登录校验 简单实现
    事务隔离级别
    事务的四大特性(ACID)
    多线程简单了解
    Eureka bug
    什么是存储过程
    filter和servlet的区别
    说说你对多线程锁机制的理解
    session的生命周期,session何时创建,何时销毁,session销毁的方式
  • 原文地址:https://www.cnblogs.com/fanxss/p/11147218.html
Copyright © 2011-2022 走看看