데코레이터 패턴
Coddy PHP 여정의 객체 지향 프로그래밍 섹션에 포함된 레슨. 91개 중 77번째.
Decorator Pattern은 객체를 데코레이터라고 하는 특수한 래퍼 객체로 감싸 객체에 새로운 동작을 동적으로 추가할 수 있게 해 주는 구조적 디자인 패턴입니다. 컴파일 시간에 동작을 추가하는 상속과 달리, 데코레이터는 런타임에 동작을 추가합니다.
커피숍을 상상해 보세요. 기본 커피로 시작한 다음 우유, 설탕 또는 휘핑크림 같은 추가 재료를 넣습니다.
각 추가 요소는 원래의 coffee를 감싸고 description과 비용에 adds합니다. 핵심 통찰은 base coffee와 데코레이터가 모두 동일한 interface를 공유한다는 것입니다.
<?php
interface Coffee {
public function getDescription(): string;
public function getCost(): float;
}
class SimpleCoffee implements Coffee {
public function getDescription(): string {
return "Simple Coffee";
}
public function getCost(): float {
return 2.00;
}
}
데코레이터는 동일한 Coffee 인터페이스를 구현하고 다른 Coffee 객체를 감쌉니다:
<?php
class MilkDecorator implements Coffee {
public function __construct(private Coffee $coffee) {}
public function getDescription(): string {
return $this->coffee->getDescription() . ", Milk";
}
public function getCost(): float {
return $this->coffee->getCost() + 0.50;
}
}
class SugarDecorator implements Coffee {
public function __construct(private Coffee $coffee) {}
public function getDescription(): string {
return $this->coffee->getDescription() . ", Sugar";
}
public function getCost(): float {
return $this->coffee->getCost() + 0.25;
}
}
$coffee = new SimpleCoffee();
$coffee = new MilkDecorator($coffee);
$coffee = new SugarDecorator($coffee);
echo $coffee->getDescription() . " = $" . $coffee->getCost();
출력:
Simple Coffee, Milk, Sugar = $2.75각 decorator는 이전 object를 감싸 체인을 형성합니다. 이 패턴을 사용하면 가능한 모든 조합에 대해 class를 만들 필요 없이 동작을 원하는 순서와 수량으로 결합할 수 있습니다. 우유를 두 배로 추가하고 싶나요? 그냥 두 번 감싸면 됩니다.
챌린지
쉬움Decorator Pattern을 사용하여 피자 주문 시스템을 만들어 봅시다. 기본 피자로 시작한 다음 토핑을 동적으로 추가합니다. each 토핑은 피자를 감싸고 설명과 가격에 값을 더하며, 이는 레슨의 커피 예제와 같습니다.
코드를 네 개의 파일로 구성합니다:
Pizza.php: 모든 피자와 토핑에 대한 계약을 정의하는Pizzainterface를 Define합니다. 다음 두 methods가 있어야 합니다:getDescription(): string및getPrice(): float.BasePizza.php: Pizza interface를 포함하고 이를 implements하는MargheritaPizzaclass를 Create합니다. 이것이"Margherita"라는 description과8.00의 가격을 가진 기본 피자입니다.Toppings.php: Pizza interface를 포함하고 이를 implements하는 세 개의 decorator classes를 Create합니다. 각 decorator는Pizzaobject를 감싸며(constructor에서 전달받음), description과 가격을 모두 향상합니다:CheeseTopping: description에", Extra Cheese"를 추가하고 가격에1.50을 더합니다PepperoniTopping: description에", Pepperoni"를 추가하고 가격에2.00을 더합니다MushroomTopping: description에", Mushrooms"를 추가하고 가격에1.25를 더합니다
main.php: BasePizza 및 Toppings 파일을 포함합니다. 추가할 토핑의 쉼표로 구분된 list를 하나의 input으로 받습니다(예:"cheese,pepperoni"또는"mushroom,cheese,cheese").MargheritaPizza로 시작합니다. input의 각 토핑에 대해 적절한 decorator로 피자를 감쌉니다:"cheese"는CheeseTopping으로 감쌉니다"pepperoni"는PepperoniTopping으로 감쌉니다"mushroom"은MushroomTopping으로 감쌉니다
모든 토핑을 적용한 후, 최종 피자의 description과 가격을 다음 format으로 출력합니다:
[description] = $[price]가격은 소수점 이하 두 자리로 Format합니다.
동일한 토핑을 여러 번 적용할 수 있다는 점에 주목하세요. 더블 치즈를 주문한다는 것은 단순히 CheeseTopping으로 두 번 감싸는 것을 의미합니다. 이러한 유연성이 바로 Decorator Pattern의 강력함입니다!
직접 해보기
<?php
require_once 'BasePizza.php';
require_once 'Toppings.php';
// 입력 읽기 - 쉼표로 구분된 토핑 목록
$input = trim(fgets(STDIN));
$toppings = explode(',', $input);
// 기본 MargheritaPizza로 시작
$pizza = new MargheritaPizza();
// TODO: 각 토핑을 순회하며 적절한 데코레이터로 피자를 감싸기
// - "cheese" -> CheeseTopping으로 감싸기
// - "pepperoni" -> PepperoniTopping으로 감싸기
// - "mushroom" -> MushroomTopping으로 감싸기
// TODO: 결과를 다음 형식으로 출력: [description] = $[price]
// number_format()을 사용하여 가격을 소수점 2자리로 포맷
?>이 레슨에는 짧은 퀴즈가 포함되어 있습니다. 레슨을 시작해 문제를 풀고 진행 상황을 기록하세요.
객체 지향 프로그래밍의 모든 레슨
직접 연습해 보세요: 온라인 PHP 컴파일러