עיצוב ממשקים
חלק מהיחידה תכנות מונחה עצמים במסלול ה-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נקודה מרכזית: ממשקים מגדירים מה מחלקות חייבות לעשות, ולא איך הן עושות זאת. השתמשו במחלקות בסיס מופשטות הכוללות רק מתודות מופשטות כדי ליצור חוזים ברורים שעל המחלקות המממשות לפעול לפיהם. כך מובטחת התנהגות עקבית בין מימושים שונים.
אתגר
בינוניבאתגר הזה תממשו מערכת נגן מדיה עם ממשקים.
עליכם לערוך את הקבצים הבאים:
playable.py- ממשו את מחלקות הבסיס המופשטות (ממשקים)song.py- ממשו את המחלקה Songvideo.py- ממשו את המחלקה Videomediaplayer.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!")השיעור הזה כולל חידון קצר. התחילו את השיעור כדי לענות עליו ולעקוב אחרי ההתקדמות.
כל השיעורים ביחידה תכנות מונחה עצמים
1יסודות התכנות מונחה העצמים (OOP)
קבצים חיצונייםמבוא ל-OOPמחלקות לעומת אובייקטיםהפרמטר selfמתודותמאפייניםשיטת הבנאי (__init__)חזרה: מחשבון פשוט5פולימורפיזם
בחינה מחדש של דריסת מתודותטיפוסיות ברווזמחלקות ומתודות אבסטרקטיותעיצוב ממשקיםסיכום – מחשבון צורות8מושגים מתקדמים בתכנות מונחה עצמים
קומפוזיציה לעומת הורשהMixinsמתודות סטטיות ומתודות מחלקהדקורטורים למחלקותמנהלי הקשרתרגלו בעצמכם: קומפיילר Python אונליין