Существует ли шаблон для класса python для делегирования его реализации другому классу? - PullRequest
0 голосов
/ 20 апреля 2020

Мои извинения за то, что может быть базовым c вопросом. Я программист на C ++, который относительно новичок в python.

У меня есть класс python, поведение которого существенно зависит от одного из аргументов его конструктора:

    class MyClass():
       def __init__(self, some_arg):
          self.some_arg = some_arg
          ...

       def abcd(self):
          if self.some_arg == 1:
             ...
          else:
             ...

       def efgh(self):
          if self.some_arg == 1:
             ...
          else:
             ...

Я бы Я хотел бы реорганизовать это в два класса с разными значениями some_arg. Конечно, наиболее простой вещью было бы иметь два класса (возможно, с общим базовым классом) и затем иметь фабричную функцию, выбирающую, какой из них создать. Что-то вроде:

   def MyClassSomeArg1():
      def __init__(self):
         ...

      def abcd(self):
         ...

      def efgh(self):
         ...

   def MyClassSomeArgNot1():
      def __init__(self):
         ...

      def abcd(self):
         ...

      def efgh(self):
         ...

   def buildMyClass(some_arg):
      if some_arg == 1:
        return MyClassSomeArg1()
      else:
        return MyClassSomeArgNot1()

Я уверен, что это будет работать нормально. Проблема в том, что я не хочу менять код клиента. Клиенты ожидают создания экземпляра объекта класса «MyClass» с аргументом конструктора some_arg. Есть ли достойный способ реорганизовать это под капотом без изменения клиентского кода?

Я попытался использовать иерархию реализации: MyClassImpl в качестве базового класса с подклассами MyClassImplSomeArg1 и MyClassImplSomeArgNot1. MyClass сам тогда становится в основном пустым:

class MyClass():

   def __init__(self, some_arg):
      if some_arg == 1:
         self._impl = MyClassImplSomeArg1()
      else:
         self._impl = MyClassImplSomeArgNone1()

   def __getattr__(self, a):
      # For performance, I could store this in self so it doesn't need to be looked up each time
      return getattr(self._impl, a)

Это в основном работает, но это не самая простая вещь. С одной стороны, методы magi c, такие как __str__ и __eq__, похоже, не делегируются через механизм __getattr__, и я не знаю почему. Хотя написать методы делегирования не сложно. Кроме того, это сбивает с толку pydo c (он не может видеть делегированные атрибуты), и я не уверен, как это исправить.

Есть ли сахар, чтобы эта схема делегирования работала хорошо? Или делегирование - даже лучший способ справиться с такой проблемой?

Спасибо,

1 Ответ

1 голос
/ 20 апреля 2020

Вы можете переопределить функцию __new__ и вернуть подкласс на основе some_arg. Это общий шаблон для реализации фабрики

class MyClassImplSomeArg1:
    pass

class MyClassImplSomeArgNone1:
    pass

class MyClass:
    def __new__(cls, some_arg):
        if some_arg:
            return MyClassImplSomeArg1()
        else:
            return MyClassImplSomeArgNone1()

assert isinstance(MyClass(some_arg=True), (MyClassImplSomeArg1,))
assert isinstance(MyClass(some_arg=False), (MyClassImplSomeArgNone1,))

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...