Принцип открытости-закрытости в Python с примерами
В этом руководстве вы узнаете о принципе открытости-закрытости в Python, позволяющем расширить систему без прямого изменения существующего кода.
Что такое принцип открытости-закрытости в Python?
Принцип открытости-закрытости является одним из пяти составляющих принципа SOLID. Буква О в SOLID означает принцип «open-closed».
- S – Принцип единой ответственности
- O – Принцип открытости-закрытости
- L – Принцип подстановки Лисков
- I – Разделение интерфейса
- D – Инверсии зависимостей
Принцип открытости-закрытости гласит, что класс, метод и функция должны быть открыты для расширения, но закрыты для модификации. Следует заметить, что звучит это противоречиво.
Цель принципа открытости-закрытости — облегчить добавление новых функций (или вариантов использования) в систему без прямого изменения существующего кода.
Рассмотрим следующий пример:
class Person: def __init__(self, name): self.name = name def __repr__(self): return f'Person(name={self.name})' class PersonStorage: def save_to_database(self, person): print(f'Save the {person} to database') def save_to_json(self, person): print(f'Save the {person} to a JSON file') if __name__ == '__main__': person = Person('John Doe') storage = PersonStorage() storage.save_to_database(person)
В этом примере класс PersonStorage имеет два метода:
- Метод save_to_database() сохраняет Person в базу данных.
- Метод save_to_json() сохраняет Person в файл JSON.
Позже, если вы захотите сохранить объект Person в XML-файл, вам необходимо изменить класс PersonStorage. Это означает, что класс PersonStorage открыт не для расширения, а для модификации. Следовательно, это нарушает принцип открытости-закрытости.
Пример принципа открытости-закрытости
Чтобы класс PersonStorage соответствовал принципу открытости-закрытости; вам необходимо спроектировать классы так, чтобы, когда вам нужно сохранить объект Person в другом формате файла, вам не нужно было его изменять.
См. следующую диаграмму классов:
- Сначала определите абстрактный класс PersonStorage, содержащий абстрактный метод save():
from abc import ABC, abstractmethod class PersonStorage(ABC): @abstractmethod def save(self, person): pass
- Во-вторых, создайте два класса PersonDB и PersonJSON, которые сохранят объект Person в базе данных и файле JSON. Эти классы наследуются от класса PersonStorage:
class PersonDB(PersonStorage): def save(self, person): print(f'Save the {person} to database') class PersonJSON(PersonStorage): def save(self, person): print(f'Save the {person} to a JSON file')
- Чтобы сохранить объект Person в XML-файл, вы можете определить новый класс PersonXML, который наследуется от класса PersonStorage, следующим образом:
class PersonXML(PersonStorage): def save(self, person): print(f'Save the {person} to an XML file')
- И вы можете сохранить объект Person в XML-файл, используя класс PersonXML:
if __name__ == '__main__': person = Person('John Doe') storage = PersonXML() storage.save(person)
Полный код:
from abc import ABC, abstractmethod class Person: def __init__(self, name): self.name = name def __repr__(self): return f'Person(name={self.name})' class PersonStorage(ABC): @abstractmethod def save(self, person): pass class PersonDB(PersonStorage): def save(self, person): print(f'Save the {person} to database') class PersonJSON(PersonStorage): def save(self, person): print(f'Save the {person} to a JSON file') class PersonXML(PersonStorage): def save(self, person): print(f'Save the {person} to an XML file') if __name__ == '__main__': person = Person('John Doe') storage = PersonXML() storage.save(person)