1. 추상 팩토리 패턴 (Abstract Factory Pattern) 구현

추상 팩토리 패턴 프로젝트 파일 다운로드

1.4 구현

 이제 구체적으로 구현해 봅시다. 먼저, 카메라와 렌즈를 구현하고 팩토리 부분을 구현한 후에 마지막으로 테스터를 구현합시다.

1.4.1 렌즈

렌즈의 기능은 ITake 인터페이스로 정의하고 상을 맺히는 기능을 약속합시다. EvLens와 HoLens는 ITake를 기반으로 상을 맺히는 기능을 구체적으로 구현합시다. 이처럼 인터페이스를 정의하고 이를 기반으로 구현하면 표준화된 인터페이스를 사용할 수 있어서 사용방법을 익히는 비용을 줄일 수 있습니다.

▶ITake.cs

namespace AbstractFactory
{
    interface ITake //렌즈의 기능에 대한 추상적 약속
    {
        void Take();//상을 맺히는 기능에 대한 약속
    }
}

EvLens는 ITake에 약속한 Take 메서드를 구현해야 합니다. 그리고 EvLens에는 자동 초점을 맞춰주는 기능을 별도로 제공할게요.

▶EvLens.cs

using System;
namespace AbstractFactory
{
    class EvLens:ITake
    {
        public void Take() //ITake에 약속된 기능을 구체적으로 구현
        {
            Console.WriteLine("부드럽다.");
        }
        public void AutoFocus()
        {
            Console.WriteLine("자동 초점 조절하다.");
        }
    }
}

HoLens도 ITake에 약속한 Take 메서드를 구현해야 합니다. 그리고 HoLens에는 사용자가 수동으로 초점을 맞추는 기능을 제공할게요.

▶HoLens.cs

using System;
namespace AbstractFactory
{
    class HoLens:ITake
    {
        public void Take() //ITake에 약속된 기능을 구체적으로 구현
        {
            Console.WriteLine("자연스럽다.");
        }
        public void ManualFocus()
        {
            Console.WriteLine("사용자의 명령대로 초점을 잡다.");
        }
    }
}

1.4.2 카메라

카메라에는 추상 클래스 Camera와 파생 클래스 EvCamera, HoCamera가 있습니다. 그리고 추상 클래스인 Camera는 사진을 찍는 메서드를 TakeAPicture 이름으로 제공할게요. 카메라의 사진을 찍는 기능은 공통으로 렌즈에 상을 맺히는 부분이 있지만, 세부적인 사항은 카메라의 종류에 따라 다를 수 있어서 가상 메서드로 구현할게요. 그리고 카메라는 렌즈를 장착하는 기능이 필요한데 카메라 종류에 따라 호환성 있는 렌즈가 다르므로 추상 메서드로 약속하고 구체적 기능은 파생된 카메라에서 구현할게요.

▶Camera.cs

namespace AbstractFactory
{
    abstract class Camera
    {
        protected ITake Lens
        {
            get;
            set;
        }
        public virtual bool TakeAPicture()  //사진을 찍는 가상 메서드
        {
            if (Lens == null)
            {
                return false;
            }
            Lens.Take(); //렌즈에 상을 맺힌다.
            return true;
        }
        //호환성 있는 렌즈를 장착하는 메서드 - 구체적 구현은 파생 클래스에서
        public abstract bool PutInLens(ITake itake);
        public ITake GetOutLens()
        {
            ITake re = Lens;
            Lens = null;
            return re;
        }
        public Camera()
        {
            Lens = null;
        }
    }
}

EvCamera에서는 사진을 찍는 가상 메서드에 대해 재정의를 하고 렌즈를 장착하는 추상 메서드를 구체적으로 구현해야 합니다. 사진을 찍는 메서드에서는 자동으로 초점을 맞추고 상을 렌즈에 맺히면 되겠죠.

▶EvCamera.cs

namespace AbstractFactory
{
    class EvCamera:Camera
    {
        //호환성 있는 렌즈를 장착하는 기능에 대한 구체적 구현
        public override bool PutInLens(ITake itake) 
        {
            EvLens evlens = itake as EvLens; //호환성 있는 Ev 렌즈 형식으로 참조 연산
            if (evlens == null) //호환성 없는 렌즈일 때
            {
                return false;
            }
            Lens = itake; //호환성 있는 렌즈일 때 장착
            return true;
        }

        public override bool TakeAPicture()
        {
            EvLens evlens = Lens as EvLens;
            if (evlens == null)
            {
                return false;
            }
            evlens.AutoFocus();
            return base.TakeAPicture();
        }
    }
}

