面向对象分析与设计
知识点:
-
面向对象的三大特征:从设计者的角度理解,
-
封装:将需求拆分为一个个类(分而治之)、每一个变化点封装成一个独立的类(封装变化)
-
继承:通过抽象出一个父类来约束子类,隔离子类的多变性(隔离变化)
-
多态:利用重写,使同一父类的方法在不同子类实现不同
-
-
六大原则:
-
开闭原则
-
类的单一职责
-
依赖倒置
-
组合复用原则
-
里氏替换
-
迪米特原则
-
-
类与类的关系
-
泛化关系
-
关联(组合)关系
-
依赖关系
-
案例:天龙八部技能系统
-
目的:通过练习该案例,初步理解面向对象设计思路,设计软件架构,熟悉python面向对象语法
-
需求:根据技能表设计技能系统
-
面向对象设计流程
-
思考过程:
-
拿到需求后,曾经想过将一个技能设计一个类(类的单一职责),但罗列之后发现类与类之间存在重复的部分。
-
寻找到变化点–技能的具体效果,封装成一个个类,再设计一个技能释放器类统一调用这些类
-
因为技能效果类存在变化,使用继承的特性,抽象出一个父类技能效果,用来约束这些子类,隔离这些变化。用技能释放器类调用技能效果父类,不用关注具体的子类。符合了依赖倒置的原则和开闭原则。
-
利用多态的重写特性,将子类的共性个性化,里氏替换
-
通过配置文件加载列表
-
-
这样架构的优势:
-
一个需求改变(增加一个技能效果),只需要修改一个类。避免了散弹式修改
-
增加/修改技能效果,程序不用修改。依赖注入:根据配置文件,决定程序的功能
-
-
六大原则的具体体现
-
开闭原则:增加新的影响效果,只需要创建新类, 不需要修改技能释放器.
-
类的职责单一:释放器负责释放技能. 具体影响效果类负责某一种算法. 影响效果类负责隔离释放器与具体效果的变化.
-
依赖倒置:技能释放器调用影响效果,没有调用具体效果类(伤害生命…) 子类依赖父类,但父类不依赖子类. 技能释放器通过字符串(配置文件)创建具体效果对象.
-
组合复用:技能释放器与影响效果使用关联(组合)关系,而不是继承关系.
-
里氏替换:父类出现的地方可以被子类替换,在替换后依然保持原功能(重写)所有具体影响效果,都可以将抽象(父)的影响效果替换掉
-
迪米特原则:低耦合,存在隔离。具体影响效果之间,没有联系. 技能释放器与具体影响效果也有隔离.
-
"""
天龙八部 技能系统
"""
class ImpactEffect:
"""
影响效果
"""
def impact(self):
"""
影响效果,由技能释放器调用,由具体效果类实现.
:return:
"""
raise NotImplementedError()
class DamageEffect(ImpactEffect):
"""
伤害生命效果
可以被所有需要伤害生命的技能使用
"""
def __init__(self, value):
self.value = value
def impact(self):
print("伤害你的%d生命" % self.value)
class LowerMoveSpeed(ImpactEffect):
"""
降低移动速度效果
"""
def __init__(self, speed, time):
self.speed = speed
self.time = time
def impact(self):
print("降低速度为%d,持续时间%d." % (self.speed, self.time))
class SkillDeployer:
"""
技能释放器
"""
def __init__(self, name):
self.name = name
self.__list_impact = self.__config_skill()
def __config_skill(self):
"""
配置技能
"""
# 配置文件中,记录的信息.
dict_skill_config_info = {
"金刚伏魔": ["DamageEffect(100)"],
"降龙十八掌": ["LowerMoveSpeed(50,60)", "DamageEffect(100)"]
}
# 根据键(技能名称)从字典中获取值(str列表)
list_skill_info = dict_skill_config_info[self.name]
# 根据字符串列表,创建影响效果对象的列表.
# "DamageEffect(100)" -->DamageEffect的对象
list_skill_instance = []
for item in list_skill_info:
list_skill_instance.append(eval(item))
# 返回技能列表
return list_skill_instance
# 建议使用列表推导式
# return [eval(item) for item in list_skill_info]
def generate_skill(self):
"""
生成(释放)技能
:return:
"""
print(self.name, "技能释放啦")
# 遍历影响效果列表,执行每个效果.
for item in self.__list_impact:
item.impact()
# 测试
# 创建技能(确定技能名称,加载技能效果)
xlsbz = SkillDeployer("降龙十八掌")
xlsbz.generate_skill()
jgfm = SkillDeployer("金刚伏魔")
jgfm.generate_skill()