인터페이스 vs 추상 클래스
Coddy PHP 여정의 객체 지향 프로그래밍 섹션에 포함된 레슨 — 91개 중 30번째.
이제 인터페이스와 추상 클래스를 모두 배웠으므로, 각각을 언제 사용해야 하는지 명확히 해보겠습니다. 이들은 비슷해 보일 수 있지만, 서로 다른 목적을 수행하며 뚜렷하게 다른 기능을 가지고 있습니다.
| 특징 | 인터페이스 | 추상 클래스 |
|---|---|---|
| 메서드 | 메서드 시그니처만 포함 | 추상 메서드와 구체적인 메서드 모두 포함 |
| 속성 | 상수만 포함 | 속성을 가질 수 있음 |
| 다중 상속 | 클래스는 여러 개를 구현할 수 있음 | 클래스는 하나만 상속할 수 있음 |
| 생성자 | __construct 시그니처를 선언할 수 있음 (본문 없음) | 본문이 있는 생성자를 정의할 수 있음 |
서로 관련이 없는 클래스들이 충족할 수 있는 계약을 정의하고 싶을 때 인터페이스를 사용하세요. 예를 들어, Printer와 Logger는 공통된 조상을 공유하지 않더라도 둘 다 Writable 인터페이스를 구현할 수 있습니다.
공통 코드를 공유하는 관련 클래스들이 있을 때 추상 클래스를 사용하세요. Dog와 Cat 클래스 모두 동일한 eat() 메서드 구현이 필요한 경우, 추상 Animal 클래스를 사용하면 해당 코드를 한 번만 작성할 수 있습니다.
두 가지 방식을 결합할 수도 있습니다. 클래스는 여러 인터페이스를 구현하는 동시에 추상 클래스를 상속받을 수 있습니다:
<?php
abstract class Animal {
protected $name;
public function eat() {
return $this->name . " is eating";
}
}
interface Swimmable {
public function swim();
}
class Duck extends Animal implements Swimmable {
public function __construct($name) {
$this->name = $name;
}
public function swim() {
return $this->name . " is swimming";
}
}
핵심 포인트: 서로 관련이 없는 클래스들 간의 기능을 정의할 때는 인터페이스를 선택하세요. 관련된 클래스들 간에 코드를 공유해야 할 때는 추상 클래스를 선택하세요.
챌린지
쉬움추상 클래스와 인터페이스를 언제 사용해야 하는지, 그리고 두 방식을 어떻게 효과적으로 결합하는지 보여주는 차량 시스템을 구축해 보겠습니다.
상속을 통해 공통 속성을 공유하면서도 인터페이스를 통해 추가적인 기능을 얻을 수 있는 시스템을 만들 것입니다. 이는 실제 설계 결정을 반영합니다. 자동차는 차량의 일종("is-a" 관계, 상속)이지만, 연료를 채울 수 있는 기능("has the capability" 관계, 인터페이스)도 가지고 있습니다.
코드를 네 개의 파일로 구성하세요:
Refuelable.php— 단일 메서드 시그니처인refuel($amount)를 가진Refuelable인터페이스를 정의합니다. 이 기능은 상속 계층 구조에 관계없이 연료 보충이 필요한 모든 클래스에 적용될 수 있습니다.Vehicle.php— 모든 차량에 공통된 기능을 제공하는 추상Vehicle클래스를 정의합니다. 보호된(protected)$brand속성과 보호된$fuelLevel속성(0에서 시작)을 가져야 합니다. 생성자는 브랜드 이름을 인자로 받습니다. 브랜드를 반환하는 구체적인getBrand()메서드, 현재 연료 수준을 반환하는 구체적인getFuelLevel()메서드, 그리고 자식 클래스에서 반드시 구현해야 하는 추상drive()메서드를 포함하세요.Car.php—Vehicle을 상속받고Refuelable을 구현하는Car클래스를 생성합니다. 상단에 필요한 두 파일을 포함하세요. 생성자는 브랜드를 인자로 받아 부모 생성자에 전달합니다.drive()를 구현하여"[brand] car is driving"을 반환하도록 하세요.refuel($amount)를 구현하여 연료 수준에 금액을 더하고"[brand] refueled to [fuelLevel] liters"를 반환하도록 하세요.main.php— Car 파일을 포함합니다. 브랜드 이름과 연료량(정수로 변환)이라는 두 개의 입력을 받습니다. 해당 브랜드로Car객체를 생성합니다. 첫 번째 줄에drive()의 결과를 출력하고, 두 번째 줄에 연료량을 인자로 전달한refuel()의 결과를 출력하세요.
이 챌린지는 핵심적인 차이점을 보여줍니다. 추상 Vehicle 클래스는 코드를 공유하고 "is-a" 관계를 설정하는 반면, Refuelable 인터페이스는 차량이 아니더라도(예: 발전기나 보트) 적용될 수 있는 기능을 추가합니다.
직접 해보기
<?php
require_once 'Car.php';
// 입력 읽기
$brand = trim(fgets(STDIN));
$fuelAmount = intval(trim(fgets(STDIN)));
// TODO: brand를 사용하여 Car 객체 생성
// TODO: 첫 번째 줄에 drive()의 결과 출력
// TODO: 두 번째 줄에 fuelAmount를 사용하여 refuel()의 결과 출력
?>이 레슨에는 짧은 퀴즈가 포함되어 있습니다. 레슨을 시작해 문제를 풀고 진행 상황을 기록하세요.
객체 지향 프로그래밍의 모든 레슨
8매직 메서드
매직 메서드 소개__toString 및 __debugInfo__get, __set, __isset, __unset__call 및 __callStatic__clone 및 객체 복제__serialize 및 __unserialize요약 - 커스텀 컬렉션