Menu
Coddy logo textTech

עיצוב ממשקים

חלק מהיחידה תכנות מונחה עצמים במסלול ה-Python של Coddy. שיעור 26 מתוך 64.

ממשק מגדיר חוזה שעל מחלקות לפעול לפיו. ב-Python יוצרים ממשקים באמצעות מחלקות בסיס מופשטות שבהן כל המתודות מופשטות.

ייבא את המודול abc:

from abc import ABC, abstractmethod

צרו ממשק עם מתודות מופשטות בלבד:

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

כל המתודות בממשק צריכות להיות מופשטות — הן מגדירות מה מחלקות שמממשות אותו חייבות לעשות, ולא איך לעשות זאת.

ממשו את הממשק במחלקה קונקרטית:

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

צרו מחלקה נוספת שמממשת את אותו ממשק:

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

השתמשו בממשק באופן פולימורפי:

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

פלט:

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

אפשר גם להשתמש בממשקים כרמזי טיפוס:

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

פלט:

Drawing a circle

נקודה מרכזית: ממשקים מגדירים מה מחלקות חייבות לעשות, ולא איך הן עושות זאת. השתמשו במחלקות בסיס מופשטות הכוללות רק מתודות מופשטות כדי ליצור חוזים ברורים שעל המחלקות המממשות לפעול לפיהם. כך מובטחת התנהגות עקבית בין מימושים שונים.

challenge icon

אתגר

בינוני

באתגר הזה תממשו מערכת נגן מדיה עם ממשקים.

עליכם לערוך את הקבצים הבאים:

  • playable.py - ממשו את מחלקות הבסיס המופשטות (ממשקים)
  • song.py - ממשו את המחלקה Song
  • video.py - ממשו את המחלקה Video
  • mediaplayer.py - ממשו את המחלקה MediaPlayer

כל קובץ מכיל הערות TODO מפורטות שינחו אתכם במימוש. פעלו לפי ההערות כדי ליצור מערכת נגן מדיה מלאה עם הורשה מתאימה ומימוש של ממשקים.

נסו בעצמכם

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

# מטפל מקיף במקרי בדיקה
test_case = input()

if test_case == "default_test":
    # מקרה הבדיקה המוגדר כברירת מחדל מהבעיה המקורית
    song = Song("Bohemian Rhapsody", "Queen", 355)
    video = Video("Python Tutorial", "1080p", 1800)
    player = MediaPlayer()

    # בדיקה עם שיר
    player.set_media(song)
    print(player.current_media.get_info())
    print(player.play())
    print(player.pause())
    print(player.stop())
    print()  # שורה ריקה לשיפור הקריאות

    # בדיקה עם סרטון
    player.set_media(video)
    print(player.current_media.get_info())
    print(player.play())
    print(player.pause())
    print(player.stop())

elif test_case == "empty_player":
    # בדיקת נגן המדיה כשלא הוגדרה בו מדיה
    player = MediaPlayer()
    print(player.play())  # אמור להדפיס "No media set"
    print(player.pause())  # אמור להדפיס "No media set"
    print(player.stop())  # אמור להדפיס "No media set"

elif test_case == "time_formatting":
    # בדיקת עיצוב הזמן במתודה 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":
    # בדיקה ש-Song ו-Video מממשים כראוי את הממשקים
    song = Song("Test Song", "Test Artist", 180)
    video = Video("Test Video", "480p", 240)
    
    # בדיקת מימוש הממשק
    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)}")
    
    # בדיקת כל המתודות של הממשק
    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":
    # בדיקת התנהגות פולימורפית באמצעות רשימה של סוגי מדיה שונים
    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":
    # בדקו מקרי קצה
    empty_song = Song("", "", 0)
    edge_video = Video("A" * 100, "", -10)  # כותרת ארוכה מאוד, רזולוציה ריקה, משך שלילי
    
    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":
    # ממשו בדיקת עומס עם אובייקטי מדיה רבים
    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()
    
    # בדקו עם כל השירים
    for i, song in enumerate(songs):
        player.set_media(song)
        if i % 10 == 0:  # הדפיסו רק כל פריט עשירי כדי להימנע מפלט רב מדי
            print(f"Playing song {i+1}: {player.play()}")
    
    # בדקו עם כל הסרטונים
    for i, video in enumerate(videos):
        player.set_media(video)
        if i % 10 == 0:  # הדפיסו רק כל פריט עשירי כדי להימנע מפלט רב מדי
            print(f"Playing video {i+1}: {player.play()}")
    
    print("Stress test completed successfully!")
quiz iconבחנו את עצמכם

השיעור הזה כולל חידון קצר. התחילו את השיעור כדי לענות עליו ולעקוב אחרי ההתקדמות.

כל השיעורים ביחידה תכנות מונחה עצמים

תרגלו בעצמכם: קומפיילר Python אונליין