zoukankan      html  css  js  c++  java
  • 面向对象之多态

    一.封装方法

    语法:方法名前加双下划线

    优点:1.提高安全性;2.隔离复杂度(将复杂的内容隔离到内部,使用者通过简单的使用接口就可进行访问)

    # ATM 的取款功能
    # 1.插入银行卡 2.输入密码 3.选择取款金额  4.取款
    
    class ATM:
        def __insert_card(self):
            print("插入银行卡...")
    
        def __input_pwd(self):
            print("输入密码...")
        def __select_money(self):
            print("选择取款金额...")
        def withdraw(self):
            self.__insert_card()
            self.__input_pwd()
            self.__select_money()
            print("取款成功!....")
    
    atm = ATM()
    
    atm.withdraw() # 外部调用这个简单的接口 就能完成一系列复杂的操作
    
    # atm.select_money()  #直接调用内部的方法 是没有意义的无法完成整个功能
    
    # 当然用户按照流程一一调用也可以完成功能 但是太麻烦
    # atm.insert_card()
    # atm.input_pwd()
    # atm.select_money()
    封装方法

    二.封装的实现原理

    python是通过语法的转换来实现封装的,具体就是在私有的属性和方法名前,自动加上了_类名,因此__属性名和__方法名就转换成了_类名__方法名和_类名__属性名。

    注:

    1.只有在类的内部的双下划线开头的属性和方法才会被自动转换,且这种转换过程只执行一次,在类定义完成之后,后续在外部添加的双下划线开头的属性和方法是不会进行转换的。

    2.父类中被封装的方法,子类中无法进行访问和覆盖。

    3.我们知道了封装的实现原理,也可以绕过封装的限制进行访问,但是这种做法是毫无意义的。

    class Person:
    
        def __init__(self,name,sex,age,idCard):
            self.name = name
            self.sex = sex
            self.__age = age
            self.__idCard = idCard
    
        def get_idCard(self):
            return self.__idCard
    
        def __test(self):
            pass
    
        print("aaaaaaaaaa")
    
    
    # p = Person("比尔盖茨","男",20,"322323232332332")
    #
    # # print(p.__idCard)
    # p.__idCard = "XXXXXX"
    # print(p.__idCard)
    #
    # print(p.get_idCard())
    #
    # print(p.__dict__)
    # print(Person.__dict__)
    #
    #
    # p.__xxxxxxxxxxxx = 1
    #
    # print(p.__dict__)
    
    
    # 通过__dict__ 可以发现
    # 1.私有的属性和方法名称 前自动加上了_类名 python就是通过这样的转换方式来实现封装
    # 2.只有在类的内部的双下划线才会被自动转换,并且这个转换过程只执行一次,在类定义完成后 后续添加的双下划线开头的名称是不会自动转换的
    # 3.父类中私有的方法 子类中无法使用
    
    
    #在父类中定义的私有方法 能不能被子类所覆盖?
    
    
    # class A:
    #     def __f1(self):
    #         print("A __f1")
    #
    # class B(A):
    #     def __f2(self):
    #         # self.__f1()
    #         super().__f1()
    #         print("B __f2")
    #
    #     def test(self):
    #         self.__f2()
    #
    # b = B()
    # b.test()
    
    
    
    
    # 子类无法覆盖父类的私有方法
    
    # class  A:
    #     def f(self):
    #         self.__f1()   #_A__f1
    #
    #     def __f1(self):
    #         print("A  __f1")
    #
    # class B(A):
    #     def __f1(self):  # _B__f1
    #         print("B __f1")
    #
    #     def f2(self):
    #         self.f()
    #
    # b = B()
    # b.f2()
    
    # 之所以无法覆盖 是因为 子类和父类中的私有方法 名称必然不相同 所以无法覆盖   子类的方法一定子类独有的 因为名称不同
    
    
    
    
    class A:
        __age = 10
    
    # 绕过封装的限制直接访问  这是毫无意义的
    print(A._A__age)
    封装的实现原理

    三.property装饰器

    1.什么是property?

    property是一种特殊的属性,访问它时会执行一段功能(函数),然后返回值。

    2.为什么用property?

    当一些属性的值,不是固定的,而是通过计算得来的,我们就需要为其添加方法才能完成计算。这样一来该属性的使用就会变成调用方法才能使用它,会给使用者造成困惑。这时候就需要用到property装饰器装饰该方法,使其伪装成一个属性。在使用者调用该方法时,会跟访问属性的形式一样,从而形成了访问属性的统一标准。

    3.如何用property?

    在需要装饰的方法上方,加上@property即可。另外property还提供了setter(用于修改属性的值),deleter(用于删除属性的值)。

    # BIM案例:
    class Person:
        def __init__(self,name,weight,height):
            self.name = name
            self.weight = weight
            self.height = height
            # self.bmi = weight/(height*height)
        # def bmi(self):
        #     return self.weight / (self.height * self.height)
        @property
        def bmi(self):
            return self.weight / (self.height * self.height)
    
    p = Person("尔晴",50,1.5)
    # print(p.bmi)
    # p.weight = 90
    # print(p.bmi)
    
    # 现在 虽然可以实现需求 但是我们把一个属性变成了一个行为 这是不合理的
    # print(p.bmi())
    # p.weight = 90
    # print(p.bmi())
    
    # 使用property装饰器 可以将一个方法伪装成一个属性
    print(p.bmi)
    p.height += 0.2
    print(p.bmi)
    
    
    class Student:
        def __init__(self,name,sex,idCard):
            self.name = name
            self.sex = sex
            self.__idCard = idCard
    
        def get_idCard(self):
            return self.__idCard
    
        def set_idCard(self,new_id):
            self.__idCard = new_id
    
        @property # 需要掌握
        def idCard(self):
            return self.__idCard
    
    
        @idCard.setter #了解的
        def idCard(self,new_id):
            self.__idCard = new_id
    
        @idCard.deleter # 了解的
        def idCard(self):
            print("身份证属性被删除了.....")
            del self.__idCard
    
    
    stu = Student("尔康","","323254554554")
    
    # print(stu.get_idCard())
    
    # stu.set_idCard("xxxx")
    
    print(stu.get_idCard()) # 使用装饰器前
    print(stu.name) # 普通属性的访问
    
    print(stu.idCard) # 使用装饰器后
    
    stu.idCard = "aaaaaaa" # 使用装饰器后的修改操作
    
    print(stu.idCard)
    
    del stu.idCard
    property的使用

    四.多态

    1.什么是多态?

    多态简单的来说就是一个事物有多种状态。在程序中,不同对象可以享有同一方法,并作出不同的行为,产生不同的结果。

    2.为什么用多态?

      1.增加了程序的灵活性

    以不变应万变,不论对象千变万化,使用者都用同一种方式去调用。

      2.增加了程序的可扩展性

    通过继承基类创建一个新的类,使用者无需修改代码,还是使用之前的方式去调用。

    3.如何实现多态?

    让几个不同的类继承相同的父类,这样子类就可以拥有相同的方法,每个子类都要覆盖父类的方法,这样子类的对象行为都不同。

    class Animal:
        def eat(self):
            print("动物在吃东西...")
        def sleep(self):
            print("动物在睡觉...")
        def drink(self):
            print("动物需要水.....")
    
    
    class Person(Animal):
        def eat(self):
            print("人吃粮食...")
    
    class Pig(Animal):
        def eat(self):
            print("猪吃饲料...")
    
    class Dog(Animal):
        def eat(self):
            print("狗吃骨头...")
    
    
    person = Person()
    pig = Pig()
    dog = Dog()
    
    person.eat()
    pig.eat()
    dog.eat()
    
    #假设你学习了C1驾照  意味着 所有C1类的汽车都能开  因为每种C1汽车的驾驶方式相同
    
    
    # 当使用了多态之后 对象的使用者不需要关系这个对象具体的实现,只需要知道该对象属于哪个基类,就能直接使用它
    # 如此扩展性变高了
    
    
    class Phone:
        def call(self):
            print("手机就能打电话..")
    
        def send_msg(self):
            print("手机能发短信..")
    
    
    class WindowsPhone(Phone):
        def call(self):
            print("拨号打电话..")
    
        def send_msg(self):
            print("输入号码发短信..")
    
    class IPhone(Phone):
        def call(self):
            print("拨号打电话..")
    
    
        def send_msg(self):
            print("输入号码发短信..")
    
    
    
    
    # 可以定义一个方法接收一个手机为参数 无论是是类型的手机 都可以被使用
    
    def CALL(phone):
        phone.call()
    
    wp = WindowsPhone()
    ipx = IPhone()
    
    CALL(wp)
    CALL(ipx)
    
    
    # 系统内置的方法有很多都体现了多态
    
    
    print(len("abc"))
    print(len([1,2,3,4,]))
    print(len({"name":"123","sex":"man"}))
    
    print("abc".__len__())
    print([1,2,3,4,].__len__())
    print({"name":"123","sex":"man"}.__len__())
    
    print(len({1,23,4,5}))
    多态的实现

    4.多态之ABC模块

    abc模块(abstract  class(抽象类)),使用abc模块来限制子类的步骤。

    4.1.为类中指定元类为abc.ABCMeta

    4.2.在相应的方法加上abc.abstractmethod装饰器

    import abc
    # abstract class 是抽象类的缩写   抽象的意思是 不清晰 不具体 看不懂
    
    #使用ABC模块来限制子类 的步骤
    #1.为类中指定元类为abc.ABCMeta
    #2.在相应的方法上加上abc.abstractmethod装饰器
    
    class Animal(metaclass=abc.ABCMeta):
    
        @abc.abstractmethod
        def eat(self):
            pass
    
        @abc.abstractmethod
        def drink(self):
            pass
    
    
    class Cat(Animal):
        def eat(self):
            print("猫爱吃鱼肉...")
    
        def drink(self):
            print("用舌头舔..")
    
    class Dog(Animal):
        def eat(self):
            print("狗爱吃骨头...")
        def drink(self):
            print("用舌头舔..")
    
    class Pig(Animal):
        def eat(self):
            print("猪 爱吃草...")
    
        def drink(self):
            print("用嘴吸的..")
    
    p = Pig()
    # p.eat()
    
    c = Cat()
    # c.eat()
    
    # 多态的好处 完全不需要考虑得到的对象时声明类型 只要知道了其基类中的内容就能使用
    def feeding(animal):
        animal.eat()
        animal.drink()
    
    feeding(c)
    feeding(p)
    # 多态中的基类 相当于(协议 标准 规范) 要求子类必须满足这些标准
    ABC模块的使用
    import abc
    
    # 电脑基类
    class Computer(metaclass=abc.ABCMeta):
    
        @abc.abstractmethod
        def open(self):
            pass
    
        @abc.abstractmethod
        def shutdown(self):
            pass
    
    
    #
    class DesktopComputer(Computer):
        def open(self):
            print("台式机正在启动....")
    
        def shutdown(self):
            print("台式机正在关机....")
    
    
    class Worker:
    
        def working(self,pc):
            # 先开机
            pc.open()
            print("工作中.....")
            pc.shutdown()
    
    
    w1 = Worker()
    
    dp = DesktopComputer()
    
    w1.working(dp)
    
    
    # 增加了笔记本电脑
    class BookComputer(Computer):
    
        def open(self):
            print("笔记本正在启动....")
    
    
        def shutdown(self):
            print("笔记本正在关机....")
    
    bc = BookComputer()
    w1.working(bc)
    
    class PadComputer(Computer):
    
        def open(self):
            print("平板正在启动....")
    
    
        def shutdown(self):
            print("平板正在关机....")
    
    bc = PadComputer()
    w1.working(bc)
    多态的练习

    五.鸭子类型

    python推崇的是鸭子类型,推崇简单的编程方式。鸭子类型指的是如果一个对象叫声像鸭子,走路的姿势也像鸭子,那就把它当成鸭子。对应到代码中:只要你的行为一样,就把你当成同一个类型来对待。

    class Duck:
    
        def bark(self):
            print("鸭子嘎嘎叫...")
    
        def run(self):
            print("摇摇晃晃走....")
    
    class Chicken:
        def bark(self):
            print("鸡咯咯叫...")
    
        def run(self):
            print("摇摇晃晃走....")
    
    def test(obj):
        obj.bark()
        obj.run()
    duck = Duck()
    c = Chicken()
    
    test(duck)
    test(c)
    
    # 如果你足够自觉 你可以不使用abc模块 也不需要基类 自觉地将方法名字都写成一样 同样可以实现多态
    # 这种方式称之为鸭子类型
    鸭子类型

     其实我们一直在享受着多态性带来的好处,比如Python的序列类型有多种形态:字符串,列表,元组,多态性体现如下:

    #str,list,tuple都是序列类型
    s=str('hello')
    l=list([1,2,3])
    t=tuple((4,5,6))
    
    #我们可以在不考虑三者类型的前提下使用s,l,t
    s.__len__()
    l.__len__()
    t.__len__()
    
    len(s)
    len(l)
    len(t)
    View Code
  • 相关阅读:
    String类的常用成员方法
    String类和StringBuffer类
    记事本
    GridLayout 可使容器中的各个组件呈网格状布局
    在使用add()方法添加组件到容器时,必须指定将其放置在哪个区域中
    每个容器都有一个布局管理器
    框架一般用作Java应用程序的窗口,而Applet是Java小程序的窗口
    面板是一种透明的容器,没有标题和边框
    要生成一个窗口,通常使用Window的子类Frame类进行实例化
    分布式系统 (大规模分布式系统原理解析和架构实践)
  • 原文地址:https://www.cnblogs.com/wangke0917/p/10137354.html
Copyright © 2011-2022 走看看