如何基于实例的组件修改该实例的功能?(Python场景)
问题场景
我有一个Character类,用于表示地图上角色的视觉与功能逻辑,它包含一个CharacterData组件,用来存储角色的核心数据。少数情况下,CharacterData需要修改Character的部分功能逻辑。
我原本的实现是让CharacterData定义和Character方法同名的变量(默认None),如果有自定义逻辑就替换成对应的函数。这种方法能运行,但感觉不够优雅。
已经排除的方案:
- 子类化
CharacterData不合适:因为大部分时候不需要修改功能,而且CharacterData没必要知晓Character的细节 - 子类化
Character不合适:因为只有拿到CharacterData后才知道要修改哪些功能,创建Character的代码也未必清楚这些修改需求
原实现代码:
class Character: def __init__(self, x: int, y: int, data: CharacterData): self.x = x self.y = y self.data = data self.move_action = self.move if self.data.move_action is not None: self.move_action = self.data.move_action # 有自定义逻辑就替换函数 def move(self, *args): # args用来接收多余的self参数 self.y += 1 def perform_move(self): self.move_action(self) # 调用时要显式传入self class CharacterData: def __init__(self, name, atk, move_action): self.name, self.atk = name, atk self.move_action = move_action # 外部定义的替换函数,传入CharacterData使用 def move_action_replacement(*args): args[0].x += 1 args[0].y += 1
优化方案1:钩子方法模式
让Character的核心方法先检查CharacterData是否存在对应钩子,有则执行钩子逻辑(钩子可决定是否跳过默认逻辑),否则走默认实现。这种方式不需要函数替换,CharacterData只需提供可选的钩子,完全不用关心Character的默认逻辑。
示例代码:
class Character: def __init__(self, x: int, y: int, data: CharacterData): self.x = x self.y = y self.data = data def move(self): # 检查data是否有自定义move钩子,有则执行 if hasattr(self.data, 'on_move') and callable(self.data.on_move): # 把Character实例传给钩子,方便操作角色属性 if self.data.on_move(self): return # 钩子返回True则跳过默认逻辑 # 默认移动逻辑 self.y += 1 def perform_move(self): self.move() # 直接调用,无需额外处理self传递 class CharacterData: def __init__(self, name, atk): self.name, self.atk = name, atk # 大部分角色无需自定义move,默认不定义钩子 # 有自定义移动需求的CharacterData子类 class CustomCharacterData(CharacterData): def on_move(self, character): character.x += 1 character.y += 1 return True # 告知Character无需执行默认逻辑 # 也可以直接给实例绑定钩子 data = CharacterData("Test", 10) def custom_move(character): character.x += 2 character.y += 2 return True data.on_move = custom_move
优化方案2:函数包装器模式
在Character初始化时,用CharacterData的自定义逻辑包装默认方法,而非直接替换。这种方式可以灵活控制自定义逻辑与默认逻辑的执行顺序(比如在默认逻辑前后添加额外操作)。
示例代码:
class Character: def __init__(self, x: int, y: int, data: CharacterData): self.x = x self.y = y self.data = data # 如果data有包装逻辑,就包装默认move方法 if hasattr(self.data, 'wrap_move') and callable(self.data.wrap_move): self.move = self.data.wrap_move(self.move) def move(self): self.y += 1 def perform_move(self): self.move() class CharacterData: def __init__(self, name, atk): self.name, self.atk = name, atk # 自定义包装器示例 class CustomMoveData(CharacterData): def wrap_move(self, original_move): def wrapped_move(): # 先执行自定义逻辑 self.x += 1 # 再调用默认移动逻辑 original_move() return wrapped_move # 更灵活的包装器(支持直接操作Character实例) def create_move_wrapper(custom_logic): def wrapper(original_move): def wrapped(character): custom_logic(character) original_move(character) return wrapped return wrapper # 使用示例 def custom_logic(character): character.x += 1 data = CharacterData("Test", 10) data.wrap_move = create_move_wrapper(custom_logic)
优化方案3:策略模式(结构化扩展)
定义统一的策略接口,Character默认使用默认策略,CharacterData可提供自定义策略实现。这种方式结构清晰,适合存在多种不同功能逻辑的场景。
示例代码:
from abc import ABC, abstractmethod # 定义移动策略接口 class MoveStrategy(ABC): @abstractmethod def execute(self, character): pass # 默认移动策略 class DefaultMoveStrategy(MoveStrategy): def execute(self, character): character.y += 1 # 自定义斜向移动策略 class DiagonalMoveStrategy(MoveStrategy): def execute(self, character): character.x += 1 character.y += 1 class Character: def __init__(self, x: int, y: int, data: CharacterData): self.x = x self.y = y self.data = data # 默认使用默认策略 self.move_strategy = DefaultMoveStrategy() # 如果data有自定义策略则替换 if hasattr(self.data, 'move_strategy') and isinstance(self.data.move_strategy, MoveStrategy): self.move_strategy = self.data.move_strategy def perform_move(self): self.move_strategy.execute(self) class CharacterData: def __init__(self, name, atk, move_strategy=None): self.name, self.atk = name, atk self.move_strategy = move_strategy # 使用示例 data = CharacterData("Test", 10, DiagonalMoveStrategy()) char = Character(0, 0, data) char.perform_move() # 执行后x=1, y=1
内容的提问来源于stack exchange,提问作者Nicholas
相关产品推荐
相关产品推荐

