我正在为我的python课程编写一个小游戏,我想整合一个库存和项目系统。该项目提供的可能性是变量(武器,任务物品,消耗品或非消耗品,等等)。
我已经阅读了这篇关于pattern decorator(google translated in english)的教程(法语),我带来了这个: (我使用的是python3)
class Item(object):
def __init__(self, caracts=None, inventory=None):
self.caracts = {}
if caracts:
self.caracts = caracts
self.inventory = inventory
class ItemDecorator(Item):
def __init__(self, item):
super().__init__()
self.item = item
self.caracts = item.caracts
class Consumable(ItemDecorator):
def __init__(self, item, amount=1):
super().__init__(item)
self._amount = 0
self.amount = amount
@property
def amount(self):
return self._amount
@amount.setter
def amount(self, value):
self._amount = max(0, value)
if self._amount == 0 and self.item.inventory:
self.item.inventory.remove(self)
@amount.deleter
def amount(self):
del self._amount
class Usable(ItemDecorator):
def __init__(self, item, action=None, consumable=None):
if not action:
action = lambda *args, **kwargs: None
self._use = action
self.consumable = consumable
def use(self, *args, **kwargs):
if self.consumable and self.consumable.amount <= 0:
raise CantBeUsedException("There is no consumable")
else:
if self.consumable:
self.consumable.amount -= 1
self._use(*args, **kwargs)
我的想法是能够做到这一点:
potion = Usable(Consumable(Item(), 3), use_potion)
print("isinstance(potion.item, Consumable): {}".format(
isinstance(potion.item, Consumable)))
potion.consumable = potion.item
for dummy in range(4):
try:
potion.use()
except CantBeUsedException as e:
print("Expected exception: {}".format(e))
但是我的问题就在第4行。可用的potion
使用的耗材应该是potion
本身。但potion
失去了其消耗品能力,只有potion.item
拥有它。这甚至是最糟糕的,因为我调用装饰器的顺序很重要。 potion = Consumable(Usable(Item(), use_potion), 3)
引导我做potion.item.use()
,这个项目总是令我烦恼。
我该如何简化?知道可用的并不一定会消耗自己,甚至是某种东西。事实上,无论先调用哪个装饰器,我都希望能够做到这一点:
potion = Consumable(Usable(Item(), use_potion), 3)
potion.consumable = potion
potion.use()
我无法为我的问题找到一个干净的解决方案。以下是我想到的所有问题: *这个装饰模式是否适应? (它看起来如此,但我可能是错的) *如果情况并非如此,那么您认为不是一个接口系统(因此,具有多重遗产)更好的解决方案? *我被困在这里做错了什么?
如何在可扩展的同时使这个系统变得非常简单。为此,我想到了这个解决方案:
class ItemDecorator(Item):
def __init__(self, item):
super().__init__()
self.item = item
self.caracts = item.caracts
if hasattr(item, "amount"):
self.amount = item.amount
if hasattr(item, "use"):
self.use = item.use
但是通过这样做,我不会失去Decorator模式的所有可扩展性吗?实际上,每次我想创建一个非常复杂的装饰器时,我都需要更新ItemDecorator。因此,我不会失去装饰者模式的所有优势吗?
非常感谢您的帮助
答案 0 :(得分:0)
现在你的课程布局相当扭曲,而Usable(Consumable(Item(), 3), use_potion)
看起来并不像pythonic。
我稍微重新设计了系统:
class ItemCapability:
pass
class Consumable(ItemCapability):
def __init__(self, amount):
super().__init__()
self.amount = amount
class Usable(ItemCapability):
pass
class Item:
def __init__(self, name):
self.name = name
self.capabilities = {}
def make(self, capability):
assert isinstance(capability, ItemCapability)
assert capability.__class__ not in self.capabilities
self.capabilities[capability.__class__] = capability
def has(self, capability_cls):
try:
return self.capabilities[capability_cls]
except KeyError:
return False
potion = Item('potion')
potion.make(Usable())
potion.make(Consumable(amount=10))
print(potion.has(Usable))
print(potion.has(Consumable))
通过这种方式,您可以非常简单地理解类系统,并轻松地查询项目的功能。