마찬가지로 HoCamera에서도 사진을 찍는 메서드를 재정의하고 렌즈를 장착하는 메서드를 구체적으로 구현해야 합니다.

▶HoCamera.cs

namespace AbstractFactory
{
    class HoCamera:Camera
    {
        // 호환성 있는 렌즈를 장착하는 기능에 대한 구체적 구현
        public override bool PutInLens(ITake itake)
        {
            HoLens holens = itake as HoLens; //호환성 있는 Ho 렌즈 형식으로 참조 연산

            if (holens == null) // 호환성 없을 때
            {
                return false;
            } 
            Lens = itake; //호환성 있는 렌즈일 때 장착
            return true;
        }
        public override bool TakeAPicture()
        {
            HoLens holens = Lens as HoLens;
            if (holens == null)
            {
                return false;
            }
            holens.ManualFocus();
            return base.TakeAPicture();
        }
    }
}

1.4.4 팩토리

팩토리에는 카메라와 렌즈를 생산하는 기능을 약속하는 IMakeCamera 인터페이스를 정의할게요. 그리고 IMakeCamera를 기반으로 EvDayFactory, HoDayFactory 클래스가 정의할게요. 이들 클래스에서는 IMakeCamera에서 약속한 기능을 구현해야 합니다.

▶IMakeCamera.cs

namespace AbstractFactory
{
    interface IMakeCamera // 호환성 있는 렌즈와 카메라를 생성하는 기능에 대한 약속
    {
        ITake MakeLens();
        Camera MakeCamera();
    }
}

▶EvDayFactory.cs

namespace AbstractFactory
{
    class EvDayFactory:IMakeCamera //Ev 렌즈와 Ev 카메라 생성하는 클래스
    {
        public ITake MakeLens() //호환성 있는 EvLens를 생성하는 기능 구현
        {
            return new EvLens();
        }
        public Camera MakeCamera() //호환성 있는 EvCamera를 생성하는 기능 구현
        {
            return new EvCamera();
        }
    }
}

▶HoDayFactory.cs

namespace AbstractFactory
{
    class HoDayFactory:IMakeCamera //Ho 렌즈와 Ho 카메라 생성하는 클래스
    {
        public ITake MakeLens() //호환성 있는 EvLens를 생성하는 기능 구현
        {
            return new HoLens();
        }
        public Camera MakeCamera() //호환성 있는 EvCamera를 생성하는 기능 구현
        {
            return new HoCamera();
        }
    }
}

1.4.5 테스터

테스터에서는 직접 카메라와 렌즈를 생성하여 호환성 테스트하는 것과 팩토리 개체를 통해 생성하여 호환성 테스트하는 것을 보여줍시다.

▶Tester.cs

using System;
namespace AbstractFactory
{
    class Tester
    {
        IMakeCamera[] factories = new IMakeCamera[2];
        public Tester()
        {
            factories[0] = new EvDayFactory();
            factories[1] = new HoDayFactory();
        }
        //카메라와 렌즈의 호환성 테스트
        private void TestCase(Camera camera, ITake lens)
        {
            Console.WriteLine("테스트");
            if (camera.PutInLens(lens) == false)
            {
                Console.WriteLine("카메라에 렌즈가 장착이 되지 않았음");
            }
            if (camera.TakeAPicture() == false)
            {
                Console.WriteLine("사진이 찍히지 않았습니다.");
            }
        }

        public void Test()
        {
            TestDirect();//직접 카메라와 렌즈를 생성하여 호환성 테스트
            TestUsingFactory();//팩토리를 통해 생성하여 호환성 테스트
        }
        private void TestUsingFactory()
        {
            Camera camera = null;
            ITake lens = null;
            foreach (IMakeCamera factory in factories)
            {
                camera = factory.MakeCamera();
                lens = factory.MakeLens();
                TestCase(camera, lens); //호환성 테스트
            }
        }
        private void TestDirect()
        {
            Camera camera = new EvCamera();
            ITake lens = new HoLens();
            TestCase(camera,lens); // 호환성 테스트
        }
    }
}

▶Program.cs

namespace AbstractFactory
{
    class Program
    {
        static void Main(string[] args)
        {
            Tester tester = new Tester();
            tester.Test();
        }
    }
}

▶실행 결과

테스트
카메라에 렌즈가 장착이 되지 않았음
사진이 찍히지 않았습니다.
테스트
자동 초점 조절하다.
부드럽다.
테스트
사용자의 명령대로 초점을 잡다.
자연스럽다.