컴퓨터/정보처리기사 SW 공학

| 니앙팽이 - 객체지향(OOP) | 4-4 | 구조패턴 - Decorator pattern

객체지향

📕 4. 객체지향 디자인 패턴

유니티에서 사용하면 좋을 디자인 패턴만 명시한다.


📄 4. 구조 패턴

클래스나 객체를 조합하여 더 큰구조로 만드는 패턴


2). Decorator Patterns

ⓐ 특징

  1. 객체의 기본 기능에 추가 기능을 덧붙여 결합 & 장착할 수 있다.


1. 다수의 옷이 가진 각각의 효과를 결합 할 수 있다.

  1. 즉 객체를 런타임 동안 동적으로 변화시킬수 있다.

ⓑ 왜 쓰는가?

  • 기능 확장성
    • 기존 코드를 수정하지 않고도 데코레이터 패턴을 통해 행동을 확장할수 있다.
  • 동적 확장성
    • 구성과 위임을 통해서 실행중에 새로운 행동을 추가할 수 있습니다.

ⓒ 구성요소

  1. Component
    • 인터페이스 또는 추상클래스가 된다.
    • 기본 기능을 정의한다.
  2. ConcreteComponent
    • 기본 기능이 되는 인스턴스가 된다. 데코가 붙을 대상
    • Component를 상속한다.
  3. Decorator
    • 데코가 붙을 대상을 포함한다.
    • ConcreteDecorator의 form을 제공함 ConcreteDecorator가 생긴다면 다 Decorator와 비슷하게 생김
    • 추상클래스다
  4. ConcreteDecorator
    • 객체에 ConcreteDecorator기능을 추가하고싶을때
      ConcreteDecorator 생성자에 객체를 넣는다 그럼 행동이 추가된다.

ⓓ 단점

  • 데코레이터를 너무 많이 사용하면 코드가 필요 이상으로 복잡해 질 수 도 있다.

ⓔ 예시

  • 클라이언트가 데코레이터를 붙이는 방법
    /* Client.cs */
    Component component = new ConcreteComponent();
    
    component = new ConcreteDecorator1(...);
    component = new ConcreteDecorator2(...);
    
