데코레이터 패턴
보이기
데코레이터 패턴(Decorator pattern)이란 주어진 상황 및 용도에 따라 어떤 객체에 책임을 덧붙이는 패턴으로, 기능 확장이 필요할 때 서브클래싱 대신 쓸 수 있는 유연한 대안이 될 수 있다.
예
자바
// the Window interface
interface Window {
public void draw(); // draws the Window
public String getDescription(); // returns a description of the Window
}
// implementation of a simple Window without any scrollbars
class SimpleWindow implements Window {
public void draw() {
// draw window
}
public String getDescription() {
return "simple window";
}
}
아래의 클래스들은 모든 Window 클래스들의 데코레이터를 포함하고 있다.
// abstract decorator class - note that it implements Window
abstract class WindowDecorator implements Window {
protected Window decoratedWindow; // the Window being decorated
public WindowDecorator (Window decoratedWindow) {
this.decoratedWindow = decoratedWindow;
}
}
// the first concrete decorator which adds vertical scrollbar functionality
class VerticalScrollBarDecorator extends WindowDecorator {
public VerticalScrollBarDecorator (Window decoratedWindow) {
super(decoratedWindow);
}
public void draw() {
drawVerticalScrollBar();
decoratedWindow.draw();
}
private void drawVerticalScrollBar() {
// draw the vertical scrollbar
}
public String getDescription() {
return decoratedWindow.getDescription() + ", including vertical scrollbars";
}
}
// the second concrete decorator which adds horizontal scrollbar functionality
class HorizontalScrollBarDecorator extends WindowDecorator {
public HorizontalScrollBarDecorator (Window decoratedWindow) {
super(decoratedWindow);
}
public void draw() {
drawHorizontalScrollBar();
decoratedWindow.draw();
}
private void drawHorizontalScrollBar() {
// draw the horizontal scrollbar
}
public String getDescription() {
return decoratedWindow.getDescription() + ", including horizontal scrollbars";
}
}
Window 인스터스를 만드는 테스트 프로그램은 아래와 같다.
public class DecoratedWindowTest {
public static void main(String[] args) {
// create a decorated Window with horizontal and vertical scrollbars
Window decoratedWindow = new HorizontalScrollBarDecorator (
new VerticalScrollBarDecorator(new SimpleWindow()));
// print the Window's description
System.out.println(decoratedWindow.getDescription());
}
}
C++
#include <iostream>
using namespace std;
/* Component (interface) */
class Widget {
public:
virtual void draw() = 0;
virtual ~Widget() {}
};
/* ConcreteComponent */
class TextField : public Widget {
private:
int width, height;
public:
TextField( int w, int h ){
width = w;
height = h;
}
void draw() {
cout << "TextField: " << width << ", " << height << '\n';
}
};
/* Decorator (interface) */
class Decorator : public Widget {
private:
Widget* wid; // reference to Widget
public:
Decorator( Widget* w ) {
wid = w;
}
void draw() {
wid->draw();
}
~Decorator() {
delete wid;
}
};
/* ConcreteDecoratorA */
class BorderDecorator : public Decorator {
public:
BorderDecorator( Widget* w ) : Decorator( w ) { }
void draw() {
Decorator::draw();
cout << " BorderDecorator" << '\n';
}
};
/* ConcreteDecoratorB */
class ScrollDecorator : public Decorator {
public:
ScrollDecorator( Widget* w ) : Decorator( w ) { }
void draw() {
Decorator::draw();
cout << " ScrollDecorator" << '\n';
}
};
int main( void ) {
Widget* aWidget = new BorderDecorator(
new ScrollDecorator(
new TextField( 80, 24 )));
aWidget->draw();
delete aWidget;
}
C#
namespace GSL_Decorator_pattern
{
interface IWindowObject
{
void draw(); // draws the object
String getDescription(); // returns a description of the object
}
class ControlComponent : IWindowObject
{
public ControlComponent()
{
}
public void draw() // draws the object
{
Console.WriteLine( "ControlComponent::draw()" );
}
public String getDescription() // returns a description of the object
{
return "ControlComponent::getDescription()";
}
}
abstract class Decorator : IWindowObject
{
protected IWindowObject _decoratedWindow = null; // the object being decorated
public Decorator( IWindowObject decoratedWindow )
{
_decoratedWindow = decoratedWindow;
}
public virtual void draw()
{
_decoratedWindow.draw();
Console.WriteLine("\tDecorator::draw() ");
}
public virtual String getDescription() // returns a description of the object
{
return _decoratedWindow.getDescription() + "\n\t" + "Decorator::getDescription() ";
}
}
// the first decorator
class DecorationA : Decorator
{
public DecorationA(IWindowObject decoratedWindow) : base(decoratedWindow)
{
}
public override void draw()
{
base.draw();
DecorationAStuff();
}
private void DecorationAStuff()
{
Console.WriteLine("\t\tdoing DecorationA things");
}
public override String getDescription()
{
return base.getDescription() + "\n\t\tincluding " + this.ToString();
}
}// end class ConcreteDecoratorA : Decorator
class DecorationB : Decorator
{
public DecorationB(IWindowObject decoratedWindow) : base(decoratedWindow)
{
}
public override void draw()
{
base.draw();
DecorationBStuff();
}
private void DecorationBStuff()
{
Console.WriteLine("\t\tdoing DecorationB things");
}
public override String getDescription()
{
return base.getDescription() + "\n\t\tincluding " + this.ToString();
}
}// end class DecorationB : Decorator
class DecorationC : Decorator
{
public DecorationC(IWindowObject decoratedWindow) : base(decoratedWindow)
{
}
public override void draw()
{
base.draw();
DecorationCStuff();
}
private void DecorationCStuff()
{
Console.WriteLine("\t\tdoing DecorationC things");
}
public override String getDescription()
{
return base.getDescription() + "\n\t\tincluding " + this.ToString();
}
}// end class DecorationC : Decorator
}// end of namespace GSL_Decorator_pattern
PHP
- Example
abstract class Bakery {
protected $sBakeryName;
public function PourWheatFlour() {}
public function PourBakingFlour() {}
public function PourSugar() {}
public function GetBakeryName() {
return $this->sBakeryName;
}
}
class BaguetleBakery extends Bakery {
public function BaguetleBakery() {
$this->sBakeryName = "바게트빵<br/>";
}
public function PourBakingFlour() {
return "베이킹파우더 50그램을 붓습니다.<br/>";
}
public function PourWheatFlour() {
return "밀가루 120그램을 붓습니다.<br/>";
}
public function PourSugar() {
return "설탕 10그램을 붙습니다.<br/>";
}
}
class SoboruBakery extends Bakery {
public function SoboruBakery() {
$this->sBakeryName = "소보루빵<br/>";
}
public function PourBakingFlour() {
return "베이킹 파우더를 30그램 붓습니다.<br/>";
}
public function PourWheatFlour() {
return "밀가루를 30그램 붓습니다.<br/>";
}
public function PourSugar() {
return "설탕을 20그램 붓습니다.<br/>";
}
}
abstract class BakeryDecorator extends Bakery {
public function GetBakeryName() {
throw new Exception("BakeryDecorator를 상속 받으려면 GetBakeryName의 재정의가 필요합니다.");
}
}
class CreamBakery extends BakeryDecorator {
private $oBakery;
public function CreamBakery(Bakery $oBakery) {
$this->oBakery = $oBakery;
}
public function GetBakeryName() {
return "크림".$this->oBakery->GetBakeryName();
}
public function PourCream() {
return "크림을 10그램 붓습니다.<br/>";
}
public function PourBakingFlour() {
return $this->oBakery->PourBakingFlour()."10을 더 첨가합니다.<br/>";
}
public function PourSugar() {
return $this->oBakery->PourSugar()."10을 더 첨가합니다.<br/>";
}
public function PourWheatFlour() {
return $this->oBakery->PourWheatFlour()."10을 더 첨가합니다.<br/>";
}
}
class RedbeanBakery extends BakeryDecorator {
private $oBakery;
public function RedbeanBakery(Bakery $oBakery) {
$this->oBakery = $oBakery;
}
public function GetBakeryName() {
return "팥".$this->oBakery->GetBakeryName();
}
public function PourRedbean() {
return "팥을 10그램 붓습니다.";
}
public function PourBakingFlour() {
return $this->oBakery->PourBakingFlour()."5을 더 첨가합니다.<br/>";
}
public function PourSugar() {
return $this->oBakery->PourSugar()."5을 더 첨가합니다.<br/>";
}
public function PourWheatFlour() {
return $this->oBakery->PourWheatFlour()."5을 더 첨가합니다.<br/>";
}
}
class BakeryFactory {
public static function main() {
$oBaguetle = new BaguetleBakery();
echo $oBaguetle->GetBakeryName();
echo $oBaguetle->PourBakingFlour();
echo $oBaguetle->PourSugar();
echo $oBaguetle->PourWheatFlour();
echo "<br/><br/><br/>";
$oCreamBaguetle = new CreamBakery($oBaguetle);
echo $oCreamBaguetle->GetBakeryName();
echo $oCreamBaguetle->PourCream();
echo $oCreamBaguetle->PourBakingFlour();
echo $oCreamBaguetle->PourSugar();
echo $oCreamBaguetle->PourWheatFlour();
echo "<br/><br/><br/>";
$oSobotu = new SoboruBakery();
echo $oSobotu->GetBakeryName();
echo $oSobotu->PourBakingFlour();
echo $oSobotu->PourSugar();
echo $oSobotu->PourWheatFlour();
echo "<br/><br/><br/>";
$oRedbeanSoboru = new RedbeanBakery($oSobotu);
echo $oRedbeanSoboru->GetBakeryName();
echo $oRedbeanSoboru->PourRedbean();
echo $oRedbeanSoboru->PourBakingFlour();
echo $oRedbeanSoboru->PourSugar();
echo $oRedbeanSoboru->PourWheatFlour();
}
}
BakeryFactory::main();
- Output
바게트빵
베이킹파우더 50그램을 붓습니다.
설탕 10그램을 붙습니다.
밀가루 120그램을 붓습니다.
크림바게트빵
크림을 10그램 붓습니다.
베이킹파우더 50그램을 붓습니다.
10을 더 첨가합니다.
설탕 10그램을 붙습니다.
10을 더 첨가합니다.
밀가루 120그램을 붓습니다.
10을 더 첨가합니다.
소보루빵
베이킹 파우더를 30그램 붓습니다.
설탕을 20그램 붓습니다.
밀가루를 30그램 붓습니다.
팥소보루빵
팥을 10그램 붓습니다.베이킹 파우더를 30그램 붓습니다.
5을 더 첨가합니다.
설탕을 20그램 붓습니다.
5을 더 첨가합니다.
밀가루를 30그램 붓습니다.
5을 더 첨가합니다.