7. 가교 패턴(Bridge Pattern) 구현

가교 패턴 프로젝트 다운로드

7.4 구현

가교 패턴에 대한 예제 프로그램은 Module 파트, Lens 파트, Camera순으로 구현하는 과정을 설명하겠습니다.

7.4.1 Module 파트

Module 파트는 구체적 기능을 구현하는 역할을 담당합니다. 여기에서는 피사체를 목적에 맞게 영상 처리하는 기능을 구현하겠습니다. IImageProcessing은 영상 처리 기능을 약속한 인터페이스입니다. 영상 처리하는 기능은 string 형식의 피사체를 입력 인자로 전달 받아 영상 처리된 결과를 string 형식으로 반환하는 ImageProcessing 메서드입니다.

▶ IImageProcessing.cs

namespace Bridge
{
    interface IImageProcessing
    {
        string ImageProcessing(string subject);
    }
}

IImageProcessing 기반의 VRModule 클래스는 피사체로 넘어온 문자열 인자에 “떨림” 부분 문자열이 있는 부분을 제거하도록 구현하겠습니다.

▶ VRModule.cs

namespace Bridge
{
    class VRModule:IImageProcessing
    {
        public string  ImageProcessing(string subject) //약속한 기능 구현
        {
            return subject.Replace("떨림","");
        }
}

IImageProcessing 기반의 PCModule 클래스는 피사체로 넘어온 문자열 인자에 “0”이라는 부분 문자열이 있는 부분을 “1”로 변경하는 것으로 구현하겠습니다. 이는 예제 프로그램의 피사체와의 상대적 거리입니다. 0은 아주 가까운 곳에 있는 피사체이고 1은 가까운 곳, 2는 중간 위치, 3은 먼 곳에 있는 피사체를 표현할 때 사용할게요. 즉, 아주 가까운 곳에 있는 피사체를 가까운 곳에 있는 피사체로 원근감을 왜곡시키는 기능을 수행할 것입니다.

▶ PCModule.cs

namespace Bridge
{
    class PCModule:IImageProcessing
    {
        public string ImageProcessing(string subject)  //약속한 기능 구현
        {
            return subject.Replace("0", "1");
        }
    }
}


7.4.2 Lens
파트

Lens 파트는 추상적 개념 부분인데 내부에 IImageProcessing 개체를 포함하고 있어 포함하고 있는 개체의 유형에 따라 목적에 맞는 기능을 포함하는 Lens를 만들 수 있게 됩니다. Lens 클래스에서는 카메라에 의해 string 형식으로 피사체와 int 형식으로 거리를 인자로 전달받아 사진을 만드는 기능을 약속한 추상 클래스입니다. 이 기능에 대한 구체적인 구현은 Lens 기반의 파생 클래스인 AFLens와 MFLens에서 합니다. 물론, Lens 파트에서는 피사체를 영상 처리 요청을 받아 내부에 있는 모듈을 이용하여 영상 처리합니다.

Lens 개체의 영상 처리하는 기능은 내부에 포함된 Module 개체를 이용하여 수행합니다. 이처럼 가교 패턴에서는 추상적 부분(렌즈)과 구체적 구현 부분(모듈)을 분리하여 관계를 느슨하게 만들어 줍니다.

▶ Lens.cs

using System.Collections.Generic;
namespace Bridge
{
    abstract class Lens
    {
        const int min_focuslevel=1;
        const int max_focuslevel=3;
        public int FocusLevel
        {
            get;
            private set;
        }
        public int ModuleIndex
        {
            get;
            private set;
        }
        List<IImageProcessing> modules = new List<IImageProcessing>();
        //피사체를 얻어와 영성처리하여 사진으로 변환하는 메서드 약속
        public abstract string Take(string subject, int distance); 
        public int ModuleCount
        {
            get
            {
                return modules.Count;
            }
        } 
        
        public Lens()
        {
            FocusLevel = min_focuslevel;
            ModuleIndex = -1;
        }

