Menu
CoddyTech

인터페이스 설계

Coddy Python 여정의 객체 지향 프로그래밍 섹션에 포함된 레슨. 64개 중 26번째.

인터페이스는 클래스가 따라야 하는 계약을 정의합니다. 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())  # Should print "No media set"
    print(player.pause())  # Should print "No media set"
    print(player.stop())  # Should print "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:  # 출력이 너무 많아지지 않도록 10번째마다만 출력
            print(f"Playing song {i+1}: {player.play()}")
    
    # 모든 비디오로 테스트
    for i, video in enumerate(videos):
        player.set_media(video)
        if i % 10 == 0:  # 출력이 너무 많아지지 않도록 10번째마다만 출력
            print(f"Playing video {i+1}: {player.play()}")
    
    print("Stress test completed successfully!")
quiz icon실력 점검

이 레슨에는 짧은 퀴즈가 포함되어 있습니다. 레슨을 시작해 문제를 풀고 진행 상황을 기록하세요.

객체 지향 프로그래밍의 모든 레슨

직접 연습해 보세요: 온라인 Python 컴파일러