C# 이것저것/C# 디자인패턴

[C#] Decorator 패턴

agingcurve 2024. 4. 15. 14:10
반응형

카테고리 : 구조 패턴

개요 : Decorator 패턴은 기존 객체의 구조를 그대로 둔 채, 그 객체에 부가적인 기능을 동적으로 추가하기 위해 사용된다. 객체지향 프로그래밍에서 흔히 클래스에 새로운 기능들을 추가하기 위해 서브클래스를 만들어 사용하는데, 이것의 대안적인 방법으로 Decorator 패턴을 이용할 수 있다. 클래스 상속을 사용하면 너무 많은 서브클래스들이 만들어 지는 경우 Decorator 패턴이 유용하게 사용된다.

 

기능 확장을 위해 서브클래스를 사용하는 방식은 컴파일시에 결정되는 기능 확장 방식인 반면, Decorator 패턴은 객체를 전달하며 기능을 확장하는 방식으로 런타임시에 동적으로 기능 추가, 확장하게 된다. 서브클래싱 방식은 클래스 상속을 사용하게 되는데 상속으로 구현시, 서브클래스들이 많이 만들어지게 된다. 이경우, 상속 대신 컴퓨지션을 사용하는 Decorator 패턴 방식이 유용하다.

 

아래의 다이어그램은 Decorator와 이의 파생클래스인 DecoratorA와 DecoratorB는 Compoent에 정의된 메서드를 재정의하면서 기능들을 추가, 확장하게 된다.

 

 

Decorator 패턴은 기본적으로 Decoration의 대상이 되는 Component 부분과 Component에 추가적으로 기능을 덧붙이는 Decorator 부분으로 구성된다. Compoenent 부분은 Component 인텊이스와 이를 구현한 ConcreteComponent 클래스로 구성되고, Decorator 부분은 Decorator 인터페이스와 이를 구현한 Concrte Decorator 클래스로 구분된다.

 

아래 예제는 Draw()기능을 확장하는 Decorator 샘플이다. 

프로젝트 생성 시, Winform 프로젝트로 생성한다.

 

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace Decorator_
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }
    }
    class Client
    {
        public static void HowToTest()
        {
            //폼생성
            Form form = new System.Windows.Forms.Form();
            form.Show();
            Graphics gr = form.CreateGraphics();

            // Decorator를 사용해 원안 색칠
            Shape shape = new Circle(new Point(100, 100), 50);
            var deco = new FillShapeDecorator(shape);
            deco.Draw(gr);
        }
    }
    public abstract class Shape
    {
        public abstract void Draw(Graphics g);

        public int X { get; set; }
        public int Y { get; set; }
        public int Width { get; set; }
        public int Height { get; set; }

    }

    // Concrete Compoent
    public class Circle : Shape
    {
        public Circle(Point origin, int radius)
        {
            X = origin.X;
            Y = origin.Y;
            Width = radius * 2;
            Height = radius * 2;
        }

        public override void Draw(Graphics g)
        {
            g.DrawEllipse(Pens.Black, X, Y, Width, Height);
        }
    }

    // Decorator
    public abstract class ShapeDecorator : Shape
    {
        protected Shape component;
        public ShapeDecorator(Shape shape)
        {
            component = shape;
        }
    }

    //Concrete Decorator
    public class FillShapeDecorator : ShapeDecorator
    {
        public FillShapeDecorator(Shape shape) : base(shape) { }
        public override void Draw(Graphics g)
        {
            // 기본 외곽 그리기
            component.Draw(g);

            // Fill 기능 추가 (extra functionality)
            g.FillEllipse(Brushes.Green, component.X, component.Y, component.Width, component.Height);
        }
    }
}

 

도형의 외곽을 그리는 기능 외에 그 안에 색깔을 색칠하는 기능을 Circle 클래스를 손대지 않고 추가하고 싶다면, 파생클래스를 만들거나 C#의 특유 기능인 확장 메서드를 사용할 수 있다. 이러한 방법 외에 Decorator 패턴을 사용할 수 있는데, 이를 위해 FillShapeDecorator란느 Decorator 클래스를 만들어 도형 안에 색을 채우는 기능을 추가했다.

'C# 이것저것 > C# 디자인패턴' 카테고리의 다른 글

[C#] Proxy 패턴  (0) 2024.04.15
[C#] Bridge 패턴  (0) 2024.04.06
[C#] Adapter 패턴  (0) 2024.03.31
[C#] Object Pool 패턴  (0) 2024.03.31