        public void AddModule(IImageProcessing module) 
        {
            modules.Add(module); // 실제 영상 처리를 하는 모듈 장착
        }

        //장착된 영상 처리 모듈을 이용하여 영상 처리를 하는 메서드
        protected string ImageProcessing(string subject,int index)
        {
            if((index>=0)&&(index<ModuleCount))
            {
                IImageProcessing module = modules[index];
                subject = module.ImageProcessing(subject);
            }
            return subject;
        }
        public virtual void FocusUp()
        {
            if(FocusLevel < max_focuslevel)
            {
                FocusLevel++;
            }
        }
        public virtual void FocusDown()
        {
            if(FocusLevel > min_focuslevel)
            {
                FocusLevel--;
            }
        }

        protected string MakePicture(string subject,int distance)
        { 
            string s = distance.ToString(); 
            return subject.Replace(s,"선명");
        }
        //영상 처리에 사용할 모듈을 선택하는 메서드
        public void SetModuleIndex(int index)
        {
            if((index >=0 )&&(index<ModuleCount))
            {
                ModuleIndex = index;
            }
        }
    }
}

Lens 클래스를 기반으로 파생된 AFLens 클래스에서는 Take 메서드를 구체적으로 구현해야 합니다. AFLens에서는 영상 처리를 구체적으로 구현하기 위해 자동 초점 조절 기능과 영상 처리 기능을 제공할게요.

▶ AFLens.cs

namespace Bridge
{
    class AFLens:Lens
    {
        public override string Take(string subject, int distance)
        {
            AutoFocusing(distance);
            subject = Processing(subject);
            return MakePicture(subject,distance);
        }

        void AutoFocusing(int distance)
        {
            //먼 거리에 있을 때 줌 레벨을 높인다.
            while (distance > FocusLevel)
            {
                FocusUp();
            }

            //가까운 거리에 있을 때 줌 레벨을 낮춘다.
            while(distance<FocusLevel)
            {
                FocusDown();
            }
        }

        string Processing(string subject)
        {
            int mcount = ModuleCount;

            //내부에 장착된 모듈들을 이용하여 영상 처리
            for(int i =0; i<mcount; i++)
            {
                subject = ImageProcessing(subject,i);
            }
            return subject;
        }
    }
}

Lens 클래스를 기반으로 파생된 MFLens 클래스에서도 Take 메서드를 구체적으로 구현해야 합니다. MFLens에서는 수동으로 초점을 조절하는 기능을 제공할게요.

▶ MFLens.cs

using System;
namespace Bridge
{
    class MFLens:Lens
    {
        public override string Take(string subject, int distance)
        {
            int mindex = ModuleIndex;
            int mcount = ModuleCount;
            if((mindex>=0)&&(mindex<mcount))
            {
                subject = ImageProcessing(subject,mindex);
            }
            return MakePicture(subject, FocusLevel);
        }
        public override void FocusUp()
        {
            base.FocusUp();
            Console.WriteLine("현재 FocusLevel:{0}",FocusLevel);
        }
        public override void FocusDown()
        {
            base.FocusDown();
            Console.WriteLine("현재 FocusLevel:{0}",FocusLevel);
        }
    }
}

7.4.3 Camera

Camera 클래스는 가교 패턴으로 작성된 Lens를 사용하는 부분입니다. 구체적으로 처리하는 Module 부분은 Camera에 노출되지 않고 추상화 부분인 Lens만 노출되지만 실제 목적에 맞는 구체적 구현은 Module에서 수행합니다. Camera 클래스에서는 렌즈를 장착하는 기능과 피사체에 대한 사진을 찍는 기능, 초점 조절하는 기능, 렌즈에 장착된 모듈 개수를 얻어오는 기능, 영상 처리할 모듈을 설정하는 기능을 제공하려고 합니다.

▶ Camera.cs

using System;
namespace Bridge
{
    class Camera
    {
        Lens lens = null;
        public int ModuleCount
        {
            get
            {
                if( lens!=null )
                {
                    return lens.ModuleCount;
                }
                return -1;
            }
        }
        public void SetModuleIndex(int index)
        {
            if(lens!=null)
            {
                lens.SetModuleIndex(index);
            }
        }
        public void PutInLens(Lens lens)
        {
            this.lens = lens;
        }
        public void TakeAPicture(string subject,int distance)
        {
            Console.WriteLine("피사체:{0}",subject);
            string picture = "■";
            if(lens!=null)
            {
               picture = lens.Take(subject,distance);
            }
            Console.WriteLine("사진:{0}",picture); 
        }
        public void FocusUp()
        {
            if(lens!=null)
            {
                lens.FocusUp();
            }
        }
        public void FocusDown()
        {
            if(lens!=null)
            {
                lens.FocusDown();
            }
        }
    }
}

이를 테스트 하는 코드에서는 AFLens에 VRModule을 탑재한 AFVRLens를 카메라에 장착하여 사진을 찍을 수 있을 것입니다. AFLens에 PCModule을 탑재한 AFPCLens를 카메라에 장착할 수도 있습니다. AFLens에 VRModule과 PCModule을 탑재한 AFVRPCLens를 카메라에 장착할 수도 있습니다. 물론, MFLens에 대해서도 마찬가지이며 Camera는 이러한 다양한 종류의 렌즈가 어떠한 모듈을 탑재하였는지 어떠한 종류의 렌즈인지를 알 필요 없이 공통된 인터페이스로 사용할 수 있습니다.

▶ Program.cs

using System;

namespace Bridge
{
    class Program
    {
        static void Main(string[] args)
        {  
            Camera camera = new Camera();
            TestAFVRPCLens(camera);
            TestMFVRLens(camera); 
        }

