P137 Python面向对象-5.1 课程回顾
一、Day12复习
"""
复习
View Model Controller
界面 数据 业务逻辑
变化 载体 变化
"""
class XXController:
def add_xx(self, a):
print("Controller 添加了数据", a)
class XXView:
def __init__(self):
self.c = XXController()
def input_xx(self):
# 需求:调用XXController类中的实例方法add_xx
self.c.add_xx(100)
v = XXView()
v.input_xx()
P138 Python面向对象-5.2 课后作业解析
一、练习1
在class StudentManagerController类内添加排序函数:
def order_by_score(self):
"""
根据成绩,对self.__stu_list进行升序排列
"""
for r in range(len(self.__stu_list) - 1):
for c in range(r + 1, len(self.__stu_list)):
if self.__stu_list[r].score > self.__stu_list[c].score:
self.__stu_list[r], self.__stu_list[c] = self.__stu_list[c], self.__stu_list[r]
在class StudentManagerView类内添加函数:
def __output_student_by_score(self):
self.__manager.order_by_score()
self.__output_students(self.__manager.stu_list)
P139 Python面向对象-5.3 继承
一、继承
"""
继承 -- 方法
财产:钱不用孩子挣,但是可以花。
皇位:江山不用孩子打,但是可以坐。
代码:子类不用写,但是可以用。
"""
'''
# 多个子类在概念上一致的,所以就抽象出一个父类.
# 多个子类的共性,可以提取到父类中.
# 在实际开发过程中:
# 从设计角度讲:先有子,再有父.
# 从编码角度讲:先有父,再有子.
'''
class Person:
def say(self):
print("说话")
class Student(Person):
def study(self):
print("学习")
class Teacher(Person):
def teach(self):
print("讲课")
P140 Python面向对象-5.4 继承的方法
一、继承的方法和父类子类间的关系
class Person:
def say(self):
print("说话")
class Student(Person):
def study(self):
print("学习")
class Teacher(Person):
def teach(self):
print("讲课")
'''
继承的方法
'''
s01 = Student()
# 子类对象可以调用子类成员,也可以调用父类成员.
s01.study()
s01.say() # 父类成员
p01 = Person()
# 父类对象只可以调用父类成员,不能调用子类成员.
p01.say()
'''
父类和子类间的关系
'''
t01 = Teacher()
# python 内置函数
# 1. 判断对象是否属于一个类型
# "老师对象" 是 一个老师类型
print(isinstance(t01, Teacher)) # True
# "老师对象" 不是 一个学生类型
print(isinstance(t01, Student)) # False
# "老师对象" 是 一个人类型
print(isinstance(t01, Person)) # True
# 2.判断一个类型是否属于另一个类型
# "老师类型" 不是 一个学生类型
print(issubclass(Teacher, Student)) # False
# "老师类型" 是 一个人类型
print(issubclass(Teacher, Person)) # True
# "人类型" 不是 一个老师类型
print(issubclass(Person, Teacher)) # False
练习
"""
定义父类
动物(行为:叫)
定义子类
狗(行为:跑)
鸟(行为:飞)
创建三个类型的对象
体会:isinstance(对象,类型)
体会:issubclass(类型,类型)
"""
class Animal:
def shout(self):
print("喊叫")
class Bird(Animal):
def fly(self):
print("飞")
class Dog(Animal):
def run(self):
print("跑")
animal = Animal()
bird = Bird()
dog = Dog()
print(isinstance(animal, Bird))
print(isinstance(dog, Animal))
print(issubclass(Animal, Bird))
print(issubclass(Dog, Animal))
P141 Python面向对象-5.5 继承的变量
一、继承的变量
"""
继承 -- 变量
"""
class Person:
def __init__(self, name):
self.name = name
"""
class Student(Person):
# 子类若没有构造函数,使用父类的.
pass
s01 = Student()
print(s01.name)
"""
class Student(Person):
# 子类若具有构造函数,则必须先调用父类构造函数。
def __init__(self, name, score):
super().__init__(name)
self.score = score
p01 = Person("李四")
print(p01.name)
s01 = Student("张三", 100)
print(s01.score)
print(s01.name)
内存图
练习
"""
定义父类
车(数据:品牌,速度)
定义子类
电动车(数据:电池容量,充电功率)
创建两个对象
画出内存图.
"""
class Car:
"""
车
"""
def __init__(self,brand,speed):
self.brand = brand
self.speed = speed
class Electrocar(Car):
"""
电动车
"""
def __init__(self,brand,speed,battery_capacity,charging_power):
super().__init__(brand,speed)
self.battery_capacity = battery_capacity
self.charging_power = charging_power
c01 = Car("奔驰",230)
print(c01.brand)
e01 = Electrocar("比亚迪",120,15000,220)
print(e01.brand)
print(e01.charging_power)
P142 Python面向对象-5.6 继承的设计01
一、面向对象设计原则:开-闭原则
Open Closed Principle
对扩展开放,对修改关闭。
增加新功能,不改变原有代码。
示例代码
# 需求:老张开车去东北
# 变化: 坐飞机
# 坐火车
# 骑车
# ...
'''
# 违反了开闭原则:
# 如果增加火车,需要增加"火车类",再修改人类中的go_to方法.
'''
class Person:
def __init__(self, name):
self.name = name
def go_to(self, vehicle, str_position):
# 如果是汽车
if type(vehicle) == Car:
vehicle.run(str_position)
# 否则如果是飞机
elif type(vehicle) == Airplane:
vehicle.flay(str_position)
class Car:
def run(self, str_position):
print("汽车开到", str_position)
class Airplane:
def flay(self, str_position):
print("飞机飞到", str_position)
p01 = Person("老张")
c01 = Car()
a01 = Airplane()
p01.go_to(c01, "东北")
p01.go_to(a01, "东北")
示意图
P143 Python面向对象-5.7 继承的设计,多态
一、面向对象设计原则
1、类的单一职责(一个类的定义)
Single Responsibility Principle
一个类有且只有一个改变它的原因。
2、依赖倒置(依赖抽象)
Dependency Inversion Principle
客户端代码(调用的类)尽量依赖(使用)抽象的组件。
抽象的是稳定的。实现是多变的。
二、依赖倒置原则更替上述示意图
三、多态
父类的同一种动作或者行为,在不同的子类上有不同的实现。
用多态改进之前的代码,使其满足开闭原则
# 需求:老张开车去东北
# 变化: 坐飞机
# 坐火车
# 骑车
# ...
class Vehicle:
"""
交通工具,代表所有具体的交通工具(火车/飞机..)
继承:隔离子类变化,将子类的共性(坐/飞..)提取到父类(运输)中.
"""
def transport(self, str_position):
# 因为父类太过于抽象,所以写不出方法体.
pass
# 客户端代码,用交通工具。
class Person:
def __init__(self, name):
self.name = name
def go_to(self, vehicle, str_position):
# 多态:调用父,执行子.
# 调用的是交通工具的运输方法
# 执行的是飞机的运输方法或者汽车的运输方法
vehicle.transport(str_position)
# -------以上是架构师完成的--以下是程序员完成的-----
class Car(Vehicle):
def transport(self, str_position):
print("汽车开到", str_position)
class Airplane(Vehicle):
def transport(self, str_position):
print("飞机飞到", str_position)
p01 = Person("老张")
c01 = Car()
a01 = Airplane()
p01.go_to(c01, "东北")
p01.go_to(a01, "东北")
P144~145 Python面向对象-5.8&5.9 习题练习01&02
一、练习1
"""
手雷炸了,可能伤害敌人/玩家的生命.
还可能伤害未知事物(鸭子.房子....)
要求:增加了新事物,不影响手雷。
体会:继承的作用
多态的体现
设计原则
开闭原则
单一职责
依赖倒置
画出设计图
15:35
"""
class Granade:
def __init__(self, atk):
self.atk = atk
def explode(self, damage_target):
# 如果传入的不是子类,则报错.
if not isinstance(damage_target, Damageable):
raise ValueError("不是Damageable的子类")
print("爆炸")
# 多态:
# 调用父类代表(玩家/敌人.....)的可以受伤者.
# 执类行子(具体玩家/敌人.....)
damage_target.damage(self.atk)
class Damageable:
"""
可以受伤
继承:统一多个子类的概念,隔离变化。
"""
def damage(self, value):
# 如果子类不重写,则异常。
raise NotImplementedError()
# ------------------------------
class Player(Damageable):
def __init__(self, hp):
self.hp = hp
def damage(self, value):
self.hp -= value
print("玩家受伤啦")
print("碎屏")
class Enemy(Damageable):
def __init__(self, hp):
self.hp = hp
def damage2(self, value):
self.hp -= value
print("敌人受伤喽")
print("头顶爆字")
g01 = Granade(100)
e01 = Enemy(200)
p01 = Player(300)
g01.explode(p01)
示意图
P146 Python面向对象-5.10 习题练习03
一、练习1
"""
定义图形管理器类
1. 管理所有图形
2. 提供计算所有图形总面积的方法
具体图形:
圆形(pi × r ** 2)
矩形(长*宽)
...
测试:
创建1个圆形对象,1个矩形对象,添加到图形管理器中.
调用图形管理器的计算面积方法,输出结果。
要求:增加新图形,不修改图形管理器的代码.
体会:面向对象三大特征:
封装/继承/多态
面向对象设计原则:
开闭/单一/倒置
"""
class GraphicManager:
def __init__(self):
self.__graphics = []
def add_graphic(self, graphic):
if isinstance(graphic, Graphic):
self.__graphics.append(graphic)
else:
raise ValueError()
def get_total_area(self):
total_area = 0
# 遍历图形列表,累加每个图形的面积
for item in self.__graphics:
# 多态:
# 调用的是图形
# 执行的是圆形/矩形...
total_area += item.calculate_area()
return total_area
class Graphic:
def calculate_area(self):
# 如果子类不重写,则异常.
raise NotImplementedError()
#-----------------------------------
class Circle(Graphic):
def __init__(self,radius):
self.radius = radius
def calculate_area(self):
return 3.14 * self.radius **2
class Rectanlge(Graphic):
def __init__(self,length,width):
self.lenght = length
self.width = width
def calculate_area(self):
return self.lenght * self.width
c01 = Circle(5)
r01 = Rectanlge(10,20)
manager = GraphicManager()
manager.add_graphic(c01)
manager.add_graphic(r01)
re = manager.get_total_area()
print(re)
示意图
P147 Python面向对象-5.11 类与类的关系
一、类与类的关系
泛化
子类与父类的关系,概念的复用,耦合度最高;
B类泛化A类,意味B类是A类的一种;
做法:B类继承A类
关联(聚合/组合)
部分与整体的关系,功能的复用,变化影响一个类;
A与B关联,意味着B是A的一部分;
做法:在A类中包含B类型成员。
依赖
合作关系,一种相对松散的协作,变化影响一个方法;
A类依赖B类,意味A类的某些功能靠B类实现;
做法:B类型作为A类中方法的参数,并不是A的成员。
二、设计原则:组合复用原则(复用的最佳实践)
Composite Reuse Principle
如果仅仅为了代码复用优先选择组合复用,而非继承复用。
组合的耦合性相对继承低。
举例示意图
P148 Python面向对象-5.12 作业及总结
一、继承
语法
- 代码
class 子类(父类):
def init(self,参数列表):
super().init(参数列表)
self.自身实例变量 = 参数 - 说明
– 子类拥有父类的所有成员。
– 子类如果没有构造函数,将自动执行父类的,但如果有构造函数将覆盖父类的。此时必须通过super()函数调用父类的构造函数,以确保父类属性被正常创建。
定义
- 重用现有类的功能与概念,并在此基础上进行扩展。
- 说明:
– 子类直接具有父类的成员(共性),还可以扩展新功能。
– 事物具有一定的层次、渊源,继承可以统一概念。
例如:公司组织架构
老板
行政中心 营销中心 技术中心
人力资源 行政部 销售部 策划部 研发部 产品部
优点
- 一种代码复用的方式。
- 以层次化的方式管理类。
缺点
耦合度高
作用
隔离客户端代码与功能的实现方式。
适用性
多个类在概念上是一致的,且需要进行统一的处理。
二、多态
定义
父类的同一种动作或者行为,在不同的子类上有不同的实现。
作用
- 继承将相关概念的共性进行抽象,多态在共性的基础上,体现类型的个性化(一个行为有不同的实现)。
- 增强程序扩展性,体现开闭原则。
重写
子类实现了父类中相同的方法(方法名、参数),在调用该方法时,实际调用的是子类的方法。