Menu
Coddy logo textTech

Projektowanie interfejsów

Część sekcji Programowanie obiektowe ścieżki Python w Coddy. Lekcja 26 z 64.

Interfejs definiuje kontrakt, którego muszą przestrzegać klasy. W Pythonie tworzymy interfejsy za pomocą abstrakcyjnych klas bazowych, w których wszystkie metody są abstrakcyjne.

Zaimportuj moduł abc:

from abc import ABC, abstractmethod

Utwórz interfejs zawierający wyłącznie metody abstrakcyjne:

class Drawable(ABC):
    @abstractmethod
    def draw(self):
        pass
    @abstractmethod
    def resize(self, width, height):
        pass

Wszystkie metody w interfejsie powinny być abstrakcyjne — określają, co muszą robić klasy implementujące interfejs, a nie jak mają to robić.

Zaimplementuj interfejs w konkretnej klasie:

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}"

Utwórz kolejną klasę, która implementuje ten sam interfejs:

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}"

Użyj interfejsu polimorficznie:

shapes = [Circle(5), Rectangle(3, 4)]
for shape in shapes:
    print(shape.draw())
    print(shape.resize(10, 8))

Wynik:

Drawing a circle
Resized circle to radius 4.0
Drawing a rectangle
Resized rectangle to 10x8

Możesz także używać interfejsów jako podpowiedzi typów:

def render_shape(drawable: Drawable):
    return drawable.draw()
circle = Circle(3)
print(render_shape(circle))

Wynik:

Drawing a circle

Najważniejsza kwestia: interfejsy określają, co klasy muszą robić, a nie jak mają to robić. Używaj abstrakcyjnych klas bazowych zawierających wyłącznie metody abstrakcyjne, aby tworzyć jasne kontrakty, których muszą przestrzegać klasy implementujące. Zapewnia to spójne działanie różnych implementacji.

challenge icon

Wyzwanie

Średni

W tym wyzwaniu zaimplementujesz system odtwarzacza multimediów z interfejsami.

Musisz edytować następujące pliki:

  • playable.py — zaimplementuj abstrakcyjne klasy bazowe (interfejsy)
  • song.py — zaimplementuj klasę Song
  • video.py — zaimplementuj klasę Video
  • mediaplayer.py — zaimplementuj klasę MediaPlayer

Każdy plik zawiera szczegółowe komentarze TODO, które pomogą Ci w implementacji. Postępuj zgodnie z tymi komentarzami, aby utworzyć kompletny system odtwarzacza multimediów z odpowiednim dziedziczeniem i implementacją interfejsów.

Spróbuj swoich sił

from song import Song
from video import Video
from mediaplayer import MediaPlayer
from playable import Playable, MediaInfo

# Kompleksowa obsługa przypadków testowych
test_case = input()

if test_case == "default_test":
    # Domyślny przypadek testowy z oryginalnego zadania
    song = Song("Bohemian Rhapsody", "Queen", 355)
    video = Video("Python Tutorial", "1080p", 1800)
    player = MediaPlayer()

    # Test z utworem
    player.set_media(song)
    print(player.current_media.get_info())
    print(player.play())
    print(player.pause())
    print(player.stop())
    print()  # Pusta linia dla czytelności

    # Test z filmem
    player.set_media(video)
    print(player.current_media.get_info())
    print(player.play())
    print(player.pause())
    print(player.stop())

elif test_case == "empty_player":
    # Test odtwarzacza multimediów bez ustawionych mediów
    player = MediaPlayer()
    print(player.play())  # Powinno wypisać "No media set"
    print(player.pause())  # Powinno wypisać "No media set"
    print(player.stop())  # Powinno wypisać "No media set"

elif test_case == "time_formatting":
    # Test formatowania czasu w metodzie get_info()
    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":
    # Test, czy Song i Video poprawnie implementują interfejsy
    song = Song("Test Song", "Test Artist", 180)
    video = Video("Test Video", "480p", 240)
    
    # Sprawdzenie implementacji interfejsów
    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)}")
    
    # Test wszystkich metod interfejsów
    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":
    # Test zachowania polimorficznego na liście różnych typów mediów
    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":
    # Przetestuj przypadki brzegowe
    empty_song = Song("", "", 0)
    edge_video = Video("A" * 100, "", -10)  # Bardzo długi tytuł, pusta rozdzielczość, ujemny czas trwania
    
    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":
    # Zaimplementuj test obciążeniowy z wieloma obiektami multimedialnymi
    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()
    
    # Przetestuj wszystkie utwory
    for i, song in enumerate(songs):
        player.set_media(song)
        if i % 10 == 0:  # Wypisuj tylko co 10. wynik, aby uniknąć zbyt dużej ilości danych wyjściowych
            print(f"Playing song {i+1}: {player.play()}")
    
    # Przetestuj wszystkie filmy
    for i, video in enumerate(videos):
        player.set_media(video)
        if i % 10 == 0:  # Wypisuj tylko co 10. wynik, aby uniknąć zbyt dużej ilości danych wyjściowych
            print(f"Playing video {i+1}: {player.play()}")
    
    print("Stress test completed successfully!")
quiz iconSprawdź się

Ta lekcja zawiera krótki quiz. Zacznij lekcję, żeby na niego odpowiedzieć i śledzić swoje postępy.

Wszystkie lekcje w sekcji Programowanie obiektowe

Poćwicz samodzielnie: Kompilator Python online