Должен ли я добавлять новые методы в класс вместо использования принципа единой ответственности
У нас был семинар, на котором я представил своей команде принцип единой ответственности, чтобы мы использовали его в наших проектах. Я использовал следующий популярный пример:
class Employee:
save()
calculate_salary()
generate_report()
И я попросил команду сказать, все ли в порядке с этим классом. Все говорили мне, что все в порядке.
Но я вижу здесь три нарушения принципа СРП.
Правильно ли я говорю, что все методы должны быть извлечены из класса?
Мои рассуждения:
Метод Save () является причиной для изменения, если изменить наш база данных.
Метод Calculate_salary() является причиной для изменения, поскольку политика заработной платы может измениться.
Метод Generate_report () является причиной для изменения, если мы хотим изменить представление отчета (т. е. csv вместо html). Давайте возьмем последний метод. Я придумал следующий класс HtmlReportGenerator.class HTMLReportGenerator:
def __init__(self, reportable):
self.reportable = reportable
def generate_csv_report()
class CSVReportGenerator:
def __init__(self, reportable):
self.reportable = reportable
def generate_html_report()
Теперь, даже если бизнес-логика этого генератора изменится, это не коснется класса сотрудников, и это было моим главным пунктом. Более того, теперь мы можно повторно использовать эти классы для объектов, отличных от объектов класса Employee.
Но команда придумала другой класс:class Employee:
save()
calculate_salary()
generate_html_report()
generate_csv_report()
Они понимают, что нарушают ПДД, но для них это нормально.
И именно здесь у меня не было других идей для борьбы))
Есть какие-нибудь соображения по поводу ситуации?
1 ответ:
Я согласен с вами, добавляя дополнительные функции, они нарушили как SRP, так и принцип open/close, и каждый раз, когда будет новый тип отчета, они будут нарушать его снова.
Я бы сохранил функцию generate_report (), но добавил параметр из типа интерфейса "ReportType", который имеет функцию generate ().
Это означает, что, например, вы можете вызвать (простите мою Java):
employee.generate_report(new CSVReport()) employee.generate_report(new HTMLReport())
И завтра, если вы хотите добавить отчет XML, вы просто реализуете XMLReport из интерфейс отчета и вызов:
employee.generate_report(new XMLReport())
Это дает вам большую гибкость, не нужно менять сотрудника для новых типов отчетов, и гораздо проще тестировать (например, если бы generate_report имел сложную логику, вы могли бы просто создать класс TestReport, который реализует интерфейс отчета и просто печатает в выходной поток для отладки и вызова generate_report (new TestReport ()))