人狗大战Ⅰ-2:面向对象关系详解

下面以“人狗大战”为场景,系统梳理面向对象中继承、组合、聚合、关联、依赖5种核心关系,通过战斗细节直观展示每种关系的特性与区别。

场景核心逻辑

  • 所有角色(人、狗)都是“生物”,共享生命值、受伤等基础特性(继承);
  • 人自带拳头、狗自带牙齿,这些是身体不可分割的部分(组合);
  • 人可持有武器、狗可佩戴项圈,这些装备可独立存在并更换(聚合);
  • 角色的敌人可以是任何人、狗或其他生物,用列表长期存储(关联);
  • 战斗中可临时使用药水疗伤,用完即弃(依赖)。

代码实现与关系解析

1. 继承(Inheritance):“是一种”(is-a)的层级关系

定义:子类是父类的“特殊类型”,继承父类的属性和方法,实现共性复用。
场景:人(Human)和狗(Dog)都是“生物(Creature)”,共享“生命值”“受伤”“存活判断”等基础能力。

class Creature:
    """生物基类(所有角色的父类)"""
    def __init__(self, name, hp=100):
        self.name = name  # 名称
        self.hp = hp      # 生命值

    def take_damage(self, damage):
        """所有生物都会受伤(共性方法)"""
        self.hp = max(0, self.hp - damage)
        return f"{self.name}受{damage}点伤害,剩余{self.hp}血"

    def is_alive(self):
        """所有生物都能判断是否存活(共性方法)"""
        return self.hp > 0


# 人类:继承自生物(“人是一种生物”)
class Human(Creature):
    def __init__(self, name):
        super().__init__(name)  # 继承父类的属性初始化

# 狗:继承自生物(“狗是一种生物”)
class Dog(Creature):
    def __init__(self, name):
        super().__init__(name)

2. 组合(Composition):“不可分离的部分”(整体包含部分,部分依赖整体)

定义:部分是整体“与生俱来”的组成部分,脱离整体后无意义,整体销毁时部分也会销毁。
场景:人的拳头、狗的牙齿是身体的一部分,创建角色时自动生成,无法单独存在或分离。

class Fist:
    """人的拳头(组合:人体不可分割的部分)"""
    def hit(self):
        return 5  # 拳头攻击力(仅作为人的一部分生效)


class Tooth:
    """狗的牙齿(组合:狗体不可分割的部分)"""
    def bite(self):
        return 8  # 牙齿伤害(仅作为狗的一部分生效)


# 完善人类:包含拳头(组合关系)
class Human(Creature):
    def __init__(self, name):
        super().__init__(name)
        self.fist = Fist()  # 创建人时自动生成拳头(不可分离)

# 完善狗类:包含牙齿(组合关系)
class Dog(Creature):
    def __init__(self, name):
        super().__init__(name)
        self.tooth = Tooth()  # 创建狗时自动生成牙齿(不可分离)

3. 聚合(Aggregation):“可分离的部分”(整体包含部分,部分独立存在)

定义:部分是整体“可附加”的组件,可独立存在(如武器可丢在地上),整体和部分的生命周期互不影响。
场景:人持有的武器、狗佩戴的项圈,可单独创建后“附加”到角色上,也可随时分离。

class Weapon:
    """武器(聚合:可被人持有,脱离人仍有意义)"""
    def __init__(self, name, damage):
        self.name = name    # 武器名称(如“长剑”)
        self.damage = damage  # 攻击力


class Collar:
    """项圈(聚合:可被狗佩戴,取下后仍存在)"""
    def __init__(self, material):
        self.defense = 2 if material == "金属" else 1  # 防御加成(金属项圈更强)


# 完善人类:支持持有武器(聚合关系)
class Human(Creature):
    def __init__(self, name):
        super().__init__(name)
        self.fist = Fist()  # 组合
        self.weapon = None  # 聚合:初始无武器,可后续添加(如捡起地上的剑)

# 完善狗类:支持佩戴项圈(聚合关系)
class Dog(Creature):
    def __init__(self, name):
        super().__init__(name)
        self.tooth = Tooth()  # 组合
        self.collar = None    # 聚合:初始无项圈,可后续佩戴(如主人给戴的项圈)

4. 关联(Association):“长期的对象引用”(非整体-部分,对象间稳定联系)

定义:两个独立对象之间存在“有一个”(has-a)的长期引用关系,不涉及“整体-部分”,仅体现稳定的互动绑定。
场景:角色的“敌人列表”(enemies)存储多个生物(人、狗等),长期持有引用(即使不战斗,敌人关系也存在)。

class Human(Creature):
    def __init__(self, name):
        super().__init__(name)
        self.fist = Fist()
        self.weapon = None
        self.enemies = []  # 关联:用列表存储多个敌人(长期引用,可是人/狗/其他生物)

    def add_enemy(self, enemy):
        """添加敌人(管理关联关系):敌人必须是生物,且不能是自己"""
        if isinstance(enemy, Creature) and enemy not in self.enemies and enemy != self:
            self.enemies.append(enemy)
            return f"{self.name}将{enemy.name}({type(enemy).__name__})列为敌人"
        return f"无法将{getattr(enemy, 'name', '未知目标')}列为敌人"

    def attack(self, target):
        """攻击指定目标(需验证目标是否在敌人列表中)"""
        if not self.is_alive():
            return f"{self.name}已倒下,无法攻击"
        if target not in self.enemies:
            return f"{target.name}不在{self.name}的敌人列表中,无法攻击"
        if not target.is_alive():
            return f"{target.name}已倒下,无需攻击"

        # 用武器或拳头攻击(聚合/组合的应用)
        damage = self.weapon.damage if self.weapon else self.fist.hit()
        target.take_damage(damage)
        weapon_name = self.weapon.name if self.weapon else "拳头"
        return f"{self.name}用{weapon_name}攻击{target.name},造成{damage}点伤害"


class Dog(Creature):
    def __init__(self, name):
        super().__init__(name)
        self.tooth = Tooth()
        self.collar = None
        self.enemies = []  # 关联:敌人列表(可包含人/狗等任何生物)

    def add_enemy(self, enemy):
        """添加敌人(逻辑同人类)"""
        if isinstance(enemy, Creature) and enemy not in self.enemies and enemy != self:
            self.enemies.append(enemy)
            return f"{self.name}将{enemy.name}({type(enemy).__name__})列为敌人"
        return f"无法将{getattr(enemy, 'name', '未知目标')}列为敌人"

    def bite(self, target):
        """撕咬指定目标(需验证目标是否在敌人列表中)"""
        if not self.is_alive():
            return f"{self.name}已倒下,无法撕咬"
        if target not in self.enemies:
            return f"{target.name}不在{self.name}的敌人列表中,无法撕咬"
        if not target.is_alive():
            return f"{target.name}已倒下,无需撕咬"

        # 用牙齿撕咬,项圈减少敌人伤害(组合/聚合的应用)
        damage = self.tooth.bite()
        if self.collar:
            damage -= self.collar.defense  # 金属项圈减伤
            damage = max(1, damage)
        target.take_damage(damage)
        return f"{self.name}撕咬{target.name},造成{damage}点伤害"

5. 依赖(Dependency):“临时的方法级使用”(用完即断,无长期引用)

定义:一个类的方法临时使用另一个类的对象,仅在方法调用时存在关系,不长期持有引用(用完即断)。
场景:战斗中临时使用“药水”疗伤,药水仅在使用时被引用,使用后角色不会保留对药水的引用。

class Potion:
    """治疗药水(被依赖的类:仅临时使用)"""
    def __init__(self, heal_amount):
        self.heal_amount = heal_amount  # 治疗量

    def restore(self, target):
        """临时为目标恢复生命值(仅在调用时生效)"""
        target.hp = min(100, target.hp + self.heal_amount)
        return f"药水为{target.name}恢复{self.heal_amount}血,当前{target.hp}血"


# 人类添加“使用药水”方法(依赖关系)
class Human(Creature):
    # (省略之前的属性和方法)
    def use_potion(self, potion):
        """临时使用药水(仅在调用时依赖potion对象)"""
        return potion.restore(self)  # 方法结束后,不持有potion的引用

大战场景演示(综合应用所有关系)

