З огляду на те, що Python дозволяє отримати багаторазове успадкування, як виглядає ідіоматичне успадкування в Python?
У мовах з одинарним успадкуванням, як-от Java, успадкування буде використовуватися, коли можна сказати, що один об'єкт "є-а" іншого об'єкта, і ви хочете поділити код між об'єктами (від батьківського об'єкта до дочірнього об'єкта). Наприклад, ви можете сказати, що Dog
це Animal
:
public class Animal {...}
public class Dog extends Animal {...}
Але оскільки Python підтримує багатократне успадкування, ми можемо створити об'єкт, склавши багато інших об'єктів разом. Розглянемо приклад нижче:
class UserService(object):
def validate_credentials(self, username, password):
# validate the user credentials are correct
pass
class LoggingService(object):
def log_error(self, error):
# log an error
pass
class User(UserService, LoggingService):
def __init__(self, username, password):
self.username = username
self.password = password
def authenticate(self):
if not super().validate_credentials(self.username, self.password):
super().log_error('Invalid credentials supplied')
return False
return True
Це прийнятне чи корисне використання багаторазового успадкування в Python? Замість того, щоб говорити про успадкування, коли один об'єкт "є-а" іншого об'єкта, ми створюємо User
модель, що складається з UserService
і LoggingService
.
Усю логіку операцій з базою даних або мережею можна зберігати окремо від User
моделі, вводячи їх в UserService
об'єкт і зберігаючи всю логіку для входу в LoggingService
.
Я бачу деякі проблеми з таким підходом:
- Чи створює це об'єкт Бога? Оскільки
User
успадковується від або складається з нього,UserService
іLoggingService
чи дійсно він слідує принципу єдиної відповідальності? - Для доступу до методів на батьківському об'єкті / наступному рядку (наприклад,
UserService.validate_credentials
ми повинні використовуватиsuper
. Це робить трохи складніше зрозуміти, який об’єкт буде обробляти цей метод, і не так зрозуміло, як, скажімо, , інстанціюватиUserService
і робити щось подібнеself.user_service.validate_credentials
Який би був пітонічний спосіб реалізації вищевказаного коду?