Thiết kế giao diện
Thuộc phần Lập trình hướng đối tượng trong hành trình Python của Coddy. Bài học 26 trên 64.
Giao diện định nghĩa một hợp đồng mà các lớp phải tuân theo. Trong Python, ta tạo giao diện bằng cách dùng các lớp cơ sở trừu tượng, trong đó tất cả phương thức đều là trừu tượng.
Nhập module abc:
from abc import ABC, abstractmethodTạo một giao diện chỉ có các phương thức trừu tượng:
class Drawable(ABC):
@abstractmethod
def draw(self):
pass
@abstractmethod
def resize(self, width, height):
passTất cả phương thức trong một interface nên là phương thức trừu tượng. Chúng xác định các lớp triển khai phải làm gì, chứ không phải làm như thế nào.
Triển khai giao diện trong một lớp cụ thể:
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}"Tạo một lớp khác triển khai cùng giao diện:
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}"Sử dụng giao diện (interface) theo cách đa hình:
shapes = [Circle(5), Rectangle(3, 4)]
for shape in shapes:
print(shape.draw())
print(shape.resize(10, 8))Đầu ra:
Drawing a circle
Resized circle to radius 4.0
Drawing a rectangle
Resized rectangle to 10x8Bạn cũng có thể dùng giao diện làm gợi ý kiểu dữ liệu:
def render_shape(drawable: Drawable):
return drawable.draw()
circle = Circle(3)
print(render_shape(circle))Đầu ra:
Drawing a circleĐiểm chính: Giao diện (interface) định nghĩa những việc các lớp phải làm, chứ không quy định cách chúng thực hiện. Hãy dùng các lớp cơ sở trừu tượng chỉ có phương thức trừu tượng để tạo ra những quy ước rõ ràng mà các lớp triển khai phải tuân theo. Điều này đảm bảo hành vi nhất quán giữa các cách triển khai khác nhau.
Thử thách
Trung bìnhTrong thử thách này, bạn sẽ triển khai một hệ thống trình phát đa phương tiện bằng các giao diện.
Bạn cần chỉnh sửa các tệp sau:
playable.py- Triển khai các lớp cơ sở trừu tượng (giao diện)song.py- Triển khai lớp Songvideo.py- Triển khai lớp Videomediaplayer.py- Triển khai lớp MediaPlayer
Mỗi tệp đều có các chú thích TODO chi tiết để hướng dẫn bạn triển khai. Hãy làm theo những chú thích này để tạo một hệ thống trình phát đa phương tiện hoàn chỉnh với tính kế thừa phù hợp và cách triển khai giao diện.
Tự làm thử
from song import Song
from video import Video
from mediaplayer import MediaPlayer
from playable import Playable, MediaInfo
# Xử lý toàn diện các test case
test_case = input()
if test_case == "default_test":
# Test case mặc định từ đề bài gốc
song = Song("Bohemian Rhapsody", "Queen", 355)
video = Video("Python Tutorial", "1080p", 1800)
player = MediaPlayer()
# Kiểm tra với bài hát
player.set_media(song)
print(player.current_media.get_info())
print(player.play())
print(player.pause())
print(player.stop())
print() # Dòng trống giúp dễ đọc hơn
# Kiểm tra với 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":
# Kiểm tra trình phát khi chưa thiết lập nội dung
player = MediaPlayer()
print(player.play()) # Sẽ in ra "No media set"
print(player.pause()) # Sẽ in ra "No media set"
print(player.stop()) # Sẽ in ra "No media set"
elif test_case == "time_formatting":
# Kiểm tra cách định dạng thời gian trong phương thức (method) 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":
# Kiểm tra Song và Video triển khai đúng các giao diện
song = Song("Test Song", "Test Artist", 180)
video = Video("Test Video", "480p", 240)
# Kiểm tra việc triển khai giao diện
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)}")
# Kiểm tra tất cả phương thức của giao diện
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":
# Kiểm tra hành vi đa hình với danh sách (list) gồm nhiều loại nội dung khác nhau
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":
# Kiểm tra các trường hợp biên
empty_song = Song("", "", 0)
edge_video = Video("A" * 100, "", -10) # Tiêu đề rất dài, độ phân giải trống, thời lượng âm
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":
# Triển khai kiểm thử tải với nhiều đối tượng đa phương tiện
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()
# Kiểm tra với tất cả bài hát
for i, song in enumerate(songs):
player.set_media(song)
if i % 10 == 0: # Chỉ in ra mỗi mục thứ 10 để tránh quá nhiều đầu ra
print(f"Playing song {i+1}: {player.play()}")
# Kiểm tra với tất cả video
for i, video in enumerate(videos):
player.set_media(video)
if i % 10 == 0: # Chỉ in ra mỗi mục thứ 10 để tránh quá nhiều đầu ra
print(f"Playing video {i+1}: {player.play()}")
print("Stress test completed successfully!")Bài học này có một bài trắc nghiệm ngắn. Bắt đầu bài học để trả lời và theo dõi tiến độ.
Tất cả bài học trong Lập trình hướng đối tượng
1Nền tảng về lập trình hướng đối tượng
Tệp bên ngoàiGiới thiệu về lập trình hướng đối tượngLớp và đối tượngTham số selfPhương thứcThuộc tínhPhương thức khởi tạo (__init__)Ôn tập: máy tính đơn giản4Kế thừa
Kế thừa cơ bảnHàm super()Ghi đè phương thứcKế thừa đa lớpThứ tự phân giải phương thứcÔn tập: hệ thống phân cấp nhân viên2Decorator
Giới thiệu về decoratorDecorator thuộc tínhDecorator phương thức tĩnhDecorator phương thức lớp5Tính đa hình
Xem lại cách ghi đè phương thứcKiểu gõ vịtLớp và phương thức trừu tượngThiết kế giao diệnÔn tập: máy tính hình học8Các khái niệm OOP nâng cao
Kết hợp và kế thừaMixinPhương thức tĩnh và phương thức lớpDecorator lớpTrình quản lý ngữ cảnhTự luyện tập: Trình biên dịch Python online