Инкапсуляция против наследования, помочь сделать выбор - PullRequest
1 голос
/ 13 апреля 2009

Мне нужно написать обработчики для нескольких разных типов падежей (в Python). Интерфейс для всех этих типов одинаков, но логика обработки отличается.

Одним из вариантов будет определение общего класса, который получает конкретный тип обработчика как один из параметров __init__:

class Handler:
   def __init__ (self, handlerType):
       self._handlerType = handlerType
       self._handler = handlerType.handleStuff

   def handleStuff(self, *args, **kwargs):
       return self._handler(args, kwargs)


# case specific handlers

class Handler_Case1:
   def handleStuff(self, *args, **kwargs):
       print 'Handling Case 1'


class Handler_Case2:
   def handleStuff(self, *args, **kwargs):
       print 'Handling Case 2'



if __name__ == '__main__':
   handlers = []
   handlers.append(Handler(Handler_Case1))
   handlers.append(Handler(Handler_Case2))
   for h in handlers:
       h.handleStuff()

Однако это приводит к ошибке TypeError:

TypeError: необязательный метод handleStuff () должен вызываться с экземпляром Handler_Case1 в качестве первого аргумента (вместо этого получен экземпляр кортежа)

Другой вариант - имитировать абстрактную функцию, как показано здесь («Вопрос: можете ли вы реализовать абстрактные классы в Python в 0 строк кода?»):

class Handler:
  def handleStuff(self, *args, **kwargs): abstract
  def commonFunction(self):
       print 'Common function'


 # case specific handlers

 class Handler_Case1(Handler):
  def handleStuff(self, *args, **kwargs):
      print 'Handling Case 1'


 class Handler_Case2(Handler):
  def handleStuff(self, *args, **kwargs):
      print 'Handling Case 2'



 if __name__ == '__main__':
  handlers = []
  h1 = (Handler_Case1())
  h2 = (Handler_Case2())
  handlers.append(h1)
  handlers.append(h2)
  for h in handlers:
      h.handleStuff()
      print

Итак, на самом деле у меня два вопроса:

  1. Какой из двух подходов является более питоническим? и
  2. Как реализовать первый?

1 Ответ

4 голосов
/ 13 апреля 2009

Возможно, мне не хватает какой-то тонкой запутанности в вашем вопросе, но, учитывая ваш первый пример, что мешает вам сделать что-то подобное:

class HandlerCase1(object):
    def handle_stuff(self, *args, **kwargs):
        print "Handling case 1"


class HandlerCase2(object):
    def handle_stuff(self, *args, **kwargs):
        print "Handling case 2"


if __name__ == "__main__":
    handlers = []
    handlers.append(HandlerCase1())
    handlers.append(HandlerCase2())
    for h in handlers:
        h.handle_stuff()

И если вы хотите, чтобы классы разделяли некоторые общие (базовые) функции, есть что-то, что мешает вам сделать это:

class Handler(object):
    def common_function(self):
        print "Common function"


class HandlerCase1(Handler):
    def handle_stuff(self, *args, **kwargs):
        print "Handling case 1"


class HandlerCase2(Handler):
    def handle_stuff(self, *args, **kwargs):
        print "Handling case 2"


if __name__ == "__main__":
    handlers = []
    handlers.append(HandlerCase1())
    handlers.append(HandlerCase2())
    for h in handlers:
        h.handle_stuff()
        h.common_function()
...