Menu
Coddy logo textTech

트레이트 vs 상속

Coddy PHP 여정의 객체 지향 프로그래밍 섹션에 포함된 레슨 — 91개 중 55번째.

이제 트레이트(traits)가 어떻게 작동하는지 이해하셨으니, 트레이트와 상속(inheritance)을 각각 언제 사용해야 하는지 명확히 해보겠습니다. 둘 다 코드 재사용을 가능하게 하지만, 서로 다른 목적을 수행하며 뚜렷한 특징을 가지고 있습니다.

상속은 "is-a" 관계를 설정합니다. Animal을 확장하는 Dog 클래스는 개 동물임을 의미합니다. 자식 클래스는 부모의 정체성을 상속받으며 부모 타입이 요구되는 곳 어디에서나 사용될 수 있습니다.

트레이트(Traits)는 "has-a" 기능을 제공합니다. 클래스가 Loggable 트레이트를 사용할 때, 해당 클래스는 로깅 기능을 가집니다. 하지만 클래스 자체가 로거(logger)가 되는 것은 아닙니다. 트레이트는 클래스의 본질을 바꾸지 않으면서 동작을 추가합니다.

<?php
// 상속: Dog는 Animal입니다
class Animal {
    public function breathe(): void {
        echo "Breathing";
    }
}

class Dog extends Animal {
    public function bark(): void {
        echo "Woof!";
    }
}

// 트레이트: Dog는 로깅 기능을 가집니다
trait Loggable {
    public function log(string $msg): void {
        echo "Log: $msg";
    }
}

class Cat extends Animal {
    use Loggable;
}

기억해야 할 주요 차이점:

측면상속 (Inheritance)트레이트 (Traits)
관계is-ahas-a 기능
제한단일 부모만 허용다중 트레이트 허용
타입 검사instanceof와 함께 작동타입 정체성 없음
가장 적합한 경우계층적 관계관련 없는 클래스 간의 공유된 동작

클래스가 공통된 정체성을 공유할 때 상속을 사용하세요. 서로 관련 없는 클래스들이 동일한 계층 구조에 속하지 않으면서 동일한 기능이 필요할 때 트레이트(traits)를 사용하세요.

challenge icon

챌린지

쉬움

상속과 트레이트(trait)를 언제 사용해야 하는지 보여주는 차량 시스템을 구축해 보겠습니다. 상속을 통해 공통된 정체성을 공유하는 차량 계층 구조를 만들고, 트레이트를 통해 횡단 관심사(cross-cutting capabilities) 기능을 추가할 것입니다.

코드는 다음 네 개의 파일로 구성됩니다:

  • Trackable.php — GPS 추적 기능을 제공하는 Trackable이라는 트레이트를 생성합니다. 이 트레이트는 다음을 포함해야 합니다:
    • 프라이빗(private) 속성 $location (문자열)
    • 현재 위치를 저장하는 setLocation(string $location) 메서드
    • "Location: [location]"을 반환하는 getLocation() 메서드
    이 트레이트는 "has-a" 능력을 나타냅니다. 어떤 차량이든 추적 기능을 가질 수 있지만, 추적 기능이 있다고 해서 그것이 차량이 되는 것은 아닙니다.
  • Vehicle.php — "is-a" 관계를 설정하는 기본 Vehicle 클래스를 생성합니다. 트레이트 파일을 포함하세요. 생성자 프로모션(constructor promotion)을 사용하여 보호된(protected) $brand 속성을 정의합니다. "Vehicle: [brand]"를 반환하는 describe() 메서드를 추가합니다. 우리 함대의 모든 차량은 GPS를 가질 것이므로 이 클래스는 Trackable 트레이트를 사용해야 합니다.
  • Car.phpVehicle을 상속받는 Car 클래스를 생성합니다. Vehicle 파일을 포함하세요. 생성자 프로모션을 사용하여 브랜드와 프라이빗 $doors (정수) 속성을 받습니다. 브랜드와 함께 부모 생성자를 호출합니다. "Car: [brand] with [doors] doors"를 반환하도록 describe() 메서드를 오버라이드합니다.
  • main.php — Car 파일을 포함하세요. 브랜드 이름, 문 개수, 위치 문자열의 세 가지 입력을 받게 됩니다. Car 인스턴스를 생성하고 위치를 설정한 후 다음 두 줄을 출력합니다:
    • describe() 호출 결과
    • getLocation() 호출 결과

여기서 상속과 트레이트가 어떻게 함께 작동하는지 주목하세요: CarVehicle의 일종(is a)이며(상속은 정체성을 확립함), Vehicle은 추적 기능(has)을 가집니다(트레이트는 동작을 추가함). instanceof Vehicle을 사용하여 어떤 객체가 차량인지 확인할 수 있지만, 확인할 수 있는 "Trackable" 타입은 없습니다. 이것이 이 두 방식의 핵심적인 차이점입니다.

직접 해보기

<?php
// 메인 파일 - Car 인스턴스 생성 및 테스트

// TODO: Car.php 파일 포함

// 입력 읽기
$brand = trim(fgets(STDIN));
$doors = intval(trim(fgets(STDIN)));
$location = trim(fgets(STDIN));

// TODO: brand와 doors를 사용하여 Car 인스턴스 생성

// TODO: 자동차의 위치 설정

// TODO: describe() 결과 출력

// TODO: getLocation() 결과 출력
?>
quiz icon실력 점검

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

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