Interface-Design
Teil des Abschnitts Object Oriented Programming der Python-Journey von Coddy — Lektion 26 von 64.
Ein Interface definiert einen Vertrag, dem Klassen folgen müssen. In Python erstellen wir Interfaces mithilfe von abstrakten Basisklassen, bei denen alle Methoden abstrakt sind.
Importieren Sie das abc-Modul:
from abc import ABC, abstractmethodErstellen Sie ein Interface mit ausschließlich abstrakten Methoden:
class Drawable(ABC):
@abstractmethod
def draw(self):
pass
@abstractmethod
def resize(self, width, height):
passAlle Methoden in einem Interface sollten abstrakt sein – sie definieren, was implementierende Klassen tun müssen, nicht wie sie es tun sollen.
Implementieren Sie das Interface 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}"Verwenden Sie das Interface 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 10x8Sie können Interfaces auch als Type-Hints 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 implementieren Sie ein Mediaplayer-System mit Schnittstellen.
Sie müssen die folgenden Dateien bearbeiten:
playable.py– Implementieren Sie die abstrakten Basisklassen (Schnittstellen)song.py– Implementieren Sie die Klasse Songvideo.py– Implementieren Sie die Klasse Videomediaplayer.py– Implementieren Sie die Klasse MediaPlayer
Jede Datei enthält detaillierte TODO-Kommentare, die Sie bei Ihrer Implementierung unterstützen. Folgen Sie diesen Kommentaren, um ein vollständiges Mediaplayer-System mit ordnungsgemäßer Vererbung und Schnittstellenimplementierung zu erstellen.
Spickzettel
Erstellen Sie Schnittstellen mit abstrakten Basisklassen unter Verwendung des abc-Moduls:
from abc import ABC, abstractmethodDefinieren Sie eine Schnittstelle mit ausschließlich abstrakten Methoden:
class Drawable(ABC):
@abstractmethod
def draw(self):
pass
@abstractmethod
def resize(self, width, height):
passImplementieren Sie die Schnittstelle in konkreten Klassen:
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}"Verwenden Sie Schnittstellen polymorph:
shapes = [Circle(5), Rectangle(3, 4)]
for shape in shapes:
print(shape.draw())
print(shape.resize(10, 8))Verwenden Sie Schnittstellen als Typ-Hinweise (Type Hints):
def render_shape(drawable: Drawable):
return drawable.draw()Schnittstellen definieren, was Klassen tun müssen, nicht wie sie es tun. Alle Methoden in einer Schnittstelle sollten abstrakt sein, um klare Verträge für implementierende Klassen 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 Object Oriented Programming
1Grundlagen der OOP
Externe DateienEinführung in die OOPKlassen vs. ObjekteDer self-ParameterMethodenAttributeKonstruktor-Methode (__init__)Zusammenfassung – Einfacher Taschenrechner4Vererbung
Grundlagen der VererbungDie super()-FunktionMethoden überschreibenMehrfachvererbungMethod Resolution OrderZusammenfassung - Mitarbeiter-Hierarchie7Spezielle Methoden
Einführung in Magic MethodsOperator-ÜberladungMagic Methods für ContainerRückblick - Eigene Liste10Entwurfsmuster Teil 1
Einführung in EntwurfsmusterSingleton-MusterFactory-MusterObserver-MusterStrategy-Muster13Abschlussherausforderungen
E-Learning-PlattformBanksystemSpielcharakter-EntwicklungFahrzeugvermietung2Dekoratoren
Einführung in DekoratorenProperty-DekoratorStatischer Methoden-DekoratorKlassenmethoden-Dekorator5Polymorphismus
Methoden-Überschreiben vertieftDuck TypingAbstrakte Klassen und MethodenInterface-DesignZusammenfassung – Formen-Rechner8Fortgeschrittene OOP-Konzepte
Komposition vs. VererbungMixinsStatische und KlassenmethodenKlassendekoratorenContext Manager3Klasseneigenschaften
Instanz- vs. KlassenvariablenProperty-DekoratorenPrivate AttributeZusammenfassung – Bankkonto-Manager6Kapselung
Public, Protected, Private MemberZugriffsmodifikatorenInformation HidingProperty-Decorators für FortgeschritteneZusammenfassung - Studentenverwaltungssystem12Projekt: Bibliotheksverwaltung
ProjektübersichtBuch- und Benutzerklassen