Heim > Artikel > Backend-Entwicklung > SOLID-Prinzipien – erklärt anhand realer Beispiele in Python
SOLID ist ein Akronym, das für fünf Designprinzipien steht, die Entwicklern helfen, wartbarere, verständlichere und flexiblere Software zu erstellen. Lassen Sie uns jedes einzelne anhand eines nachvollziehbaren Beispiels durchgehen.
Definition: Eine Klasse sollte nur einen Grund haben, sich zu ändern, das heißt, sie sollte nur eine Aufgabe oder Verantwortung haben.
Erklärung: Stellen Sie sich vor, Sie hätten ein Tool, das zwei verschiedene Aufgaben kombiniert, wie das Versenden von E-Mails und die Verarbeitung von Zahlungen. Wenn beide Aufgaben von einer einzigen Klasse erledigt werden, können Änderungen an der E-Mail-Funktion die Zahlungsfunktion beeinträchtigen. Indem Sie diese Verantwortlichkeiten getrennt halten, minimieren Sie das Risiko, dass sich Änderungen in einem Teil auf einen anderen auswirken.
Beispiel:
class EmailSender: def send_email(self, recipient, subject, body): # Code to send an email print(f"Sending email to {recipient} with subject '{subject}'") class PaymentProcessor: def process_payment(self, amount): # Code to process payment print(f"Processing payment of amount {amount}") # Usage email_sender = EmailSender() email_sender.send_email("user@example.com", "Hello!", "Welcome to our service!") payment_processor = PaymentProcessor() payment_processor.process_payment(100)
In diesem Beispiel ist EmailSender nur für den Versand von E-Mails verantwortlich und PaymentProcessor ist nur für die Verarbeitung von Zahlungen verantwortlich. Sie haben jeweils eine einzige Verantwortung, wodurch der Code einfacher zu warten und zu erweitern ist.
Definition: Software-Entitäten (wie Klassen, Module, Funktionen usw.) sollten für Erweiterungen offen, aber für Änderungen geschlossen sein.
Erklärung: Das bedeutet, dass Sie in der Lage sein sollten, einer Klasse neue Funktionen oder Verhaltensweisen hinzuzufügen, ohne den vorhandenen Code zu ändern. Stellen Sie sich vor, Sie verfügen über ein Zahlungsverarbeitungssystem und möchten eine neue Zahlungsmethode hinzufügen. Sie sollten in der Lage sein, diese neue Methode hinzuzufügen, ohne den vorhandenen Code zu ändern.
Beispiel:
from abc import ABC, abstractmethod class PaymentProcessor(ABC): @abstractmethod def process_payment(self, amount): pass class CreditCardPayment(PaymentProcessor): def process_payment(self, amount): print(f"Processing credit card payment of {amount}") class PayPalPayment(PaymentProcessor): def process_payment(self, amount): print(f"Processing PayPal payment of {amount}") # Usage payments = [CreditCardPayment(), PayPalPayment()] for payment in payments: payment.process_payment(100)
In diesem Beispiel ist PaymentProcessor eine abstrakte Klasse, die einen Vertrag zur Zahlungsabwicklung definiert. CreditCardPayment und PayPalPayment sind Implementierungen, die diese Klasse erweitern. Wenn Sie eine neue Zahlungsmethode hinzufügen möchten, können Sie eine neue Klasse erstellen, die PaymentProcessor erweitert, ohne vorhandene Klassen zu ändern.
Definition: Untertypen müssen für ihre Basistypen ersetzbar sein, ohne die Korrektheit des Programms zu verändern.
Erklärung: Dies bedeutet, dass Objekte einer Oberklasse durch Objekte einer Unterklasse ersetzbar sein sollten, ohne die Funktionalität des Programms zu beeinträchtigen. Wenn Sie beispielsweise eine Funktion haben, die mit einer Fahrzeugklasse funktioniert, sollte sie auch mit jeder Unterklasse wie Auto oder Fahrrad funktionieren.
Beispiel:
class Vehicle: def start_engine(self): pass class Car(Vehicle): def start_engine(self): print("Starting car engine...") class Bike(Vehicle): def start_engine(self): print("Starting bike engine...") # Usage def start_vehicle_engine(vehicle: Vehicle): vehicle.start_engine() car = Car() bike = Bike() start_vehicle_engine(car) # Should work fine start_vehicle_engine(bike) # Should work fine
In diesem Beispiel sind Auto und Fahrrad Unterklassen von Fahrzeug. Die Funktion start_vehicle_engine kann mit jeder Unterklasse von Fahrzeugen arbeiten, ohne dass die Besonderheiten der Unterklasse bekannt sein müssen, was dem Liskov-Substitutionsprinzip entspricht.
Definition: Ein Client sollte nicht gezwungen werden, Schnittstellen zu implementieren, die er nicht verwendet. Anstelle einer fetten Schnittstelle werden viele kleine Schnittstellen bevorzugt, die auf Gruppen von Methoden basieren, von denen jede ein Submodul bedient.
Erklärung: Dieses Prinzip legt nahe, dass Sie für jeden Clienttyp spezifische Schnittstellen erstellen sollten und nicht eine Allzweckschnittstelle. Stellen Sie sich vor, Sie hätten ein Gerät, das drucken, scannen und faxen kann. Wenn Sie separate Geräte haben, die nur drucken oder scannen können, sollten diese nicht gezwungen werden, Funktionen zu implementieren, die sie nicht nutzen.
Beispiel:
from abc import ABC, abstractmethod class Printer(ABC): @abstractmethod def print(self, document): pass class Scanner(ABC): @abstractmethod def scan(self, document): pass class MultiFunctionDevice(Printer, Scanner): def print(self, document): print(f"Printing: {document}") def scan(self, document): print(f"Scanning: {document}") # Usage mfd = MultiFunctionDevice() mfd.print("Document 1") mfd.scan("Document 2")
Hier sind Drucker und Scanner separate Schnittstellen. MultiFunctionDevice implementiert beides, aber wenn es Geräte gäbe, die nur drucken oder nur scannen, müssten sie unter Einhaltung des Schnittstellentrennungsprinzips keine Methoden implementieren, die sie nicht verwenden.
Definition: High-Level-Module sollten nicht von Low-Level-Modulen abhängen. Beide sollten von Abstraktionen (z. B. Schnittstellen) abhängen. Abstraktionen sollten nicht von Details abhängen. Details sollten von Abstraktionen abhängen.
Erklärung: Anstelle einer High-Level-Klasse, die direkt von Low-Level-Klassen abhängt, sollten beide von einer Schnittstelle oder einer abstrakten Klasse abhängen. Dies ermöglicht mehr Flexibilität und eine einfachere Wartung.
Beispiel:
from abc import ABC, abstractmethod class NotificationService(ABC): @abstractmethod def send(self, message): pass class EmailNotificationService(NotificationService): def send(self, message): print(f"Sending email: {message}") class SMSNotificationService(NotificationService): def send(self, message): print(f"Sending SMS: {message}") class NotificationSender: def __init__(self, service: NotificationService): self.service = service def notify(self, message): self.service.send(message) # Usage email_service = EmailNotificationService() sms_service = SMSNotificationService() notifier = NotificationSender(email_service) notifier.notify("Hello via Email") notifier = NotificationSender(sms_service) notifier.notify("Hello via SMS")
In diesem Beispiel hängt NotificationSender von der NotificationService-Abstraktion ab und nicht von einer konkreten Klasse wie EmailNotificationService oder SMSNotificationService. Auf diese Weise können Sie den Benachrichtigungsdienst wechseln, ohne die NotificationSender-Klasse zu ändern.
Single-Responsibility-Prinzip (SRP): Eine Klasse sollte eine Sache tun und zwar gut.
Offenes/Geschlossenes Prinzip (OCP): Eine Klasse sollte für Erweiterungen offen, aber für Änderungen geschlossen sein.
Liskov-Substitutionsprinzip (LSP): Unterklassen sollten für ihre Basisklassen ersetzbar sein.
Interface Segregation Principle (ISP): Kein Client sollte gezwungen werden, sich auf Methoden zu verlassen, die er nicht verwendet.
Dependency Inversion Principle (DIP): Verlassen Sie sich auf Abstraktionen, nicht auf konkrete Implementierungen.
Indem Sie diese SOLID-Prinzipien befolgen, können Sie Software erstellen, die einfacher zu verstehen, zu warten und zu erweitern ist.
Das obige ist der detaillierte Inhalt vonSOLID-Prinzipien – erklärt anhand realer Beispiele in Python. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!