6. 적응자 패턴(Adapter Pattern) 구현

적응자 패턴 프로젝트 다운로드

6. 4 구현

6.4.1 첫 번째 프로그램(적응자 패턴을 적용하기 전에 사용하던 프로그램)

첫 번째 프로그램은 적응자 패턴을 사용하기 전에 사용`했던 프로그램을 작성하는 것입니다. 카메라와 사람에 대한 영상 처리를 하는 형식으로 구성된 프로그램을 만들기로 약속했었죠. 먼저, 사람에 대한 영상 처리를 하는 형식에는 피사체를 설정하는 기능과 영상 처리를 시작하는 기능, 사진을 얻어오는 기능을 제공하기로 하였습니다.

▶PImageProcessor.cs

namespace BeforeAdapter
{
    class PImageProcessor
    {
        public string Subject
        {
            get;
            set;
        }
        public string Picture
        {
            get;
            private set;
        }

        public PImageProcessor()
        {
            Subject = string.Empty;
            Picture = string.Empty;
        }

        public void ImageProcessing()
        {
            Picture = Subject.Replace("people","PEOPLE");
        }
    }
}

카메라에서는 사진을 찍는 기능을 제공할게요.

▶Camera.cs

namespace BeforeAdapter
{
    class Camera
    {
        PImageProcessor pi_processor;

        public Camera(PImageProcessor pi_processor)
        {
            this.pi_processor = pi_processor;
        }

        public string TakeAPicture(string subject)
        {
            pi_processor.Subject = subject;
            pi_processor.ImageProcessing();
            return pi_processor.Picture;
        }
    }
}

테스트 코드에서는 여러 종류로 구성된 피사체를 문자열 형태로 주어 얻어온 사진에 해당하는 문자열을 화면에 출력해 보는 형태로 하겠습니다.

▶Program.cs

using System;

namespace BeforeAdapter
{
    class Program
    {
        static void Main(string[] args)
        {
            PImageProcessor pi_processor = new PImageProcessor();
            Camera ca = new Camera(pi_processor);
            string picture = ca.TakeAPicture("people animal people plant");
            Console.WriteLine(picture);
        }
    }
}

▶실행 결과

PEOPLE animal PEOPLE plant

6.4.2 두 번째 프로그램 (적응자 패턴을 사용한 프로그램)

두 번째 프로그램은 첫 번째 프로그램에 사용했던 것과 동일한 역할을 하는 카메라와 사람에 대한 영상 처리하는 형식이 제공이 됩니다. 그리고, 사람에 대한 영상 처리를 하는 형식에 노출된 메서드와 시그니쳐가 동일한 인터페이스를 제공해야겠지요. 그리고, 사람에 대한 영상 처리를 하는 형식도 인터페이스를 구현 약속하는 클래스로 정의를 할께요. 그리고, 동물에 대한 영상 처리를 하는 형식과 이를 래핑하는 클래스를 제공합시다. 래핑하는 클래스는 인터페이스를 구현 약속합니다. 이와 같이 설계를 하면 두 개의 모듈을 동일한 방식으로 사용할 수 있게 되면 사용하는 곳에서는 구체화 된 모듈 형식과의 관계가 느슨하게 되어 유연성이 높아집니다.

두 번째 프로그램은 첫 번째 프로그램에 사용했던 것과 같은 역할을 하는 카메라와 사람에 대한 영상 처리하는 형식이 제공됩니다. 그리고 영상 처리를 담당하는 인터페이스를 제공할게요. 인터페이스에는 사람에 대한 영상 처리를 하는 클래스에 노출된 메서드와 시그니쳐가 같은 멤버를 약속하면 됩니다. 그리고 사람에 대한 영상 처리를 하는 형식도 인터페이스 기반의 클래스로 바꿀게요. 그리고 동물에 대한 영상 처리를 하는 형식과 이를 감싸는 클래스를 제공합시다. 이 클래스는 인터페이스를 기반으로 정의를 하고 약속된 기능에 대한 구현은 감싸고 있는 개체를 이용하면 되겠죠. 이처럼 설계하면 같은 방식으로 두 개의 모듈을 사용할 수 있으며 사용하는 곳에서는 파생 클래스 형식과 관계가 느슨해져서 유연성이 높아집니다.

구현 순서는 동물에 대한 영상 처리를 하는 형식, 래핑된 형식과 영상 처리에 대한 추상 클래스를 먼저 작성할 것입니다. 그리고 사람에 대한 영상 처리 형식과 카메라 형식을 변경하려고 합니다.

 – 동물에 대한 영상 처리를 하는 형식

동물에 대한 영상 처리를 하는 형식은 AImageProcessor 이름의 클래스로 정의합시다. 제공되는 메서드는 원본 이미지를 설정하고 얻어오는 속성, 이미지를 얻어오는 속성 및 원본을 변환하는 메서드를 제공할게요.

▶AImageProcessor.cs

namespace Adapter
{
    class AImageProcessor
    {
        public string Image
        {
            get;
            set;
        }
        public string Picture
        {
            get;
            private set;
        }
        public AImageProcessor()
        {
            Image = string.Empty;
            Picture = string.Empty;
        }
        public void Processing()
        {
            Picture = Image.Replace("animal","ANIMAL");
        }
    }
}


래핑한 형식과 영상 처리에 대한 인터페이스

이번에는 영상 처리에 대한 인터페이스와 이를 기반으로 래퍼 클래스를 만들어 봅시다. 래퍼 클래스는 내부에 동물에 대한 영상 처리를 하는 형식 개체를 포함하게 만들게요. 일반적으로 래퍼 클래스 형식 개체를 적응자(Adapter) 개체라 부르며 내부에 감싸져 있는 개체를 적응 대상(Adaptee) 개체라 부릅니다.

영상 처리에 대한 인터페이스는 IImageProcessing으로 정하고 기존에 사용했던 사람에 대한 영상 처리를 하는 형식에서 노출하는 멤버들과 같은 이름의 멤버들을 약속할게요.

동물에 대한 영상 처리를 하는 개체를 감싸는 클래스는 IImageProcssing을 기반으로 정의하며 인터페이스에 약속한 기능은 감싸고 있는 개체를 이용하여 구현하면 됩니다.

▶IImageProcessing.cs

namespace Adapter
{
    interface IImageProcessing
    {
        string Subject
        {
            get;
            set;
        }
        string Picture
        {
            get;
        }
        void ImageProcessing();
    }
}

▶ WrapAImageProcessor.cs

namespace Adapter
{
    class WrapAImageProcessor:IImageProcessing
    {
        AImageProcessor ai_processor = new AImageProcessor();// 영상 처리하는 실개체

        public string  Subject //약속한 속성에 대한 구현
        {
            get 
            { 
                return ai_processor.Image; //감싸고 있는 개체를 이용함
            }
            set 
            { 
                ai_processor.Image = value; //감싸고 있는 개체를 이용함
            }
        }
        public string  Picture//약속한 속성에 대한 구현
        {
            get
            { 
                return ai_processor.Picture; //감싸고 있는 개체를 이용함
            }
        }
        public void ImageProcessing()//약속한 메서드 구현
        {
            ai_processor.Processing(); //감싸고 있는 개체를 이용함
        }
    }
}


사람에 대한 영상 처리 형식과 카메라 형식 변경

사람에 대한 영상 처리를 하는 형식인 PImageProcessor 의 구체적 구현은 바뀌지 않습니다. 단지 인터페이스 IImageProcessing를 기반의 클래스로 변경할게요.

▶ PImageProcessor.cs

namespace Adapter
{
    class PImageProcessor:IImageProcessing //인터페이스 기반의 클래스로 변경
    {
        public PImageProcessor()
        {
            Subject = string.Empty;
            Picture = string.Empty;
        }
        public string Subject
        {
            get;
            set;
        }
        public string Picture
        {
            get;
            private set;
        }
        public void ImageProcessing()
        {
            Picture = Subject.Replace("people", "PEOPLE");
        }
    }
}

카메라에는 펌웨어를 업그레이드하는 기능을 추가하려고 합니다. 물론, 기존 카메라의 멤버 필드로 있었던 사람에 대한 영상 처리를 담당하는 형식을 영상 처리를 담당하는 인터페이스 형식으로 변경해야겠지요.

▶ Camera.cs

namespace Adapter
{
    class Camera
    {
        IImageProcessing img_processor;

        public Camera(IImageProcessing img_processor)
        {
            this.img_processor = img_processor;
        }

        public string TakeAPicture(string subject)
        {
            img_processor.Subject = subject;
            img_processor.ImageProcessing();
            return img_processor.Picture;
        }

        public void UpgradeFirmWare(IImageProcessing img_processor)
        {
            this.img_processor = img_processor;
        }
    }
}

테스트를 위한 코드에서는 사람에 대한 이미지 처리를 담당하는 개체가 탑재된 카메라로 피사체를 찍는 것과 래핑된 개체로 업그레이드된 카메라로 피사체를 찍은 결과를 화면에 출력하는 것으로 하겠습니다.

▶ Program.cs

using System;
namespace Adapter
{
    class Program
    {
        static void Main(string[] args)
        {
            IImageProcessing[] ips = new IImageProcessing[2];
            ips[0] = new PImageProcessor();
            ips[1] = new WrapAImageProcessor();
            
            Camera ca = new Camera(ips[0]);
            string picture = ca.TakeAPicture("people animal people plant");
            Console.WriteLine(picture);
            ca.UpgradeFirmWare(ips[1]);
            picture = ca.TakeAPicture("people animal people plant");
            Console.WriteLine(picture);
        }
    }
}

▶ Program.cs

PEOPLE animal PEOPLE plant
people ANIMAL people plant