面向对象封装案例
1. 封装
- 封装 是面向对象编程的一大特点
- 面向对象编程的 第一步—— 将 属性 和 方法 封装 到一个抽象的 类 中
- 外界 使用 类 创建 对象,都被 封装 在 类的内部
- 对象方法的细节 都被 封装 在 类的内部
"""
小明爱跑步
小明 体重 75.0 公斤
小明每次 跑步 会减肥 0.5 公斤
小明每次 吃东西 体重增加 1 公斤
"""
class Person:
# 属性 名字 体重
def __init__(self, name, weight): # 使用 __init__方法 来封装属性
# self.name = "小明" # 这种定义属性的方式,让属性值 变得不灵活
# self.weight = 75.0
self.name = name
self.weight = weight
def __str__(self): # 当使用 print(对象名) 的时候,会调用该方法, print(对象名) 不再 输出 对象的 引用/id
return f"我的名字是{self.name},我的体重是{self.weight}kg"
# 方法 跑步 吃东西
def run(self): # 执行 跑步的方法,会对 weight 产生影响
self.weight -= 0.5 # -----> 在方法中,访问 对象的 属性
print(f"{self.name} 爱跑步,跑步能够锻炼身体! 锻炼之后的体重为{self.weight}kg")
def eat(self): #
"""
说明: 调用 eat 方法,和 run方法,会对 属性 weight 产生影响,但是方法不一定会 使用这些属性
:return:
"""
self.weight += 1 # -----> 在方法中,访问 对象的 属性
print(f"{self.name}是个吃货,吃完这顿再减肥,体重变成了{self.weight}kg")
# 根据类 创建 对象
xiaoming = Person("小明", 75.0)
xiaoming.eat()
print(xiaoming.weight)
print(xiaoming) # <__main__.Person object at 0x000002E02682FFD0>
# __str__方法的返回值: 我的名字是小明,我的体重是76.0kg
提示
在 对象的方法内部,是可以 直接访问对象的属性的
同一个类 创建的 多个对象,属性 互不干扰
"""
房子(house)有 户型、总面积 和 家具名称列表
新房子没有任何家具
家具(HouseItem)有 名字 和 占地面积,其中
席梦思(bed)占地 4 平米
衣柜(chest)占地 2 平米
餐桌(table)占地 1.5 平米
将以上三件 家具 添加 到 房子 中
打印房子时,要求输出:户型、总面积、剩余面积、家具名称列表
"""
# 创建家具类
class HouseItem:
def __init__(self, name, area):
self.name = name # 家具的名称
self.area = area # 家具的占地面积
def __str__(self):
return f"{self.name}占地{self.area}平方米"
bed = HouseItem("席梦思", 4)
chest = HouseItem("大衣柜", 2)
table = HouseItem("餐桌", 1.5)
# 创建房子类
class House:
def __init__(self, house_type, area): # 创建对象的时候,对象传递了属性,属性 会传递给 __init__(self)
self.house_type = house_type # 定义户型
self.area = area # 定义 总面积
self.free_area = area # 默认情况,剩余面积 和 房屋总面积相等
self.item_list = [] # 家具列表为空
def __str__(self): # 返回 房屋属性信息
return f"户型:{self.house_type}\n总面积{self.area}\n" \
f"剩余面积{self.free_area}\n家具列表:{self.item_list}"
def add_item(self, item): # item是家具名称---> 另外的 对象 对剩余面积 和 家具列表 产生影响
print(f"要添加{item}")
# 家具 面积 > 剩余面积 ----》报错
if item.area > self.free_area:
print(f"{item.name}的面积太大了,不能添加")
return
# 正常情况 添加家具, 将家具名称 添加到 家具列表
self.item_list.append(item.name)
# 添加完家具,剩余面积 的计算
self.free_area -= item.area
my_house = House("两居室", 60) # 创建 house 对象
my_house.add_item(bed)
my_house.add_item(chest)
my_house.add_item(table)
print(my_house)
"""
tips:
整理代码 : ctrl + alt + L
debug: shift + f9
"""
小结:
- 创建了一个 房子类,使用到 init 和 str 两个内置方法
- 准备了一个 add_item 方法 准备添加家具
- 使用 房子类 创建了 一个房子对象
- 让 房子对象 调用了三次 add_item 方法,将 三件家具 以 实参 传递到 add_item内部
进阶案例
一个对象的 属性 可以是 另外一个类创建的对象
"""
士兵突击
需求
1. 士兵 许三多 有一把 AK47
2. 士兵 可以 开火
3.枪 能够 发射 子弹
4.枪 填装 子弹——增加子弹数量
"""
# 创建2个类
# 枪 ---> 95式
class Gun:
def __init__(self, model): # 枪的属性
self.model = model # 型号
self.b_count = 0 # 子弹数量
# 添加子弹
def add_bullet(self, count):
self.b_count += count
# 射击 ---》 枪如果没有子弹,不能射击 当能够射击的时候,对子弹数量产生影响
def shoot(self):
# 1 判断子弹数量
if self.b_count <= 0:
print(f"{self.model}没有子弹了!")
return
# 2 有子弹,发射子弹,每射击一次, 子弹数量 -1
self.b_count -= 1
# 3 发射子弹的提示信息
print(f"{self.model} 哒哒哒~ {self.b_count}")
"""
开发士兵类
假设:每一个新兵 都 没有枪
定义没有初始值的属性
在定义属性时,如果 不知道什么是初始值,可以设置为 None
None 关键字 表示 什么都没有
表示一个 空对象,没有方法和属性,是一个特殊的常量
可以将 None 赋值给任何一个变量
"""
# 创建 士兵 类
class Solider:
def __init__(self, name):
# 姓名
self.name = name
# 新兵没有枪 --> 设定 gun 为 对象的一个 属性
self.gun = None # gun 表示的是一个 外部对象
def fire(self): # 士兵 可以开枪
# 判断 士兵是否有枪
if self.gun == None:
print(f"{self.name}还没有枪!")
return
# 2. 高喊口号
print(f" {self.name}冲啊!!!!!!")
# 3 装子弹
self.gun.add_bullet(30) # gun 对象的方法
# 4 开枪射击
self.gun.shoot() # gun 对象的方法
# 创建 枪对象
ak_47 = Gun("AK-47")
# 创建士兵 对象
xusd = Solider("许三多")
xusd.gun = ak_47
xusd.fire()
小结
- 创建了一个 士兵类,使用到 init 内置方法
- 在定义属性时,如果 不知道设置什么初始值,可以设置为 None
- 在 封装的方法内部,还可以让 自己 使用其他类创建的对象属性 & 调用已经 封装好的方法