알맞은 조건에 맞는 객체만을 생성해서 사용하는 방법에는 어떤 것이 있을까?

문제
해당 장비에 맞는 제어 프로그램을 만들어야 한다. 이 제어 프로그램에는 데이터를 송/수신 하는 부분과 송수신된 데이터를 파싱(parsing)하는 부분, 그리고 파싱된 데이터를 처리하는 부분으로 나뉜다. 현재에는 A장비와, B장비만 제어한다. 하지만 추후에 제어 되는 장비가 더 추가되거나 제거될 수 가 있다.
DataSender : 데이터를 송신하는 객체
DataReceiver : 데이터를 수신하는 객체
DataParser : 데이터를 파싱하는 객체
DataProc : 파싱된 데이터를 처리하는 객체  


해결1
프로그램 곳곳에 조건 비교 문장을 넣어 조건에 해당하는 객체를 생성한다(조건 비교 방식).

if(A장비인가?)
{
EquipADataSender eaSender = new EquipADataSender();
EquipADataReceiver eaReceiver = new EquipADataReceiver();
EquipADataParser eaParser = EquipADataParser();
EquipADataProc eaProc = EquipADataProc();
}
else if(B 장비인가?)
{
EquipBDataSender ebSender = new EquipBDataSender ();
EquipBDataReceiver ebReceiver = new EquipBDataReceiver ();
EquipBDataParser ebParser = EquipBDataParser ();
EquipBDataProc ebProc = EquipBDataProc ();
}
// 장비 C , 장비 B 가 추가 된다면? 계속해서 조건 문을 이어 나가야 한다.
// 또한 소스 코드 여러 부분에 걸쳐 이런 조건 문을 사용할 가능성이 매우 높다. 

 해결1에 대한 문제점
프로그램 곳곳에 조건 비교 문장이 존재하기 때문에, 새로운 조건을 추가할 일이 발생하면 프로그램 전체를 찾아 다니며 일일이 수정해야 하는 커다란 문제가 생긴다. 이는 곧 프로그램 전체를 다시 개발하는 것과 비슷한 노력이나 비용이 들 수 있음을 의미한다. 프로그램 전체를 찾아 다니며 비교 문장이 존재하는 곳을 모두 수정해야 할 것이다. 조건 비교 방식의 가장 큰 단점은 비교 문장이 프로그램 전역에 퍼져 있을 경우, 이에 대한 변경 비용이 많이 든다는 것이다. 문제의 원인은 변경될 가능성이 높은 코드(공통된 기능을 하는 코드)들이 프로그램 전역 곳곳에 퍼져 있다는 것이다. 이 문제를 해결하기 위해서는 변경될 가능성이 높은 코드들을 한 곳에 모아, 변경이 필요할 경우 그 부분만 고치면 원하는 작업을 수행할 수 있게 만들어 주는 것이다. 이처럼 객체 지향 설계의 핵심적인 접근 방법은 바로 변경이 예상되는 부분을 한 곳에 모아 관리 하도록 하는 것이다. 


해결2(Factory Pattern)
 프로그램 전역에 조건 비교 문장 없이 원하는 객체를 생성하기 위해서는 객체 생성을 전담하는 클래스(Factory class)를 활용하면 된다. 이는 시스템 환경에 따른 조건 비교 문장이 Factory 클래스 내부에만 존재하기 때문에 새로운 조건이 추가되거나 이전 조건을 변경시켜야 할 경우 프로그램 전체를 찾아 다니며 수정 해야 하는 부담을 덜 수 있다. 이렇게 객체 생성을 Factory class를 활용하는 방식을 Factory Pattern이라고 한다.





샘플 소스 (C#)

        static void Main(string[] args)
        {
            EquipFactory equipFactory = new EquipFactory();  // 팩토리 클래스 생성
            equipFactory.EEquipType = EEquipType.EquipA;   // 장비 선택

// Factory에서 해당 객체 생성
// 장비 종류에 관계 없이 동일한 방법으로 생성한다.

IDataSender sender = equipFactory.CreateDataSender();
            IDataReceiver receiver = equipFactory.CreateDataReceiver();
            IDataParser parser = equipFactory.CreateDataParser();
            IDataProc proc = equipFactory.CreateDataProc();

sender.Send();
            receiver.Receive();
            parser.Parse();
            proc.Proc();
        }

Visual Studio 2008, C#

해결2에 대한 문제점
 여전히 Factory 클래스 내의 소스코드에는 비교 문장이 존재한다는 것이다. 새로운 조건을 추가할 경우 이전 소스 코드를 면밀히 분석해서 수정해야 한다. 이는 새로운 조건의 추가를 이전 소스 코드와 무관하게 독립적으로 수행할 수 없다는 의미이다(이
전 소스 코드와 독립적으로 새로운 부분을 추가, 수정하기가 힘들다).


해결 3 (Abstract Factory Pattern)
 해결2에서 EquipFactory 클래스 내부에는 장비 종류에 따는 객체를 생성할 수 있게 조건문이 존재한다.
ex) EquipFactory의 CreateDataSender 메소드
public IDataSender CreateDataSender()
{
      switch (_eEquipType) // 장비에 따른 객체 생성
      {
            case EEquipType.EquipA: return new EquipADataSender();
            case EEquipType.EquipB: return new EquipBDataSender();
       }

       return null;
 }

 프로그램이 커지면, 이런 조건문 때문에 이전 코드와 독립적으로 새로운 부분을 추가, 수정하기가 힘들어 진다. 이를 해결 하기 위해서는 장비 별로 Factory 클래스를 생성한다. 그 후 장비 별 Factory 클래스에서 공통 메소드들을 뽑아내어 공통 인터페이스(IEquipFactory)로 만든다. 장비 별 Factory 클래스에서 이 공통 인터페이스를 상속 받아 구현하면 조건문을 사용하지 않고도 문제를 해결할 수 있다. 장비를 추가하거나 삭제할 경우, 이전 소스 코드를 수정하지 않고도 독립적으로 변경이 가능하다. 이런 방식을 Abstract Factory Pattern이라고 한다.






샘플 소스 (C#)

          IEquipFactory equipFactory = null;
            EEquipType equipType = EEquipType.EquipB;

// 처음 한번은 어떤 장비를 생성할 것인지 구별하기 위해서 조건문이 사용되었다.
// 하지만 Factory 클래스들은 장비 별로 독립적으로 구현되어 있다.
            switch (equipType)
            {
                case EEquipType.EquipA: equipFactory = new EquipAFactory(); break;
                case EEquipType.EquipB: equipFactory = new EquipBFactory(); break;
            }

            if (equipFactory == null) return;
           
            IDataSender sender = equipFactory.CreateDataSender();
            IDataReceiver receiver = equipFactory.CreateDataReceiver();
            IDataParser parser = equipFactory.CreateDataParser();
            IDataProc proc = equipFactory.CreateDataProc();

            sender.Send();
            receiver.Receive();
            parser.Parse();
            proc.Proc();


Visual Studio 2008, C#

+ Recent posts