Schnittstellendesign
Teil des Abschnitts Objektorientierte Programmierung der Python-Journey von Coddy. Lektion 26 von 64.
Eine Schnittstelle definiert einen Vertrag, dem Klassen folgen müssen. In Python erstellen wir Schnittstellen mithilfe abstrakter Basisklassen, bei denen alle Methoden abstrakt sind.
Importieren Sie das abc-Modul:
from abc import ABC, abstractmethodErstelle eine Schnittstelle, die nur abstrakte Methoden enthält:
class Drawable(ABC):
@abstractmethod
def draw(self):
pass
@abstractmethod
def resize(self, width, height):
passAlle Methoden in einem Interface sollten abstrakt sein – sie legen fest, was implementierende Klassen tun müssen, nicht wie sie es tun sollen.
Implementiere die Schnittstelle in einer konkreten Klasse:
class Circle(Drawable):
def __init__(self, radius):
self.radius = radius
def draw(self):
return "Drawing a circle"
def resize(self, width, height):
self.radius = min(width, height) / 2
return f"Resized circle to radius {self.radius}"Erstellen Sie eine weitere Klasse, die dieselbe Schnittstelle implementiert:
class Rectangle(Drawable):
def __init__(self, width, height):
self.width = width
self.height = height
def draw(self):
return "Drawing a rectangle"
def resize(self, width, height):
self.width = width
self.height = height
return f"Resized rectangle to {width}x{height}"Verwende die Schnittstelle polymorph:
shapes = [Circle(5), Rectangle(3, 4)]
for shape in shapes:
print(shape.draw())
print(shape.resize(10, 8))Ausgabe:
Drawing a circle
Resized circle to radius 4.0
Drawing a rectangle
Resized rectangle to 10x8Du kannst Schnittstellen auch als Typhinweise verwenden:
def render_shape(drawable: Drawable):
return drawable.draw()
circle = Circle(3)
print(render_shape(circle))Ausgabe:
Drawing a circleKernpunkt: Interfaces definieren, was Klassen tun müssen, nicht wie sie es tun. Verwenden Sie abstrakte Basisklassen mit ausschließlich abstrakten Methoden, um klare Verträge zu erstellen, denen implementierende Klassen folgen müssen. Dies gewährleistet ein konsistentes Verhalten über verschiedene Implementierungen hinweg.
Aufgabe
MittelIn dieser Herausforderung implementierst du ein Mediaplayer-System mit Schnittstellen.
Du musst die folgenden Dateien bearbeiten:
playable.py– Implementiere die abstrakten Basisklassen (Schnittstellen).song.py– Implementiere die Klasse Song.video.py– Implementiere die Klasse Video.mediaplayer.py– Implementiere die Klasse MediaPlayer.
Jede Datei enthält ausführliche TODO-Kommentare, die dich bei der Implementierung anleiten. Befolge diese Kommentare, um ein vollständiges Mediaplayer-System mit korrekter Vererbung und Schnittstellenimplementierung zu erstellen.
Probier es selbst
from song import Song
from video import Video
from mediaplayer import MediaPlayer
from playable import Playable, MediaInfo
# Umfassender Testfall-Handler
test_case = input()
if test_case == "default_test":
# Standard-Testfall aus der ursprünglichen Problemstellung
song = Song("Bohemian Rhapsody", "Queen", 355)
video = Video("Python Tutorial", "1080p", 1800)
player = MediaPlayer()
# Test mit Song
player.set_media(song)
print(player.current_media.get_info())
print(player.play())
print(player.pause())
print(player.stop())
print() # Leerzeile für bessere Lesbarkeit
# Test mit Video
player.set_media(video)
print(player.current_media.get_info())
print(player.play())
print(player.pause())
print(player.stop())
elif test_case == "empty_player":
# Testet den Media Player ohne gesetztes Medium
player = MediaPlayer()
print(player.play()) # Sollte "No media set" ausgeben
print(player.pause()) # Sollte "No media set" ausgeben
print(player.stop()) # Sollte "No media set" ausgeben
elif test_case == "time_formatting":
# Testet die Zeitformatierung in der get_info() Methode
song1 = Song("Short Song", "Artist A", 65) # 1:05
song2 = Song("Long Song", "Artist B", 3661) # 61:01
video1 = Video("Hour Video", "720p", 3600) # 60:00
print(song1.get_info())
print(song2.get_info())
print(video1.get_info())
elif test_case == "interface_compliance":
# Testet, ob Song und Video die Interfaces korrekt implementieren
song = Song("Test Song", "Test Artist", 180)
video = Video("Test Video", "480p", 240)
# Überprüfung der Interface-Implementierung
print(f"Song implements Playable: {isinstance(song, Playable)}")
print(f"Song implements MediaInfo: {isinstance(song, MediaInfo)}")
print(f"Video implements Playable: {isinstance(video, Playable)}")
print(f"Video implements MediaInfo: {isinstance(video, MediaInfo)}")
# Testet alle Interface-Methoden
print(song.play())
print(song.pause())
print(song.stop())
print(song.get_title())
print(song.get_duration())
print(song.get_info())
print(video.play())
print(video.pause())
print(video.stop())
print(video.get_title())
print(video.get_duration())
print(video.get_info())
elif test_case == "polymorphism":
# Testet polymorphes Verhalten mit einer Liste verschiedener Medientypen
media_list = [
Song("Song 1", "Artist 1", 180),
Video("Video 1", "720p", 300),
Song("Song 2", "Artist 2", 240),
Video("Video 2", "1080p", 420)
]
player = MediaPlayer()
for media in media_list:
player.set_media(media)
print(f"Media: {media.get_title()}")
print(f"Info: {media.get_info()}")
print(f"Play: {player.play()}")
print()
elif test_case == "edge_cases":
# Testet Grenzfälle
empty_song = Song("", "", 0)
edge_video = Video("A" * 100, "", -10) # Sehr langer Titel, leere Auflösung, negative Dauer
print(f"Empty song info: {empty_song.get_info()}")
print(f"Edge video info: {edge_video.get_info()}")
player = MediaPlayer()
player.set_media(empty_song)
print(player.play())
player.set_media(edge_video)
print(player.play())
elif test_case == "stress_test":
# Implementiert einen Belastungstest mit vielen Medienobjekten
songs = [Song(f"Song {i}", f"Artist {i}", i * 30) for i in range(1, 101)]
videos = [Video(f"Video {i}", f"{i*10}p", i * 60) for i in range(1, 101)]
player = MediaPlayer()
# Test mit allen Songs
for i, song in enumerate(songs):
player.set_media(song)
if i % 10 == 0: # Nur jeden 10. ausgeben, um zu viel Output zu vermeiden
print(f"Playing song {i+1}: {player.play()}")
# Test mit allen Videos
for i, video in enumerate(videos):
player.set_media(video)
if i % 10 == 0: # Nur jeden 10. ausgeben, um zu viel Output zu vermeiden
print(f"Playing video {i+1}: {player.play()}")
print("Stress test completed successfully!")Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.
Alle Lektionen in Objektorientierte Programmierung
1Grundlagen der OOP
Externe DateienEinführung in die OOPKlassen vs. ObjekteDer self-ParameterMethodenAttributeKonstruktormethode (__init__)Zusammenfassung – Einfacher Taschenrechner4Vererbung
Grundlegende VererbungDie super()-FunktionMethodenüberschreibungMehrfachvererbungMethodenauflösungsreihenfolgeWiederholung – Mitarbeiterhierarchie7Spezielle Methoden
Einführung in magische MethodenOperatorüberladungMagische Methoden für ContainerRückblick – Benutzerdefinierte Liste10Entwurfsmuster Teil 1
Einführung in EntwurfsmusterSingleton-MusterFactory-MusterObserver-MusterStrategy-Muster13Abschließende Herausforderungen
E-Learning-PlattformBankensystemEntwicklung von SpielfigurenFahrzeugvermietungsservice2Dekoratoren
Einführung in DekoratorenProperty-DekoratorDekorator für statische MethodenDekorator für Klassenmethoden5Polymorphie
Methodenüberschreibung erneut betrachtetDuck-TypingAbstrakte Klassen und MethodenSchnittstellendesignRückblick – Formrechner8Fortgeschrittene OOP-Konzepte
Komposition vs. VererbungMixinsStatische Methoden und KlassenmethodenKlassen-DekoratorenKontextmanager3Klassenattribute
Instanz- vs. KlassenvariablenProperty-DecoratorsPrivate AttributeWiederholung – Bankkontoverwaltung6Kapselung
Öffentliche, geschützte, private MemberZugriffsmodifikatorenInformationsverbergungProperty-Decorators – FortgeschrittenWiederholung – System zur Verwaltung von Studentendaten12Projekt: Bibliotheksverwaltung
ProjektübersichtBuch- und BenutzerklassenAusleihsystemSuchfunktionAdministrationsoberflächeTests und IntegrationÜbe selbstständig: Online-Python-Compiler