if __name__ == "__main__":
    # 1. 创建角色(继承:都是生物)
    alice = Human("Alice")    # 人类主角
    bob = Human("Bob")        # 人类敌人
    wangcai = Dog("旺财")     # 狗敌人
    laifu = Dog("来福")       # 另一狗敌人

    # 2. 建立关联:添加多种敌人(人/狗)
    print("=== 关联:添加敌人列表 ===")
    print(alice.add_enemy(bob))    # Alice的敌人:人类Bob
    print(alice.add_enemy(wangcai))# Alice的敌人:狗旺财
    print(alice.add_enemy(laifu))  # Alice的敌人:狗来福
    print(bob.add_enemy(alice))    # Bob的敌人:Alice(人打人)
    print(wangcai.add_enemy(alice))# 旺财的敌人:Alice(狗打人)

    # 3. 装备聚合组件(武器/项圈)
    alice.weapon = Weapon("长剑", 20)  # Alice捡起长剑(聚合)
    bob.weapon = Weapon("斧头", 18)     # Bob拿起斧头(聚合)
    wangcai.collar = Collar("金属")    # 旺财戴上金属项圈(聚合)

    # 4. 第一回合:人打人(关联+聚合+继承)
    print("\n=== 第一回合:人打人 ===")
    print(alice.attack(bob))    # Alice用长剑攻击Bob(聚合的武器)
    print(bob.attack(alice))    # Bob用斧头反击(继承的受伤方法)

    # 5. 第二回合:人打狗(关联+组合+聚合)
    print("\n=== 第二回合:人打狗 ===")
    print(alice.attack(wangcai))# Alice攻击旺财(验证在敌人列表中)
    print(wangcai.bite(alice))  # 旺财撕咬(组合的牙齿+聚合的项圈减伤)

    # 6. 第三回合:使用药水疗伤(依赖)
    print("\n=== 第三回合:依赖(使用药水) ===")
    small_potion = Potion(30)   # 药水独立存在
    print(alice.use_potion(small_potion))  # 临时使用,用完不持有
    print("Alice是否持有药水?", hasattr(alice, "potion"))  # 输出False(无长期引用)

运行结果

=== 关联:添加敌人列表 ===
Alice将Bob(Human)列为敌人
Alice将旺财(Dog)列为敌人
Alice将来福(Dog)列为敌人
Bob将Alice(Human)列为敌人
旺财将Alice(Human)列为敌人

=== 第一回合:人打人 ===
Alice用长剑攻击Bob,造成20点伤害
Bob受20点伤害,剩余80血
Bob用斧头攻击Alice,造成18点伤害
Alice受18点伤害,剩余82血

=== 第二回合:人打狗 ===
Alice用长剑攻击旺财,造成20点伤害
旺财受20点伤害,剩余80血
旺财撕咬Alice,造成6点伤害  # 牙齿伤害8 - 金属项圈防御2 = 6
Alice受6点伤害,剩余76血

=== 第三回合:依赖(使用药水) ===
药水为Alice恢复30血,当前100血
Alice是否持有药水? False

五种关系总结表

关系类型 核心定义(“是什么”) 人狗大战场景体现 关键区别(与其他关系)
继承 子类“是一种”父类(is-a),继承属性和方法 人和狗“是一种”生物,共享生命值和受伤逻辑 强调“类型归属”,通过super()复用代码
组合 整体“包含不可分离的部分”,部分依赖整体存在 人的拳头、狗的牙齿,不能脱离身体单独存在 部分是整体的“原生组件”,创建整体时自动生成
聚合 整体“包含可分离的部分”,部分可独立存在 人的武器、狗的项圈,可单独创建后附加 部分是整体的“附加组件”,可随时分离
关联 独立对象间的“长期引用关系”(非整体-部分) 角色的敌人列表,长期存储人/狗等生物引用 强调“稳定互动绑定”,不涉及“包含”关系
依赖 方法级的“临时使用”,用完即断,无长期引用 临时使用药水疗伤,使用后不保留药水引用 强调“短期借用”,仅存在于方法调用时

通过这个场景可以清晰看到:继承负责“共性复用”,组合/聚合负责“整体与部分的不同绑定强度”,关联负责“对象间的长期互动”,依赖负责“临时资源的使用”。五种关系分工明确,共同构建了灵活且符合现实逻辑的面向对象模型。

posted @ 2025-10-20 11:52  wangya216  阅读(79)  评论(0)    收藏  举报