인터페이스와 추상 클래스 비교
Coddy PHP 여정의 객체 지향 프로그래밍 섹션에 포함된 레슨. 91개 중 30번째.
이제 interface와 abstract 클래스를 모두 배웠으니, 각각을 언제 사용해야 하는지 명확히 알아보겠습니다. 둘은 비슷해 보일 수 있지만 서로 다른 목적과 고유한 기능을 제공합니다.
| 기능 | 인터페이스 | 추상 클래스 |
|---|---|---|
| 메서드 | 메서드 시그니처만 | 추상 메서드와 구체 메서드 모두 |
| 속성 | 상수만 | 속성을 가질 수 있음 |
| 다중 상속 | class는 여러 개를 구현할 수 있음 | class는 하나만 상속할 수 있음 |
| 생성자 | __construct 시그니처를 선언할 수 있음(본문 없음) | 본문이 있는 constructor를 정의할 수 있음 |
서로 관련이 없는 클래스들이 충족할 수 있는 계약을 정의하려면 interface를 사용하세요. 예를 들어 Printer와 Logger는 공통 조상을 공유하지 않더라도 둘 다 Writable interface를 구현할 수 있습니다.
공통 코드를 공유하는 관련된 class들이 있을 때 abstract class를 사용하세요. Dog 및 Cat class에 동일한 eat() method 구현이 모두 필요한 경우, abstract Animal class를 사용하면 해당 코드를 한 번만 작성할 수 있습니다.
두 접근 방식을 결합할 수도 있습니다. 클래스는 여러 인터페이스를 Implement하면서 abstract 클래스를 extends할 수 있습니다.
<?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";
}
}
핵심 요점: 서로 관련 없는 클래스 전반에서 기능을 정의하려면 interface를 선택하세요. 관련된 클래스 간에 코드를 공유해야 할 때는 abstract 클래스를 선택하세요.
챌린지
쉬움추상 클래스와 인터페이스를 언제 사용해야 하는지, 그리고 두 접근 방식을 어떻게 효과적으로 결합할 수 있는지 보여 주는 차량 시스템을 만들어 봅시다.
상속을 통해 차량이 공통 속성을 공유하면서도 인터페이스를 통해 추가 기능을 얻을 수 있는 시스템을 만들게 됩니다. 이는 실제 설계 결정을 반영합니다. 자동차는 차량이라는 "is a" 관계를 가지지만, 동시에 연료를 보급할 수 있는 "has the capability"도 가집니다.
코드를 네 개의 파일로 구성하세요.
Refuelable.php: 단일 메서드 시그니처인refuel($amount)를 포함하는Refuelableinterface를 Define하세요. 이 기능은 상속 계층과 관계없이 연료 보급이 필요한 모든 class에 적용될 수 있습니다.Vehicle.php: 모든 차량에 공유 기능을 제공하는 abstractVehicleclass를 Define하세요. protected$brandproperty와 protected$fuelLevelproperty(0에서 시작)를 가져야 합니다. constructor는 브랜드 이름을 accepts합니다. 브랜드를 반환하는 구체적인getBrand()method, 현재 연료 level을 반환하는 구체적인getFuelLevel()method, 그리고 자식 class가 Implement해야 하는 abstractdrive()method를 포함하세요.Car.php:Vehicle을 extends하고Refuelable을 implements하는Carclass를 Create하세요. 두 필수 파일을 맨 위에서 include하세요. constructor는 브랜드를 accepts하고 이를 parent constructor에 passes합니다.drive()를 Implement하여"[brand] car is driving"을 반환하세요.refuel($amount)를 Implement하여 amount를 fuel level에 Add하고"[brand] refueled to [fuelLevel] liters"를 반환하세요.main.php: Car 파일을 include하세요. 두 개의 입력, 즉 브랜드 이름과 fuel amount를 받습니다(정수로 변환). 브랜드를 사용해Car를 Create하세요. 첫 번째 line에는drive()의 결과를 Print하고, 두 번째 line에는 fuel amount와 함께refuel()의 결과를 Print하세요.
이 challenge는 핵심적인 차이를 보여 줍니다. abstract Vehicle class는 코드를 공유하고 "is-a" 관계를 설정하는 반면, Refuelable interface는 generator나 boat처럼 서로 관련이 없는 다른 class에도 적용될 수 있는 capability를 추가하며, 해당 class가 차량일 것을 요구하지 않습니다.
직접 해보기
<?php
require_once 'Car.php';
// 입력 읽기
$brand = trim(fgets(STDIN));
$fuelAmount = intval(trim(fgets(STDIN)));
// TODO: 브랜드로 Car 생성
// TODO: 첫 번째 줄에 drive()의 결과 출력
// TODO: 두 번째 줄에 연료량으로 refuel()의 결과 출력
?>이 레슨에는 짧은 퀴즈가 포함되어 있습니다. 레슨을 시작해 문제를 풀고 진행 상황을 기록하세요.
객체 지향 프로그래밍의 모든 레슨
직접 연습해 보세요: 온라인 PHP 컴파일러