Abstract Factory Pattern
추상 팩토리 패턴이란 서로 관련성이 있거나 독립적인 여러 객체군을 생성하기 위한 인터페이스를 제공하는 패턴이다.
활용성
객체가 생성되거나 구성 혹은 표현되는 방식과 무관하게 시스템을 독립적으로 만들고자 할때
여러 제품군중 하나를 선택해서 시스템을 설정해야 하고 한번 구성한 제품을 다른 것으로 대체할 수 있을 때
관련된 제품 객체들이 함께 사용되도록 설계되었고 이 부분에 대한 제약이 외부에도 지켜지도록 하고 싶을 때
제품에 대한 클래스 라이브러리를 제공하고 그들의 구현이 아닌 인터페이스를 노출시키고 싶을 때
추상 팩토리 패턴 사용에 따른 결과 구체 클래스의 분리 추상 팩토리 패턴을 사용하면 프로그램이 생성할 객체의 클래스를 제어할 수 있다. 팩토리는 제품 객체를 생성하는 과정과 책임을 캡슐화 한 것이기 때문에 구체적인 구현 클래스가 사용자에게서 분리된다.
제품군을 쉽게 대체 구체 팩토리의 클래스는 프로그램에서 한 번만 나타나기 때문에 프로그램이 사용할 구체 팩토리를 변경하기 쉽다. 또한 구체 팩토리를 변경함으로써 프로그램은 서로 다른 제품을 사용할 수 있게 변경된다. 추상 팩토리는 필요한 모든 것을 생성하기 때문에 전체 제품군은 한번에 변경이 가능하다.
제품 사이의 일관성 증진 하나의 제품군 내에 속한 제품 객체들이 함께 동작하도록 설계되어 있을 때 프로그램은 한 번에 오직 한 군에서 만든 객체를 사용하도록 함으로써 프로그램의 일관성을 갖게 한다.
새로운 종류의 제품을 제공하기 어렵다 새로운 종류의 제품을 만들기 위해 기존 추상 팩토리를 확장하기가 쉽지 않다. 만약 새로운 종류의 제품이 등장하면 팩토리의 구현을 변경해야 한다. 이는 추상 팩토리와 모든 서브 클래스의 변경을 가져온다.
팩토리 생성의 나쁜 방법 애플과 삼성 두 회사가 있다고 가정하고 각각의 회사에선 휴대폰과 이어폰이라는 제품군이 있다고 가정하자. 다음과 같은 코드를 보자.
1 2 3 4 5 6 void BadFactoryPattern () { BadFactory badFactory; Phone* phone = badFactory.createPhone (SAMSUNG); Earphone* earphone = badFactory.createEarphone (SAMSUNG); }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 #include "BadFactory.h" Phone* createPhone (Company company) { if (company == APPLE) return new ApplePhone; if (company == SAMSUNG) return new SamsungPhone; throw std::bad_exception (); } Earphone* createEarphone (Company company) { if (company == APPLE) return new AppleEarphone; if (company == SAMSUNG) return new SamsungEarphone; throw std::bad_exception (); }
위 코드를 보면 각각의 제품군에 대해서 각각의 회사를 명시함으로써 제품을 얻고 있다. 각각의 제품 구성품들은 어느 회사인지를 구분할 필요 없이 일관된 방식으로 애플이라면 애플의 제품군을, 삼성이라면 삼성의 제품군을 만들도록 객체를 생성할 필요가 있다.
비유가 적절하지 못하다면 컴퓨터 시스템을 생각해 보자. 윈도우와 맥으로 구성된 두 개의 구체 회사가 존재할 때 멀티 플랫폼의 시스템을 설계하며 컴포넌트의 구성을 일관성 있는 방식으로 생성해야 한다고 이해한다면 수긍이 갈 것이라 생각한다.
또한 이 방식은 회사가 늘어난다면 객체를 생성하는 부분의 코드가 길어질뿐 더러 수정할 부분이 많아진다. 이는 OCP를 위배한다.
추상 팩토리 구조 추상 팩토리의 구조는 다음과 같다.
C++ 구현 1 2 3 4 5 6 7 8 9 10 11 void CreateDevice (AbstractDeviceFactory* fac) { Phone* phone = fac->createPhone (); Earphone* earphone = fac->createEarphone (); } void AbstractFactoryPattern () { CreateDevice (new SamsungDeviceFactory); CreateDevice (new AppleDeviceFactory); }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 class AbstractDeviceFactory { public : virtual ~AbstractDeviceFactory () {}; virtual Phone* createPhone () = 0 ; virtual Earphone* createEarphone () = 0 ; }; class AppleDeviceFactory : public AbstractDeviceFactory{ public : Phone* createPhone () override { return new ApplePhone (); } Earphone* createEarphone () override { return new AppleEarphone (); } }; class SamsungDeviceFactory : public AbstractDeviceFactory{ public : Phone* createPhone () override { return new SamsungPhone (); } Earphone* createEarphone () override { return new SamsungEarphone (); } };
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 class Phone { public : virtual ~Phone () {}; }; class ApplePhone : public Phone{ public : ApplePhone () { std::cout<<"ApplePhone Constructed" <<std::endl; } }; class SamsungPhone : public Phone{ public : SamsungPhone () { std::cout<<"SamsungPhone Constructed" <<std::endl; } };
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 class Earphone { public : virtual ~Earphone () {}; }; class AppleEarphone : public Earphone{ public : AppleEarphone () { std::cout<<"AppleEarphone Constructed" <<std::endl; } }; class SamsungEarphone : public Earphone{ public : SamsungEarphone () { std::cout<<"SamsungEarphone Constructed" <<std::endl; } };
Java 구현 1 2 3 4 5 6 7 8 9 10 11 12 13 14 public class Client { public static void main (String[] args) { AbstractDeviceFactory fac; fac = DeviceFactoryFactory.getFactory(Company.SAMSUNG); fac.createPhone(); fac.createEarphone(); fac = DeviceFactoryFactory.getFactory(Company.APPLE); fac.createPhone(); fac.createEarphone(); } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 public class DeviceFactoryFactory { public static AbstractDeviceFactory getFactory (Company company) { AbstractDeviceFactory factory = null ; switch (company) { case APPLE: factory = AppleDeviceFactory.getInstance(); break ; case SAMSUNG: factory = SamsungDeviceFactory.getInstance(); break ; } return factory; } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 public abstract class AbstractDeviceFactory { public abstract Phone createPhone () ; public abstract Earphone createEarphone () ; } public class SamsungDeviceFactory extends AbstractDeviceFactory { private static AbstractDeviceFactory samsungDeviceFactory = new SamsungDeviceFactory (); private SamsungDeviceFactory () {} public static AbstractDeviceFactory getInstance () { return samsungDeviceFactory; } @Override public Phone createPhone () { return new SamsungPhone (); } @Override public Earphone createEarphone () { return new SamsungEarphone (); } } public class AppleDeviceFactory extends AbstractDeviceFactory { private static AbstractDeviceFactory appleDeviceFactory = new AppleDeviceFactory (); private AppleDeviceFactory () {} public static AbstractDeviceFactory getInstance () { return appleDeviceFactory; } @Override public Phone createPhone () { return new ApplePhone (); } @Override public Earphone createEarphone () { return new AppleEarphone (); } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 public abstract class Phone {} public class SamsungPhone extends Phone { public SamsungPhone () { System.out.println("Samsung Phone Constructed" ); } } public class ApplePhone extends Phone { public ApplePhone () { System.out.println("Apple Phone Constructed" ); } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 public abstract class Earphone {} public class SamsungEarphone extends Earphone { public SamsungEarphone () { System.out.println("Samsung Earphone Constructed" ); } } public class AppleEarphone extends Earphone { public AppleEarphone () { System.out.println("Apple Earphone Constructed" ); } }