이번 시간에는 Stream / Decorator / Adapter / MISC에 대해 알아보겠습니다.

Stream Decorator

Decorator 디자인 패턴 : “원래 기능에 새로운 기능을 추가”

  • 상속 vs 포함을 사용한 기능 추가
    • 상속 : 클래스에 기능 추가 / 정적인 기능 추가
    • 포함 : 인스턴스에 기능 추가 / 동적인 기능 추가
using System;

interface Base // Decorator(기능 추가 객체)
{
    void Fire();
}

class Fighter : Base
{
    public virtual void Fire()
    {
        Console.WriteLine("Fire Missile");
    }
}

class RightMissile : Base
{
    private Base fighter = null;

    public RightMissile(Base fg) { fighter = fg; }

    public void Fire()
    {
        fighter.Fire(); // 기존 객체의 기능 사용
        Console.WriteLine("Fire Right Missile");
    }
}

class LeftMissile : Base
{
    private Base fighter = null;

    public LeftMissile(Base fg) { fighter = fg; }

    public void Fire()
    {
        fighter.Fire(); 
        Console.WriteLine("Fire Left Missile");
    }
}

class Program
{
    public static void Main()
    {
        Fighter fg = new Fighter();
        fg.Fire();

        // 아이템 획득
        RightMissile fg2 = new RightMissile(fg);
        fg2.Fire();

        LeftMissile fg3 = new LeftMissile(fg2);
        fg3.Fire();
    }
}

c# stream에서 decorator 패턴 사용 예제

using System;
using System.IO;
using System.IO.Compression;
using System.Net;

class Program
{
    public static void Main()
    {
        byte[] buff = new byte[1024 * 1024]; // 1M

        FileStream fs = new FileStream("d:\\a.dat", FileMode.Create);

        GZipStream gs = new GZipStream(fs, CompressionLevel.Fastest);

        BufferedStream bs = new BufferedStream(gs);

        //fs.Write(buff, 0, buff.Length);
        bs.Write(buff, 0, buff.Length);
        bs.Close();
        gs.Close();
        fs.Close();
    }
}

Stream Adapter

Adapter 패턴 : 기존 클래스의 인터페이스를 변경(래핑 클래스)

using System;
using System.Collections.Generic;

class Stack 
{
    public List<int> st = null; 
    public Stack(List<int> s) { st = s; }
    
    public void Push(int a) { st.Add(a);  }
    public int  Pop()
    {
        int n = st.Count - 1;
        int temp = st[n];
        st.RemoveAt(n);
        return temp;
    }
}

class Program
{
    public static void Main()
    {
        List<int> st = new List<int>();

        st.Add(10);
        st.Add(20);

        // st를 stack 처럼 사용하고 싶다.
        Stack s = new Stack(st);

        s.Push(30);
        s.Push(40);

        int n = s.Pop(); // 40
        Console.WriteLine(n);   
    }
}

c# stream에서 adapter 패턴 사용 예제

using System;
using System.IO;
using System.IO.Compression;
using System.Text;

class Program
{
    public static void Main()
    {
        Console.WriteLine("Hello");

        FileStream fs = new FileStream("D:\\a.txt", FileMode.Create);

        // "Hello" 를 파일에 쓰고 싶다. 아래처럼 하면 불편
        //string s = "hello";
        //byte[] buff = Encoding.ASCII.GetBytes(s);
        //fs.Write(buff, 0, buff.Length);

        // 편안
        StreamWriter sw = new StreamWriter(fs, Encoding.ASCII);
        sw.WriteLine("Hello");

       // GZipStream gz = new GZipStream(fs);
       // gz.Write()

        sw.Close();
        fs.Close();
    }
}

MISC

DLR(dynamic language runtime) : 실행시간에 각종 처리 가능

  • 잘못된 형 변환 발생시 런타임 예외 발생
using System;

class Car
{
    public void Go() { Console.WriteLine("Car Go"); }
}
class Program
{    
    public static void Main()
    {
        object o = new Car();
        //o.Go();     //+ compile error
        //o.Stop();   //+ compile error

        dynamic d = new Car();
        d.Go();     //+ ok.
        d.Stop();   //+ 예외 발생

        var v = new Car(); // 컴파일 시간에 v의 타입 결정. Car v = Car()
        v.Go();     //+ ok
        //v.Stop();   //+ compile error
    }
}
  • 활용 : multiple dispatch 문제 해결
using System;

abstract class Character
{
    public abstract void Fight(A a);
    public abstract void Fight(B a);
}

class A : Character
{
    public override void Fight(A a) { Console.WriteLine("A Fight With A"); }
    public override void Fight(B b) { Console.WriteLine("A Fight With B"); }
}

class B : Character
{
    public override void Fight(A a) { Console.WriteLine("B Fight With A"); }
    public override void Fight(B b) { Console.WriteLine("B Fight With B"); }
}

class Program
{
    public static void DoFight(Character c1, dynamic c2)
    {
        c1.Fight(c2);
    }
    public static void Main()
    {
        A a = new A();
        B b = new B();
        DoFight(a, a);
        DoFight(a, b);
        DoFight(b, a);
        DoFight(b, b);
    }
}