Menu
Coddy logo textTech

합성 vs 상속

Coddy Python 여정의 Object Oriented Programming 섹션에 포함된 레슨 — 64개 중 37번째.

객체 지향 프로그래밍은 코드 재사용을 위한 두 가지 주요 접근 방식인 상속("is-a" 관계)과 합성("has-a" 관계)을 제공합니다.

다음은 "is-a" 관계를 생성하는 상속의 예입니다:

class Animal:
    def __init__(self, name):
        self.name = name
    
    def eat(self):
        return f"{self.name} is eating"

class Dog(Animal):  # Dog은 Animal입니다 ("is-a" 관계)
    def bark(self):
        return "Woof!"

dog = Dog("Buddy")
print(dog.eat())   # 상속받은 메서드
print(dog.bark())  # 자체 메서드

다음은 "has-a" 관계를 생성하는 컴포지션(composition)의 예입니다:

class Engine:
    def start(self):
        return "Engine started"
    
    def stop(self):
        return "Engine stopped"

class Car:  # Car는 Engine을 "가지고 있습니다(has an)"
    def __init__(self):
        self.engine = Engine()  # 컴포지션
    
    def start(self):
        return self.engine.start()

car = Car()
print(car.start())  # 포함된 엔진을 사용합니다

더 복잡한 예제로 두 가지 접근 방식을 비교해 보세요:

# 상속 접근 방식
class Bird:
    def move(self):
        return "Flying"

class Duck(Bird):
    def quack(self):
        return "Quack!"

# 구성(Composition) 접근 방식
class FlyBehavior:
    def move(self):
        return "Flying"

class SwimBehavior:
    def move(self):
        return "Swimming"

class VersatileDuck:
    def __init__(self):
        self.fly_behavior = FlyBehavior()
        self.swim_behavior = SwimBehavior()
    
    def fly(self):
        return self.fly_behavior.move()
    
    def swim(self):
        return self.swim_behavior.move()
    
    def quack(self):
        return "Quack!"

두 가지 접근 방식을 모두 테스트해 보세요:

# 상속
duck1 = Duck()
print(duck1.move())  # 비행 중
print(duck1.quack()) # 꽥꽥!

# 합성  
duck2 = VersatileDuck()
print(duck2.fly())   # 비행 중
print(duck2.swim())  # 수영 중
print(duck2.quack()) # 꽥꽥!

출력:

Buddy is eating
Woof!
Engine started
Flying
Quack!
Flying
Swimming
Quack!

주요 차이점:

상속:

  • 부모와 자식 간의 강한 결합
  • "Is-a" 관계
  • 부모의 변경 사항이 모든 자식에게 영향을 미침
  • 진정한 계층적 관계에 가장 적합함

합성(Composition):

  • 객체 간의 낮은 결합도
  • "Has-a" 관계
  • 더 유연함 - 런타임에 동작을 변경할 수 있음
  • 테스트 및 수정이 더 쉬움

핵심 포인트: 진정한 "is-a" 관계가 있을 때 상속을 사용하세요. 유연성과 낮은 결합도가 필요할 때는 합성을 사용하세요. "상속보다는 합성(composition over inheritance)" 원칙은 유연성과 유지보수성 때문에 대부분의 경우 합성을 선호할 것을 권장합니다.

challenge icon

챌린지

중급

이 챌린지에서는 상속(inheritance)과 합성(composition) 패턴을 모두 사용하여 미디어 라이브러리 시스템을 구현합니다.

각 파일 내의 TODO 주석에 따라 다음 파일들을 수정해야 합니다:

  • media.py, book.py, movie.py, musicalbum.py - 상속 구현용
  • mediaitem.py, bookcomposition.py, moviecomposition.py, musicalbumcomposition.py - 합성 구현용

각 미디어 유형은 다음을 포함해야 합니다:

  • 제목(Title), 제작자(creator - 작가/감독/아티스트), 연도(year) 속성
  • 적절한 display_info() 메서드

치트 시트

객체 지향 프로그래밍은 코드 재사용을 위한 두 가지 주요 접근 방식을 제공합니다: 상속 ("is-a" 관계) 및 합성 ("has-a" 관계).

상속 예시:

class Animal:
    def __init__(self, name):
        self.name = name
    
    def eat(self):
        return f"{self.name} is eating"

class Dog(Animal):  # Dog은 Animal "입니다" (is-a)
    def bark(self):
        return "Woof!"

dog = Dog("Buddy")
print(dog.eat())   # 상속된 메서드
print(dog.bark())  # 자체 메서드

합성 예시:

class Engine:
    def start(self):
        return "Engine started"

class Car:  # Car는 Engine을 "가지고 있습니다" (has-a)
    def __init__(self):
        self.engine = Engine()  # 합성
    
    def start(self):
        return self.engine.start()

car = Car()
print(car.start())  # 합성된 엔진을 사용함

주요 차이점:

상속:

  • 부모와 자식 간의 강한 결합
  • "Is-a" 관계
  • 부모의 변경이 모든 자식에게 영향을 미침
  • 진정한 계층적 관계에 가장 적합

합성:

  • 객체 간의 느슨한 결합
  • "Has-a" 관계
  • 더 유연함 - 런타임에 동작을 변경할 수 있음
  • 테스트 및 수정이 더 쉬움

