Я работаю над простой симуляцией, где я хотел бы изменить методы экземпляра класса во время выполнения. Я совершенно новичок в ООП, поэтому я не уверен, какой подход лучше всего подходит для моего случая.
Я создал пару примеров, примером которых является класс Cat
, который может превращаться в зомби-кошку во время выполнения, изменяя его поведение.
class Cat:
def __init__(self, foo):
self.foo = foo
self.is_zombie = False
def turn_to_zombie(self, bar):
self.is_zombie = True
self.zombie_bar = bar
def do_things(self):
if self.is_zombie:
print('Do zombie cat things')
else:
print('Do cat things')
Это желаемое поведение, однако я бы хотел разделить методы Cat
и ZombieCat
и пропустить оператор if
.
class Cat:
def __init__(self, foo):
self. foo = foo
def do_things(self):
print('Do cat things')
def turn_to_zombie(self, bar):
self.bar = bar
self.__class__ = ZombieCat
class ZombieCat(Cat):
def __init__(self, foo, bar):
super().__init__(self, foo)
self.bar = bar
def do_things(self):
print('Do zombie cat things')
Это хорошо работает, но я не уверен, есть ли какие-либо побочные эффекты при изменении self.__class__
, это, похоже, не рекомендуется Насколько опасно устанавливать self .__ class__ на что-то еще?
class Cat:
def __init__(self, foo):
self.foo = foo
self.strategy = CatStrategy
def do_things(self):
self.strategy.do_things(self)
def turn_to_zombie(self, bar):
self.bar = bar
self.strategy = ZombieCatStrategy
class CatStrategy:
@staticmethod
def do_things(inst):
print('Do cat things')
class ZombieCatStrategy(CatStrategy):
@staticmethod
def do_things(inst):
print('Do zombie cat things')
При поиске в Google я наткнулся на шаблон стратегии. Это также работает, но выглядит немного сложнее, чем создание дочернего класса. Например, чтобы переопределить дополнительный метод, когда кошка - зомби, она требует изменений в 3 местах вместо 1.
Не стесняйтесь предлагать другие шаблоны, я уверен, что есть вещи, которые я еще не рассмотрел.
Edit:
После полезного ответа от @martineau я хотел бы добавить, что было бы полезно, если бы какие-либо ссылки на экземпляр Cat
обновлялись при вызове .turn_to_zombie
, т.е.
cats_list1 = [cat1, cat2]
cats_list2 = [cat1, cat2]
cats_list1[0].do_things() # -> Do cat things
cats_list1[0].turn_to_zombie('bar')
cats_list2[0].do_things() # -> Do zombie cat things