zoukankan      html  css  js  c++  java
  • 组合 封装 多态

    面向对象的精髓:将数据和处理数据的代码绑定成一个对象

    只要获取到对象相应的数据和方法都有了

    一.组合

    什么叫组合?

    多个对象放在一起叫组合

    组合的作用也是降低代码的冗余

    # 学生会增加各种各样的新的属性 比如手机 比如电脑, 这样Student中会增加大量的属性和方法
    # 后期的维护成本非常高
    # 这时就需要使用组合 来完成减少代码冗余
    class Phone:
      def __init__(self,phonenumber,operator,address):
        self.phonenumber=phonenumber
        self.operator=operator
        self.address=address
      def call(self):
        print('%s 正在拨号!'% self.phonenumber)
    class Person:
      def __init__(self,name,sex,age):
        self.name=name
        self.sex=sex
        self.age=age

    class Student(Person):
      def __init__(self,name,sex,age,number):
        super().__init__(name,sex,age)
        self.number=number
      def show_info(self):
        print(self.__dict__)
      def select_cursor(self):
        print('%s正在选课'% self.name)
    class Teacher(Person):
      def __init__(self,name,sex,age,salary,level):
        super().__init__(name,sex,age)
        self.salary=salary
        self.level=level
      def set_score(self):
        print('%s 正在给学生打分'% self.name)
    stu1=Student('henry','man','29','3')
    p1=Phone('18888888888','中国移动','山西运城')
    stu1.phone=p1
    stu1.phone.call()
    # 通过将手机对象和学生对象进行组合 完成了需求,并且相比较继承而言
    # 耦合度低 手机和学生在修改的时候 互不影响
    # 同时也减少了代码冗余
    # 组合是 对象之间的关系 学生对象拥有手机对象

    小练习:
    """
    用代码 描述乐队
    一个乐队有乐队名,主唱以及其他乐器组成
    乐队可以演奏歌曲

    主唱是歌手类 会唱歌 ,有名字
    钢琴类 能弹奏,有价格,牌子
    """
    class Band:
      def __init__(self,name,singer,piano):
        self.name = name
        self.singer = singer
        self.piano = piano


      def play_music(self):
        print("hello 我们%s 组合! 请欣赏" % self.name)
        self.singer.singing()
        self.piano.playing()
    class Singer:
      def __init__(self,name):
        self.name = name

      def singing(self):
        print("你好我是歌手 ",self.name)

    class Piano:
      def __init__(self,price,brand):
        self.price = price
        self.brand = brand

      def playing(self):
        print("正在弹琴.....")

    # 发现一个歌手
    singer = Singer("刘宪华")
    # 买一台钢琴
    p = Piano("100000000","雅马哈")

    # 组件乐队
    b = Band("F4",singer,p)

    # 开演唱会
    b.play_music()

    二、面向对象的三大特征之封装

    1.什么是封装?

    在程序中封装指的是将内容隐藏起来,在面向对象中就是将属性和方法隐藏起来

    注意:封装不是单纯的隐藏

    封装是指:隐藏内部实现细节,对外提供使用接口

    2.为什么封装?

    ①提高安全性 对封装而言是通过给访问和修改增加额外的逻辑判断来实现的

    ②封装是为了明确区分内部和外部

    3.如何使用封装?

    在属性或方法名称前加两个下滑线,就可以为将其设置为私有的

    python中权限只有两种,公开的和私有的

    属性的封装 需要提供相应 的设置器和访问器

    4.封装的特点?

    被隐藏的内容 在内部可以直接访问,外部无法访问

    总结:对于被隐藏的属性 访问和修改需要通过方法 get用于获取 set用于设置(也称之为设置器和访问器)

    5.封装方法的好处

    ①提高安全性

    ②隔离复杂度 (将复杂的内容隔离到内部 外部只留下简单的接口 对于使用者难度降低)

    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()
    print(ATM.__dict__)

    6.封装的实现原理

    class Person:
      def __init__(self,name,sex,age,id_card):
        self.name=name
        self.sex=sex
        self.age=age
        self.__id_card=id_card
      def get_id_card(self,pwd):
        if pwd == '123':
          return self.__id_card
        else:
          print('你无法查看我的身份证信息!')
      def set_id_card(self,pwd,new_id_card):
        if pwd == '123':
          self.__id_card=new_id_card
        else:
          print('你没有资格修改我的身份证号!')
    p1=Person('henry','man',24,'123487349830495584')
    print(p1.__dict__)
    #结果:{'name': 'henry', 'sex': 'man', 'age': 24,
    '_Person__id_card': '123487349830495584'}

    print(p1.get_id_card('123'))
    p1.set_id_card('123','142346199810183456')
    print(p1.get_id_card('123'))

    通过__dict__可以发现
    #1.私有属性和方法名称 前自动加上了_类名 python就是通过这种装换的方式来实现封装的
    #2.只有在类的内部的双下滑线才能被自动转换,并且这个转换的过程只能执行一次,在类定义完成后后续添加的双下划綫开头的名称是不会自动转换的
    p1.__id_card='xxxxx'
    print(p1.__id_card) #结果:xxxxx
    print(p1.get_id_card('123')) #结果:123487349830495584
    #3.父类中私有的方法,子类中无法使用
    class A:
      def __f1(self):
        print("A __f1")

    class B(A):
      def __f2(self):
        self.__f1()
        print("B __f2")

      def test(self):
        self.__f2()

    b = B()
    b.test()
    #结果:报错:'B' object has no attribute '_B__f1'

    #在父类中定义的私有方法,子类中无法覆盖
    class A:
      def f(self):
        self.__f1()
      def __f1(self):
        print('A __f1')
    class B(A):
      def __f1(self):
        print('B __f1')
      def f2(self):
        self.f()
    b=B()
    b.f2()
    #结果:A __f1
    之所以无法覆盖是因为子类和父类中的私有方法名称必然不相同 子类的方法一定是子类独有的 所以无法覆盖

    7.property装饰器

    BMI案例:
    class Person:
      def __init__(self,name,weight,height):
        self.name=name
        self.weight=weight
        self.height=height
      def bmi(self):
        return self.weight/(self.height*self.height)
    p1=Person('henry',69,1.76)
    print(p1.bmi())
    p1.weight+=2
    print(p1.bmi())

    当一些属性的值 不是固定的而是通过计算得来的时候 我们必须为这个属性增加方法才能完成计算
    但是一旦使用方法后 该属性的访问就变成了方法的调用 很明显与其他的属性访问方式不同,这样给使用者造成迷惑
    所以需要将这个方法伪装成普通属性 这就用到了property装饰器
    我们可以对上述BMI代码进行装饰,将使用方法调用伪装成属性的访问
    class Person:
      def __init__(self,name,weight,height):
        self.name=name
        self.weight=weight
        self.height=height
      @property
      def bmi(self):
        return self.weight/(self.height*self.height)
    p1=Person('henry',69,1.76)
    print(p1.bmi)
    p1.weight+=2
    print(p1.bmi)

    property可以将方法伪装成属性 利用这个特点 我们也可以将其使用到封装中
    这时候就可以使用property来进行伪装 使得访问私有属性与访问普通属性的方式一致
    property还提供了 setter(用于修改属性的值) 和 deleter(删除属性的值)

    class Person:
      def __init__(self,name,sex,age,id_card):
        self.name=name
        self.sex=sex
        self.age=age
        self.__id_card=id_card
      @property
      def id_card(self):
        return self.__id_card
      @id_card.setter
      def id_card(self,new_id_card):
        self.__id_card=new_id_card
      @id_card.deleter
      def id_card(self):
        del self.__id_card
        print('身份证已删除!')

    p1=Person('henry','man',24,'123487349830495584')
    print(p1.id_card) #结果:123487349830495584

    p1.id_card='aaaaaaa'
    print(p1.id_card) #结果:aaaaaaa

    del p1.id_card
    print(p1.__dict__) #结果:{'name': 'henry', 'sex': 'man', 'age': 24}

    三、面向对象三大特征之多态

    1.什么是多态?

    一种事物具备多种形态或者状态 称之为多态

    官方解释:不同对象,可以相对应同一方法,并做出不同的行为,产生不同的结果

    2.如何实现多态?

    让几个不同类拥有相同的父类,这样一来他们就具备了相同的方法,每个子类要覆盖父类的方法,从而每个类的对象行为都不同.

    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)
    当使用了多态之后 对象的使用者不需要关系这个对象具体的实现,只需要知道该对象属于哪个基类,就能直接使用它
    如此扩展性变高了

    3.多态之abc模块

    多态是多个类的对象拥有相同的方法,但是我们没有从严格要求说必须提供这些方法,子类完全可以不提供这些方法
    # 现在要做的就是 严格要求 子类必须实现父类声明的方法
    import abc
    # abstract class 是抽象类的缩写 抽象的意思是 不清晰 不具体 看不懂

    #使用ABC模块来限制子类 的步骤
    #1.为类中指定源类为abc.ABCMeta
    #2.在相应的方法上加上abc.abstractmethod装饰器

    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)

    4.鸭子类型

    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模块 也不需要基类 自觉地将方法名字都写成一样 同样可以实现多态
    这种方式称之为鸭子类型

     

  • 相关阅读:
    Datasnap http用户验证
    Delphi 接口机制真相
    tfmxobject的序列化
    delphi md5算法
    delphi xe 窗体子控件实现窗体拖动
    Delphi笔记-自定义组件
    DELPHI RES资源文件使用方法
    Delphi中WebBrowser的使用技巧汇总
    Delphi XE调用第三方库Jni详细过程
    使用VLC进行屏幕广播
  • 原文地址:https://www.cnblogs.com/lizeqian1994/p/10139197.html
Copyright © 2011-2022 走看看