📂Decorator Pattern (C#)📂
using System;
using System.Collections;
using System.Net.NetworkInformation;
using System.Runtime.CompilerServices;
using System.Text;

namespace DesignPattern
{
    public abstract class Item
    {
        public abstract int GetLineCount();
        public abstract int GetMaxLength();
        public abstract int GetLength(int i);
        public abstract String GetString(int _i);
        public virtual void PrintString()
        {
            int lineNum = GetLineCount();
            for (int i = 0; i < lineNum; i++)
            {
                String str = GetString(i);
                Console.WriteLine(str);
            }
        }
    }
    public class Strings : Item
    {
        private List<String> strings = new List<String>();

        public void add(String _str)
        {
            strings.Add(_str);
        }
        public override int GetLineCount()
        {
            return strings.Count();
        }
        public override int GetMaxLength()
        {
            int maxLen = 0;
            foreach (String E in strings)
            {
                maxLen = maxLen < E.Length ? E.Length : maxLen;
            }
            return maxLen;
        }
        public override int GetLength(int i)
        {
            return strings[i].Length;
        }
        public override String GetString(int i)
        {
            return strings[i];
        }
    }
    public abstract class Decorator : Item
    {
        protected Item item;
        public Decorator(Item item)
        {
            this.item = item;
        }
    }
    public class SideDecorator : Decorator
    {
        private readonly Char decoChar = ' ';
        public SideDecorator(Item item, Char _c) : base(item)
        {
            decoChar = _c;
        }
        public override int GetLineCount()
        {
            return item.GetLineCount();
        }
        public override int GetMaxLength()
        {
            return item.GetMaxLength() + 2;
        }
        public override int GetLength(int i)
        {
            return item.GetLength(i) + 2;
        }
        public override String GetString(int i)
        {
            return decoChar + item.GetString(i) + decoChar;
        }
    }
    public class BoxDecorator : Decorator
    {

        public BoxDecorator(Item item) : base(item) { }
        public override int GetLineCount()
        {
            return item.GetLineCount() + 2;
        }
        public override int GetMaxLength()
        {
            return item.GetMaxLength() + 2;
        }
        public override int GetLength(int i)
        {
            return item.GetLength(i) + 2;
        }
        public override String GetString(int i)
        {
            int maxLen = GetLineCount();
            if (i == 0 || i == maxLen - 1) { return MakeBorder(); }
            return $"|{MakeTailString(item.GetString(i - 1))}|";
        }
        String MakeBorder()
        {
            int maxLen = GetMaxLength();
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < maxLen; i++)
            {
                if (i == 0 || i == maxLen - 1) { sb.Append('+'); continue; }
                sb.Append('-');
            }
            return sb.ToString();
        }
        string MakeTailString(string _target)
        {
            int maxLen = item.GetMaxLength();
            int spaceLen = maxLen - _target.Length;
            for (int i = 0; i < spaceLen; i++) { _target += ' '; }
            return _target;
        }
    }
    public class LineNumberDecorator : Decorator
    {

        public LineNumberDecorator(Item item) : base(item) { }
        public override int GetLineCount()
        {
            return item.GetLineCount();
        }
        public override int GetMaxLength()
        {
            return item.GetMaxLength() + 4;
        }
        public override int GetLength(int i)
        {
            return item.GetLength(i) + 4;
        }
        public override String GetString(int i)
        {
            return $"{String.Format("{0,2:D2}", i)} :{item.GetString(i)}";
        }
    }

    static void Main(string[] argv)
    {
        Strings strings = new Strings();
        strings.add("Hello~");
        strings.add("My name is escatrgot");
        strings.add("I am a Game and Web Developer");
        strings.add("Right now im learning DesignPattern !!");
        strings.PrintString();
        Item decorator = new SideDecorator(strings, '/');
        decorator = new BoxDecorator(decorator);
        decorator = new LineNumberDecorator(decorator);
        decorator = new BoxDecorator(decorator);
        decorator = new LineNumberDecorator(decorator);
        decorator.PrintString();
    }
}
📂Decorator Pattern 2(C#)📂
using System;
using System.Collections;
using System.Collections.Generic;

namespace DesignPattern
{
    internal class Decorator {
        interface Attackable {
            public void Attack();
        } 

        public class Player : Attackable {
            public void Attack(){
                Console.WriteLine("평타");                
            }            
        } 

        public abstract class Decorator : Attackable {
            protected Attackable attackable;
            public Decorator(Attackable attackable){
                this.attackable = attackable;
            }
        }

        public class Laser : Decorator {
            public override void Attack(){
                attackable.Attack();
                Console.WriteLine("찌유유유웅");       
            }
        }

        public class Knife : Decorator {
            public override void Attack(){
                attackable.Attack();
                Console.WriteLine("슉 슈슈슉 ㅅ벌럼아 칼협 칼협");       
            }
        }

        public class Screem : Decorator {
            
            public override void Attack(){
                attackable.Attack();
                Console.WriteLine("喝!!!!!!!!!!!!!!!!!!!!!!!!");
            }
        }
        
        static void Main(string[] argv){
            Player player = new Player();
            player.Attack();

            Attackable decorator = new Laser(player);
            decorator.Attack();
            decorator = new Knife(decorator);
            decorator.Attack();
            decorator = new Laser(decorator);
            decorator = new Screem(decorator);
            decorator.Attack();
        }
    }
}
📂Decorator Pattern 3(C#)📂
namespace DesignPattern
{
    public interface Component
    {
        public String add();
    }

    public class 에스프레소 : Component {
        String name = "에스프레소";
        public String add() {
            return name;
        }
    }

    public abstract class CoffeeDecorator : Component{
        protected readonly Component coffeeComponent;
        public CoffeeDecorator(Component component){
            this.coffeeComponent = component;
        }
        public virtual String add()
        {
            return coffeeComponent.add();
        }
    }
    public class 물데코레이터 : CoffeeDecorator
    {
        public 물데코레이터(Component component) : base(component) { }
        public override String add() { return $"{coffeeComponent.add()} + 물"; }
    }
    public class 우유데코레이터 : CoffeeDecorator {
        public 우유데코레이터(Component component) : base(component){}
        public override String add() { return $"{coffeeComponent.add()} + 우유"; }
    }
    public class 얼음데코레이터 : CoffeeDecorator
    {
        public 얼음데코레이터(Component component) : base(component) { }
        public override String add() { return $"{coffeeComponent.add()} + 얼음"; }
    }
    public class 휘핑크림데코레이터 : CoffeeDecorator
    {
        public 휘핑크림데코레이터(Component component) : base(component) { }
        public override String add() { return $"{coffeeComponent.add()} + 휘핑크림"; }
    }
    public class 자바칩데코레이터 : CoffeeDecorator
    {
        public 자바칩데코레이터(Component component) : base(component) { }
        public override String add() { return $"{coffeeComponent.add()} + 자바칩"; }
    }
    static void Main(string[] argv)
    {
        Component espresso = new 에스프레소();
        Console.WriteLine($"espresso : {espresso.add()}");
        Component americano = new 물데코레이터(espresso);
        Console.WriteLine($"americano : {americano.add()}");
        Console.WriteLine($"espresso : {espresso.add()}");
        Component latte = new 우유데코레이터(new 에스프레소());
        Console.WriteLine($"latte : {latte.add()}");

        Component 자바칩프라푸치노 = new 자바칩데코레이터(new 휘핑크림데코레이터(new 얼음데코레이터(latte)));
        Console.WriteLine($"자바칩프라푸치노 : {자바칩프라푸치노.add()}");
    }
}