진정한 "is-a" 관계에는 상속을 사용하세요. 유연성과 느슨한 결합을 위해서는 합성을 사용하세요. "상속보다는 합성(composition over inheritance)" 원칙은 대부분의 경우 합성을 선호할 것을 권장합니다.

직접 해보기

from media import Media
from book import Book
from movie import Movie
from musicalbum import MusicAlbum
from mediaitem import MediaItem
from bookcomposition import BookComposition
from moviecomposition import MovieComposition
from musicalbumcomposition import MusicAlbumComposition

# 종합 테스트 케이스 핸들러
test_case = input()

def test_inheritance_basic():
    book = Book("The Hobbit", "J.R.R. Tolkien", 1937)
    movie = Movie("The Matrix", "Wachowski Sisters", 1999)
    album = MusicAlbum("Abbey Road", "The Beatles", 1969)
    
    assert book.display_info() == "Book: The Hobbit by J.R.R. Tolkien (1937)"
    assert movie.display_info() == "Movie: The Matrix directed by Wachowski Sisters (1999)"
    assert album.display_info() == "Music Album: Abbey Road by The Beatles (1969)"

def test_composition_basic():
    book_comp = BookComposition("Dune", "Frank Herbert", 1965)
    movie_comp = MovieComposition("Inception", "Christopher Nolan", 2010)
    album_comp = MusicAlbumComposition("Thriller", "Michael Jackson", 1982)
    
    assert book_comp.display_info() == "Book: Dune by Frank Herbert (1965)"
    assert movie_comp.display_info() == "Movie: Inception directed by Christopher Nolan (2010)"
    assert album_comp.display_info() == "Music Album: Thriller by Michael Jackson (1982)"

def test_inheritance_relationships():
    book = Book("Test Book", "Test Author", 2000)
    movie = Movie("Test Movie", "Test Director", 2001)
    album = MusicAlbum("Test Album", "Test Artist", 2002)
    
    assert isinstance(book, Book)
    assert isinstance(book, Media)
    assert isinstance(movie, Movie)
    assert isinstance(movie, Media)
    assert isinstance(album, MusicAlbum)
    assert isinstance(album, Media)

def test_attribute_access():
    # 상속 방식 테스트
    book = Book("Test Book", "Test Author", 2000)
    assert book.title == "Test Book"
    assert book.creator == "Test Author"
    assert book.year == 2000
    
    # 구성(Composition) 방식 테스트
    book_comp = BookComposition("Test Book", "Test Author", 2000)
    assert book_comp.media.title == "Test Book"
    assert book_comp.media.creator == "Test Author"
    assert book_comp.media.year == 2000

def test_polymorphism():
    media_list = [
        Book("Book1", "Author1", 2001),
        Movie("Movie1", "Director1", 2002),
        MusicAlbum("Album1", "Artist1", 2003)
    ]
    
    assert media_list[0].display_info() == "Book: Book1 by Author1 (2001)"
    assert media_list[1].display_info() == "Movie: Movie1 directed by Director1 (2002)"
    assert media_list[2].display_info() == "Music Album: Album1 by Artist1 (2003)"

def test_edge_cases():
    # 빈 문자열
    book = Book("", "", 0)
    assert book.display_info() == "Book:  by  (0)"
    
    # 특수 문자 - 여기서 구문 오류를 수정함
    movie = Movie("Test\"Movie", "Test\\nDirector", -1)
    assert movie.display_info() == "Movie: Test\"Movie directed by Test\\nDirector (-1)"
    
    # 극단적인 연도
    album = MusicAlbum("Test Album", "Test Artist", 9999)
    assert album.display_info() == "Music Album: Test Album by Test Artist (9999)"

def test_stress():
    # 많은 미디어 객체 생성
    books = [Book(f"Book{i}", f"Author{i}", 2000+i) for i in range(100)]
    movies = [Movie(f"Movie{i}", f"Director{i}", 2000+i) for i in range(100)]
    albums = [MusicAlbum(f"Album{i}", f"Artist{i}", 2000+i) for i in range(100)]
    
    for i, book in enumerate(books):
        assert book.display_info() == f"Book: Book{i} by Author{i} ({2000+i})"
    
    for i, movie in enumerate(movies):
        assert movie.display_info() == f"Movie: Movie{i} directed by Director{i} ({2000+i})"
    
    for i, album in enumerate(albums):
        assert album.display_info() == f"Music Album: Album{i} by Artist{i} ({2000+i})"

# 입력에 따라 적절한 테스트 실행
if test_case == "default_test" or test_case == "":
    test_inheritance_basic()
    test_composition_basic()
    print("All tests passed!")
elif test_case == "inheritance_test":
    test_inheritance_basic()
    test_inheritance_relationships()
    print("Inheritance tests passed!")
elif test_case == "composition_test":
    test_composition_basic()
    print("Composition tests passed!")
elif test_case == "polymorphism_test":
    test_polymorphism()
    print("Polymorphism tests passed!")
elif test_case == "attribute_test":
    test_attribute_access()
    print("Attribute tests passed!")
elif test_case == "edge_cases":
    test_edge_cases()
    print("Edge case tests passed!")
elif test_case == "stress_test":
    test_stress()
    print("Stress tests passed!")
quiz icon실력 점검

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

Object Oriented Programming의 모든 레슨