        static void TestAFVRPCLens(Camera camera)
        {
            Console.WriteLine("AFVRPCLens 테스트");
            VRModule vr = new VRModule();
            PCModule pc = new PCModule();
            Lens lens = new AFLens();
            lens.AddModule(vr);
            lens.AddModule(pc);
            camera.PutInLens(lens);
            camera.TakeAPicture("잎사귀떨림(0) 사람떨림(1) 건물(2) 산(3)", 1);            
        }
        static void TestMFVRLens(Camera camera)
        {
            Console.WriteLine("MFVRLens 테스트");
            IImageProcessing module = new VRModule();
            Lens lens = new MFLens();
            lens.AddModule(module);
            camera.PutInLens(lens);
            camera.TakeAPicture("잎사귀떨림(0) 사람떨림(1) 건물(2) 산(3)", 1);
            camera.FocusUp();
            camera.TakeAPicture("잎사귀떨림(0) 사람떨림(1) 건물(2) 산(3)", 1);
            camera.FocusDown();
            camera.SetModuleIndex(0);
            camera.TakeAPicture("잎사귀떨림(0) 사람떨림(1) 건물(2) 산(3)", 1);            
        }
    }
}

▶ 실행 결과

AFVRPCLens 테스트
피사체:잎사귀떨림(0) 사람떨림(1) 건물(2) 산(3)
사진:잎사귀(선명) 사람(선명) 건물(2) 산(3)
MFVRLens 테스트
피사체:잎사귀떨림(0) 사람떨림(1) 건물(2) 산(3)
사진:잎사귀떨림(0) 사람떨림(선명) 건물(2) 산(3)
현재 FocusLevel:2
피사체:잎사귀떨림(0) 사람떨림(1) 건물(2) 산(3)
사진:잎사귀떨림(0) 사람떨림(1) 건물(선명) 산(3)
현재 FocusLevel:1
피사체:잎사귀떨림(0) 사람떨림(1) 건물(2) 산(3)
사진:잎사귀(0) 사람(선명) 건물(2) 산(3)