You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何初始化抽象类的子类?黑魂风格文本游戏两种方案对比

关于《黑暗之魂》风格文本游戏角色类初始化方案的分析

我正在开发一款《黑暗之魂》风格的文本类游戏,已经创建了定义角色特性的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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.31 23:50:34