@alekseysinos
Junior data scientist

Что предпочтительнее: наследование или обёртка?

Добрый день.
У меня есть класс который реализует парсер для определенного формата файла.
Я хочу добавить возможность парсинга еще одного формата. Мне представляется, что это можно сделать двумя способами:
1. Реализовать несколько методов парсера в одном классе, проверять расширение файла и вызывать соответствующий метод для обработки:
class FileParser:
    def __init__(self, file_name):
        self.ext = os.path.splitext(file_name)[1]
        if self.ext == '.foo':
            self.data = self._parse_foo(file_name)
        elif self.ext == '.bar':
            self.data = self._parse_bar(file_name)
        else:
            raise TypeError('Wrong file extension')
    def _parse_foo(self,file_name):
        pass
    def _parse_bar(self,file_name):
        pass
    def do_great_things_with_data(self):
        pass

2. Сделать наследование от исходного класса и реализовать в каждом наследнике свою функцию парсинга. При этом сделать фабрику объектов, которая будет создавать наследника нужного класса в соответствие с расширением файла:
class FileParser:
    @staticmethod
    def load_file(cls, file_name):
        ext = os.path.splitext(file_name)[1]
        if ext == '.foo':
            return FooFileParser(file_name)
        elif ext == '.bar':
            return BarFileParser(file_name)
        else:
            raise TypeError('Wrong file extension')
     def do_great_things_with_data(self):
        pass

class FooFileParser(FileParser):
    def __init__(self):
        pass

class BarFileParser(FileParser):
    def __init__(self):
        pass


Какой подход лучше использовать? Какие у каждого есть достоинства/недостатки?
  • Вопрос задан
  • 1033 просмотра
Пригласить эксперта
Ответы на вопрос 2
SergeyEgorov
@SergeyEgorov
Веб разработчик
Парсер в данном случае просто интерфейс. Поскольку Python - язык с динамической типизацией, то наследование или обертки не требуются вовсе. Просто все конкретные парсеры должны реализовать подразумеваемый интерфейс:
class CsvParser:
    def parse(self, file_name):

class XlsParser:
    def parse(self, file_name);


Экземпляры конкретных парсеров, по мере их появления складываем в обычный словарь, где ключ - это расширение файла, под которое заточен парсер.

{ 'csv': CsvParser(), 'xls': XlsParser(), 'xml': XmlParser() }


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

class ParserProvider:
        def provide(file_name):
Ответ написан
Комментировать
BacCM
@BacCM
C++ почти с рождения
Есть хорошее правило.
Если B является A то это наследование
иначе агрегация

Банально на школьных примерах, стол является предметом мебели, но в него входят столешница, ножки и т.д

А что касается твоего примера. Я бы предпочел вариант на базе 2 но с фабричным/реестровым получением парсера по типу файла.
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы