Вы используете прокси / фасадный объект для хранения ссылки на реальный объект, self
, если у вас sh, и этот прокси (более подходящий термин, чем Facade, но не меняющий мой код сейчас) - это то, что остальные ваша кодовая база видит. Однако любой доступ к атрибуту / методу перенаправляется на фактический объект, который можно заменить.
Код ниже должен дать вам приблизительное представление. Обратите внимание, что вы должны быть осторожны с рекурсией вокруг __the_instance
, поэтому я назначаю __dict__
напрямую. Немного запутанно, так как уже давно я написал код, который полностью переносит getattr и setattr.
class Facade:
def __init__(self, instance):
self.set_obj(instance)
def set_obj(self, instance):
self.__dict__["__theinstance"] = instance
def __getattr__(self, attrname):
if attrname == "__theinstance":
return self.__dict__["__theinstance"]
return getattr(self.__dict__["__theinstance"], attrname)
def __setattr__(self, attrname, value):
if attrname == "__theinstance":
self.set_obj(value)
return setattr(self.__dict__["__theinstance"], attrname, value)
class Test:
def __init__(self, name, cntr):
self.name = name
self.cntr = cntr
def __repr__(self):
return "%s[%s]" % (self.__class__.__name__, self.__dict__)
obj1 = Test("first object", 1)
obj2 = Test("second", 2)
obj2.message = "greetings"
def pretend_client_code(facade):
print(id(facade), facade.name, facade.cntr, getattr(facade, "value", None))
facade = Facade(obj1)
pretend_client_code(facade)
facade.set_obj(obj2)
pretend_client_code(facade)
facade.value = 3
pretend_client_code(facade)
facade.set_obj(obj1)
pretend_client_code(facade)
output:
4467187104 first object 1 None
4467187104 second 2 None
4467187104 second 2 3
4467187104 first object 1 None
Таким образом, по сути, «клиентский код» всегда видит тот же самый фасадный объект, но то, к чему он фактически получает доступ, зависит от того, что сделал ваш эквивалент def b
.
Фасад имеет специфическое значение c в терминологии Design Patterns, и он может быть неприменим здесь , но достаточно близко. Возможно, Прокси был бы лучше.
Обратите внимание, что если вы хотите изменить класс на том же объекте, это совсем другое дело, путем присвоения self.__class__
. Например, скажем, RPG-игра с EnemyClass
, которого после убийства поменяют на DeadEnemyClass
: self.__class__ = DeadEnemyClass