组合
what? 组合是指一个对象中,包含另一个或多个对象。
why? 减少代码的冗余。
How? 在类中加入其他类的对象,实现跨类对象之间的联动。
耦合度 软件设计要 高内聚,低耦合。
耦合度越高,程序的可扩展性越低
耦合度越低,程序的可扩展性越高
继承与组合的区别:
继承代表【是】的关系,是类和类之间的关系,老师类是人类,学生类是人类。子类和父类是从属关系。
组合代表【有】的关系,是对象和对象之间的关系,老师对象 有 课对象,学生对象 有 课对象。表示拥有某种属性或者方法。
组合
组合的精髓在与将一个对象作为某个类的特有属性,然后通过该特有属性(赋的是其他类的对象的值)再去调用对象所在类的方法,实现多种功能的拼接。
举例:
# _*_ coding: gbk _*_ # @Author: Wonder ''' 练习需求: 选课系统: 1.有学生、老师类,学生与老师有属性 “名字、年龄、性别、 课程”, 2.有方法 老师与学生可以添加课程, 打印学习/教授课程。 # 组合实现 ''' class People: def __init__(self, name, age, gender): self.name = name self.age = age self.gender = gender def add_course(self, course_obj): self.course_list.append(course_obj) def course_info(self): for course_obj in self.course_list: course_obj.show()#通过对象去找该对象能取到的方法 class Teacher(People): def __init__(self, name, age, gender): super().__init__(name, age, gender) self.course_list = [] #存放交互对象的容器 class Student(People): def __init__(self, name, age, gender): super().__init__(name, age, gender) self.course_list = [] class Course: def __init__(self, course_name, course_price, course_cycle): self.course_name = course_name self.course_price = course_price self.course_cycle = course_cycle def show(self): print(f''' =======选的课为:======= course_name = {self.course_name} course_price = {self.course_price} course_cycle = {self.course_cycle} ''') t1 = Teacher('abc', 19, 'male') python_obj = Course('PYTHON', 10000, '6month') # 统一称之为course_obj go_obj = Course('GO', 5000, '4month') t1.add_course(python_obj) t1.add_course(go_obj) t1.course_info() t1永远只会调用自己本身或者父类的函数,组合的类,由组合的对象去调用
封装
什么是封装:将一堆属性和方法封装到对象中去,可以通过【对象名.】的方式进行调用。
封装使得对数据的提取更加方便。
封装中的访问限制机制
what 凡是在类内部定义的属性和方法,以__开头的属性和方法,都会被限制,外部不能直接使用该属性原型。类似于将该属性或方法隐藏起来了。通过在属性或函数前面加上 _ _将该属性或方法隐藏起来, 本质上是一种变形操作。 _ _name 等价于 _ 类名_ _ 属性名
why 可以将一些隐私数据隐藏起来,不让外部轻易获取。
可以将一堆数据封装成接口,让用户直接调用,并通过相应的逻辑,最后将数据返回。
how :如果知道类名以及被隐藏是数据或者方法名,可以通过【_类名__属性/方法名】进行调用
例如 :
# _*_ coding: gbk _*_ # @Author: Wonder class People: __school = 'HEU' def __init__(self, name, age, gender): self.__name = name self.__age = age self.__gender = gender def __show(self): print('隐藏了吗') human1 = People('wonder', 19, 'male') print(human1.__school) #People' object has no attribute '__school' print(human1._People__school) #HEU print(human1.__name) # AttributeError: 'People' object has no attribute '__name' print(human1._People__name) #wonder human1.__show() # AttributeError: 'People' object has no attribute '__show' human1._People__show() # 隐藏了吗
用_ _隐藏的主要目的是想将属性或者方法限制在类中使用,不想被外界调用。
property本质上是一个装饰器,用来装饰类内部的方法(在被装饰方法上方,使用语法糖@property,进而将 原先的【类名.方法名()】调用方式改变为【类名.方法名】
如果被property装饰过的方法,想要改变他的值,只可以通过@被装饰方法名.setter以及@被装饰方法名.deleter进行修改和删除操作。
# _*_ coding: gbk _*_ # @Author: Wonder # class Securty: # def __init__(self, name, gender, height, weight): # self.__name = name # self.gender = gender # self.height = height # self.weight = weight # # def hw(self): # return (self.height + self.weight) # # @property # def sex(self): # return self.gender # # @property # def namey(self): # return self.__name # s1 = Securty('wonder', 'male', 190, 200) # print(s1.hw()) # 390 # print(s1.sex()) # TypeError: 'str' object is not callable # print(s1.sex) # male # print(s1.namey) # wonder
__name是可以被return出来的。见上面红色背景的语句及执行结果。
# 想修改或删除被property装饰的属性 class Sure: def __init__(self, name, ): self.__name = name @property def namey(self): return self.__name @namey.setter def namey(self, value): if not isinstance(value, str): raise TypeError('FUCK_NO') self.__name = value @namey.deleter def namey(self): # del self.__name # 执行删除操作 # 如果将改为raise TypeError('forbidden') raise TypeError('forbidden') name1 = Sure('GOOGLE') print(name1.namey) # GOOGLE name1.namey = 'YAHOO' # 修改值操作 print(name1.namey) # YAHOO del name1.namey #删除操作 print(name1.namey) # 如果删除了,则会报错AttributeError: 'Sure' object has no attribute '_Sure__name'。否则还是YAHOO