封装
定义
1.数据角度讲,将一些基本数据类型复合成一个自定义类型。
2.行为角度讲,向类外提供必要的功能,隐藏实现的细节。
封装数据:多个数据 --> 一个种数据(新类型)
例如:学生类(姓名/年龄..) 汽车(品牌/价格..)
适用性:多种信息描述同一种事物.
3.设计角度讲:
(1)分而治之
-- 将一个大的需求分解为许多类,每个类处理一个独立的功能。 (类要小而精,拒绝大而全.)
-- 拆分好处:便于分工,便于复用,可扩展性强。
(2) 封装变化
-- 变化的地方独立封装,避免影响其他类。(分解的度,识别变化点,单独做成类.)
(3) 高 内 聚
-- 类中各个方法都在完成一项任务(单一职责的类)。(类内部,高度聚集.完成一个变化点。)
(4) 低 耦 合
-- 类与类的关联性与依赖度要低(每个类独立),让一个类的改变,尽少影响其他类。(类与类关系,尽量松散。)
[例如:硬件高度集成化,又要可插拔]
最高的内聚莫过于类中仅包含1个方法,将会导致高内聚高耦合。
最低的耦合莫过于类中包含所有方法,将会导致低耦合低内聚。
作用
简化编程,使用者不必了解具体的实现细节,只需要调用对外提供的功能。
松散耦合,降低了程序各部分之间的依赖性。
数据和操作相关联,方法操作的是自己的数据。
1.作用:无需向类外提供的成员,可以通过私有化进行屏蔽。
2.做法:命名使用双下划线开头。
3.本质:障眼法,实际也可以访问。
私有成员
私有成员的名称被修改为:_类名__成员名,可以通过_dict_属性或dir函数查看。
__slots__
作用:限定一个类创建的实例只能有固定的实例变量,不能再额外添加。
语法:
在类中定义
__slots__ = (“变量名1”,”变量名2”…..)
1.说明:含有__slots__属性的类所创建的对象没有__dict__属性, 即此实例不用字典来存储对象的实例属性。
2.优点:访止用户因错写属性的名称而发生程序错误。
3.缺点:丧失了动态语言可以在运行时为对象添加变量的灵活性。
class Wife: __slots__ = ("name","__age") def __init__(self, name, age): self.name = name self.age = age @property def age(self): return self.__age @age.setter def age(self,value): self.__age = value w01 = Wife("丽丽",26) # 因为类中定义了__slots__,所以不能在类外添加新数据. # w01.sex = "女" # w01.nmae = "莉莉" print(w01.age)
属性@property
公开的实例变量,缺少逻辑验证。私有的实例变量与两个公开的方法相结合,又使调用者的操作略显复杂。而属性可以将两个方法的使用方式像操作变量一样方便。
1.定义:
class Wife: """ 老婆 """ def __init__(self, name, age): self.name = name self.age = age @property # 拦截读取操作 def age(self): return self.__age @age.setter# 拦截写入操作 def age(self, value): if 28 <= value <= 32: self.__age = value else: raise Exception("超出年龄,我不要") # 拦截 对数据的操作,转为调用读写方法. #age = property(get_age, set_age) w01 = Wife("丽丽", 30) print(w01.age) print(w01.__dict__)
2.调用:
对象.属性名 = 数据
变量 = 对象.属性名
3.说明:
-- 通常两个公开的属性,保护一个私有的变量。
-- @property 负责读取,@属性名.setter 负责写入
-- 只写:属性名= property(None, 写入方法名)