zoukankan      html  css  js  c++  java
  • 类的组合,多态与封装

    组合

    什么是组合?组合就是对象的某个属性是另一个类的对象

    class Foo:
        def __init__(self, bar):
            self.bar = bar
    
    class Bar:
        pass
    
    # f=Foo()
    bar=Bar()
    # f=Foo(Bar())
    f=Foo(bar)
    

    这就是一个最简单的组合,那么组合又能获得什么呢?

    组合的最大用处就是减少代码的冗余

    我们可以先不用组合来定义一个父类和俩个子类:

    class Person:
        school = 'oldboy'
    
    class Teacher(Person):
        def __init__(self,name, age, level, course_name,course_price,course_period):
            self.name = name
            self.age = age
            self.level = level
    
    class Student(Person):
        def __init__(self,name,age,course,course_name,course_price,course_period):
            self.name = name
            self.age = age
            self.course = course
    

    那么如果使用组合,会怎么样呢?

    class Person:
        school = '浦之星学院'
    
    class Teacher(Person):
        def __init__(self,name, age, level, course):
            self.name = name
            self.age = age
            self.level = level
            #course是课程对象,表示老师教授的课程
            self.course = course
    
    class Student(Person):
        def __init__(self,name,age,course):
            self.name = name
            self.age = age
            # course是课程对象,表示学生选的课程
            self.course = course
    
    class Course:
        def __init__(self, course_name,course_price,course_period):
            self.name = course_name
            self.price = course_price
            self.period = course_period
    

    这样就减少了很多的代码冗余

    那么我们该如何使用组合呢?下面还是举关于学校,课程,老师,学生的例子

    class Person:
        school = '音乃木坂学院'
    class Teacher(Person):
        def __init__(self,name,age,level,course):
            self.name=name
            self.age=age
            self.level=level
            #course是课程对象,表示老师教授的课程
            self.course=course
    
    class Student(Person):
        # course=[]  #错误
        def __init__(self,name,age):
            self.name=name
            self.age=age
            # course是课程对象,表示学生选的课程
            self.course_list = []
        def choose_course(self,course):
            # self.course=[]  #错误
            #把课程对象追加到学生选课的列表中
            self.course_list.append(course)
    
        def tell_all_course(self):
            #循环学生选课列表,每次拿出一个课程对象
            for course in self.course_list:
                #课程对象.name  取到课程名字
                print(course.name)
    
    class Course:
        def __init__(self,course_name,course_price,course_period):
            self.name=course_name
            self.price=course_price
            self.period=course_period
    
    
    
    course=Course('Python',20199,7)
    stu1=Student('nick',19)
    stu1.choose_course(course)
    stu2=Student('王二丫',19)
    stu2.choose_course(course)
    stu2.choose_course(Course('linux',19999,5))
    

    那么我们如何通过对象stu1查看所有课程的名称呢?

    方法一

    通过普通函数

    def tell_all_course(student):
        for course in student.course_list:
            print(course.name)
    
    # tell_all_course(stu1)
    tell_all_course(stu2)
    

    方法二

    通过对象的绑定方法

    stu1.tell_all_course()
    

    多态与多态性

    什么是多态?多态就是一种食物的多种形态。比如说,动物类有猪,狗,人

    多态性则是指在不考虑实际类型的情况下使用实例

    多态的好处:

    增加了程序的灵活性

    增加了程序的可扩展性

    多态基础

    class Animal:
        def speak(self):
            pass
    
    class Pig(Animal):
        def speak(self):
            print('哼哼哼')
    
    class Dog(Animal):
        def speak(self):
            print('汪汪')
    
    class People(Animal):
        def speak(self):
            print('say hello')
    
    pig=Pig()
    dog=Dog()
    people=People()
    # pig.speak()
    # dog.speak()
    # people.speak()
    
    
    def animal_speak(obj):
        obj.speak()
    animal_speak(pig)
    animal_speak(people)
    

    第一种方式

    可以用abc实现接口统一化,约束代码,但是一般都不常用

    import abc
    #第一在括号中写metaclass=abc.ABCMeta
    class Animal(metaclass=abc.ABCMeta):
        #第二在要约束的方法上,写abc.abstractmethod装饰器
        @abc.abstractmethod
        def speak(self):
            pass
    
    class Pig(Animal):
        def speak(self):
            print('哼哼哼')
    class Dog(Animal):
        def yy(self):
            print('汪汪')
    
    class People(Animal):
        def zz(self):
            print('say hello')
    
    
    pig=Pig()
    pig.speak()
    
    # people = People()    # 会报错
    # people.zz()
    

    但是这样就无法利用多态性

    第二种方式

    用异常处理来实现(常用)

    class Animal():
        def speak(self):
            #主动抛出异常
            raise Exception('你得给我重写它啊')
    class Pig(Animal):
        def speak(self):
            print('哼哼哼')
    class People(Animal):
        # def speak(self):
        #     print('say hello')
    pig=Pig()
    pe=People()
    def animal_speak(obj):
        obj.speak()
    
    animal_speak(pig)	# 哼哼哼
    animal_speak(pe)   # 主动抛出异常
    

    崇尚鸭子类型

    只要走路像鸭子(对象中有某个绑定方法),那你就是鸭子

    class Pig:
        def speak(self):
            print('哼哼哼')
    class People:
        def speak(self):
            print('say hello')
    
    pig=Pig()
    pe=People()
    def animal_speak(obj):
        obj.speak()
    animal_speak(pig)
    animal_speak(pe)
    

    Linux

    #传统写法
    class File:
        def read(self):
            pass
        def write(self):
            pass
    #内存类
    class Memory(File):
        def read(self):
            print('Memory...read')
        def write(self):
            print('Memory...write')
    
    class Network(File):
        def read(self):
            print('Network...read')
        def write(self):
            print('Network...write')
    # 鸭子类型的写法
    
    # 内存类
    class Memory:
        def read(self):
            print('Memory...read')
    
        def write(self):
            print('Memory...write')
    
    class Network:
        def read(self):
            print('Network...read')
    
        def write(self):
            print('Network...write')
    
    def read(obj):
        obj.read()
    m = Memory()
    n = Network()
    read(m)
    read(n)
    

    封装

    封装是什么意思?
    从封装本身的意思去理解,
    封装就好像是拿来一个麻袋,把小猫,小狗,小王八,一起装进麻袋,然后把麻袋封上口子

    如何隐藏,把东西包装进去之后,隐藏起来,外部访问不到

    如何用代码实现隐藏
    隐藏属性/隐藏方法 隐藏之后,外部访问不到,只有内部能够访问

    隐藏属性:通过 __变量名来隐藏

    隐藏方法:通过 __方法名来隐藏

    隐藏属性是为了安全

    #name 隐藏起来
    # 隐藏属性是为了安全
    class Person:
        def __init__(self, name, age):
            self.__name=name
            self.__age=age
        def get_name(self):
            # print(self.__name)
            return '[----%s-----]'%self.__name
    
    p=Person('nick',89)
    print(p.age)
    #访问name
    print(p.name)
    print(p.__name)
    print(p.get_name())
    #隐藏的属性访问不到?实际上有方法能访问到
    #通过变形隐藏了属性
    print(p._Person__name)
    
    print(p.__dict__)
    
    #隐藏方法:隔离复杂度
    
    class Person:
        def __init__(self,name,age):
            self.__name=name
            self.__age=age
        def __speak(self):
            print('6666')
    
    p=Person('nick',89)
    p.__speak()
    print(Person.__dict__)
    p._Person__speak()
    
    #什么时候属性变形,只要再类内部,以__变量名 命名的变量,都会被隐藏,会发生的变形,在外部放入的  __变量名 属性是不隐藏的
    class Person:
        def __init__(self,name,age):
            self.__name=name
            self.__age=age
        def set_xx(self,xx):
            self.__xx=xx
    
    p=Person('nick',18)
    # ._p_xx="xxx"
    
    p.set_xx('6688')
    print(p.__dict__)
    
    #计算人的bmi指数
    #property装饰器:把方法包装成数据属性
    class Person:
        def __init__(self,name,height,weight):
            self.name=name
            self.height=height
            self.weight=weight
        @property
        def bmi(self):
            return self.weight/(self.height**2)
            # return self.weight/(self.height*self.height)
    p=Person('lqz',1.82,70)
    # print(p.bmi())
    print(p.bmi)
    # p.name='ppp'
    p.bmi=90
    

    property之setter和deleter

    class Person:
        def __init__(self,name,height,weight):
            self.__name=name
            self.__height=height
            self.__weight=weight
        @property
        def name(self):
            return '[我的名字是:%s]'%self.__name
        #用property装饰的方法名.setter
        @name.setter
        def name(self,new_name):
            # if not isinstance(new_name,str):
            if type(new_name) is not str:
                raise Exception('改不了')
            if new_name.startswith('sb'):
                raise Exception('不能以sb开头')
            self.__name=new_name
    
        # 用property装饰的方法名.deleter
        @name.deleter
        def name(self):
            # raise Exception('不能删')
            print('删除成功')
            # del self.__name
    
    p=Person('lqz',1.82,70)
    # print(p.name)
    # p.name='pppp'
    # p.name='xxx'
    #改不了,直接抛一异常
    # p.name=999
    # p.name='sb_nick'
    
    # print(p.name)
    
    del p.name
    print(p.name)
    
  • 相关阅读:
    Windows下获取逻辑cpu数量和cpu核数量
    QtScript, QML, Quick1, Quick2, Declarative 之间的关系
    将QT开发的界面程序封装成DLL,在VC中成功调用(必须有消息循环,所以使用了QTWinmigrate,附CSDN可下载的Demo)
    QPixmap的缓冲区
    Qt+QZXing编写识别二维码的程序
    ASP.NET 5:依赖注入
    angularJS之使用指令封装DOM操作
    Windows 10技术布局,谈微软王者归来
    Microsoft dotnetConf 2015
    Net社区虚拟大会
  • 原文地址:https://www.cnblogs.com/hyc123/p/11426189.html
Copyright © 2011-2022 走看看