如何初始化抽象类的子类?黑魂风格文本游戏两种方案对比
关于《黑暗之魂》风格文本游戏角色类初始化方案的分析
我正在开发一款《黑暗之魂》风格的文本类游戏,已经创建了定义角色特性的Character抽象类,要求子类仅需接收name参数,其余属性为各子类特定值。我写出了两种初始化实现方式,不确定哪种更优,也想了解是否有更合适的方案(刚接触继承与抽象类)。
两种原始实现代码
第一种实现
from abc import ABC class Character(ABC): def __init__(self, name, description, health, endurance, strength) -> None: self.name = name self.description = description self.health = health self.endurance = endurance self.strength = strength class Giant(Character): def __init__(self, name) -> None: super().__init__(name, description="giant", health=500, endurance=20, strength=100)
第二种实现
from abc import ABC class Character(ABC): def __init__(self, name) -> None: self.name = name self.description = '' self.health = 0 self.endurance = 0 self.strength = 0 class Giant(Character): def __init__(self, name) -> None: super().__init__(name) self.description = "giant" self.health = 500 self.endurance = 20 self.strength = 100
两种方案的优劣分析
第一种方案
- 优点:父类初始化明确要求所有核心属性必须传入,确保角色对象初始化时状态完整,不会出现属性缺失的情况;子类通过
super()一次性传递所有参数,所有属性值集中展示,可读性强。 - 缺点:如果后续父类新增属性,所有子类都需要修改
super()的调用参数,维护成本会随着属性增多而上升。
第二种方案
- 优点:父类初始化仅需
name参数,子类修改属性的操作更灵活。 - 缺点:父类给属性设置了默认值(如
health=0),若子类忘记覆盖这些默认值,会生成不符合预期的无效角色(比如生命值为0的巨人),容易引入bug;属性赋值分散在父类和子类两处,需要跨文件/类查看才能知道角色的完整属性,可读性差。
更优的实现思路
思路一:类属性+父类统一初始化
将子类的固定属性定义为类属性,父类在初始化时自动读取这些类属性赋值给实例,子类无需编写__init__方法:
from abc import ABC class Character(ABC): # 定义父类模板属性,子类需覆盖 description = "" health = 0 endurance = 0 strength = 0 def __init__(self, name) -> None: self.name = name # 从子类的类属性中读取固定值 self.description = self.__class__.description self.health = self.__class__.health self.endurance = self.__class__.endurance self.strength = self.__class__.strength class Giant(Character): # 子类仅需定义自己的固定类属性 description = "giant" health = 500 endurance = 20 strength = 100 # 使用示例 giant = Giant("山丘巨人") print(giant.health) # 输出500
优势:代码简洁,子类无需重复编写初始化逻辑;所有固定属性集中在子类的类属性区域,可读性强、修改方便;父类的默认值能快速暴露子类的属性遗漏问题。
思路二:抽象方法强制子类提供属性值
利用抽象类的特性,强制子类实现返回属性值的方法,从根源上避免属性遗漏:
from abc import ABC, abstractmethod class Character(ABC): def __init__(self, name) -> None: self.name = name # 通过抽象方法获取子类的属性值 self.description, self.health, self.endurance, self.strength = self.get_character_stats() @abstractmethod def get_character_stats(self): """子类必须实现该方法,返回(description, health, endurance, strength)""" pass class Giant(Character): def get_character_stats(self): return ("giant", 500, 20, 100) # 使用示例 giant = Giant("山丘巨人") print(giant.strength) # 输出100
优势:通过抽象方法强制子类必须定义所有属性,完全杜绝属性遗漏的bug;所有属性值集中在一个方法内,逻辑清晰;父类初始化逻辑统一,子类只需关注自身属性的返回。
总结
如果追求代码简洁和可读性,优先选择类属性+父类统一初始化的方案;如果需要严格约束子类的实现,避免遗漏属性,可选择抽象方法强制返回属性值的方案。这两种思路都比原始的两种方案更符合抽象类的设计初衷,也更易于后续维护。
内容的提问来源于stack exchange,提问作者propserouspi404
相关产品推荐
相关产品推荐

