본문으로 이동

데코레이터 패턴

위키백과, 우리 모두의 백과사전.
Cedar101 (토론 | 기여)님의 2013년 8월 27일 (화) 21:58 판 (-→‎파이썬: , -→‎자바스크립트: , +{{위키책}})

데코레이터 패턴(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

  1. 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();
  1. Output
바게트빵
베이킹파우더 50그램을 붓습니다.
설탕 10그램을 붙습니다.
밀가루 120그램을 붓습니다.
 
크림바게트빵
크림을 10그램 붓습니다.
베이킹파우더 50그램을 붓습니다.
10을 더 첨가합니다.
설탕 10그램을 붙습니다.
10을 더 첨가합니다.
밀가루 120그램을 붓습니다.
10을 더 첨가합니다.
 
소보루빵
베이킹 파우더를 30그램 붓습니다.
설탕을 20그램 붓습니다.
밀가루를 30그램 붓습니다.
 
팥소보루빵
팥을 10그램 붓습니다.베이킹 파우더를 30그램 붓습니다.
5을 더 첨가합니다.
설탕을 20그램 붓습니다.
5을 더 첨가합니다.
밀가루를 30그램 붓습니다.
5을 더 첨가합니다.

바깥 고리