Factory 패턴

Java Design Pattern 2013. 2. 20. 15:51

 ü  객체를 생성하기위한 인터페이스를 정의하는데 어떤 클래스의 인스턴스를
   
서브클래스에서 결정하여 만들도록 유도하게게된다.

사실 서브클래스에서 실행중에 어떤 클래스의 인스턴스를 만들어진다는 관점의 내용보다 상위 클래스에서는 어떤 종류의 인스턴스가 만들어 지는지에대한 지식이 없기 때문에 사용하는 패턴이라고 정의하는것이 원래의 패턴목적에 맞는다.

 

ü  추상 팩토리 패턴에서는 인터페이스를 이용하여 서로 연관된 또는 의존하는 객체를
구상 클래스를 지정하지 않고도 생성할 있다.

 

피자를 주문할때 주문된 피자를 생성하기위한 코드를 살펴보자

 

 

public class PizzaStore {

       public Pizza orderPizza(String type) {

              Pizza pizza;

 

              // 피자종류별 피자를 생성한다.

if (type.equals("cheese")) {

pizza = new CheesePizza();

} else if (type.equals("greek")) {

       pizza = new GreekPizza();

} else if (type.equals("pepperoni")) {

pizza = new PepperoniPizza();

} else if (type.equals("clam")) {

       pizza = new ClamPizza();

} else if (type.equals("veggie")) {

       pizza = new VeggiePizza();

}

 

              pizza.prepare();

              pizza.bake();

              pizza.cut();

              pizza.box();

 

              return pizza;

       }

}

 

 

위와 같은 코드가 있다는 것은 무엇인가 변경하거나 확장해야 코드를 다시 확인하고 추가 또는 제거해야 한다는 것을 뜻한다. à 관리 갱신이 어려워진다.

è 바뀔수있는 부분을 찾아내서 바뀌지 않는 부분하고 분리시켜야 한다.  

 

 

 

다음 코드는 위와 같이 피자의 종류는 수시로 바뀔수 있는 부분이므로 별도로 분리시켜 객체를 생성하는 Factory클래스로 만든다.

 

 

package headfirst.factory.pizzas;

 

public class PizzaStore {

SimplePizzaFactory factory;

 

public PizzaStore(SimplePizzaFactory factory) {

this.factory = factory;

}

 

       public Pizza orderPizza(String type) {

              Pizza pizza;

 

pizza = factory.createPizza(type);

 

              pizza.prepare();

              pizza.bake();

              pizza.cut();

              pizza.box();

 

              return pizza;

       }

}

 

 

 

다음코드는 위의코드를 좀더 기능적으로 분리된 형태의 Factory 패턴이다.

 

 

package headfirst.factory.pizzafm;

 

public abstract class PizzaStore {

 

       // 실제로 피자를 만드는것은 하위 클래스에서 만든다.

// 중요한것은 상위클래스에서는 어떠한 피자가 만들어지는 모르며 알필요도 없다는 것이다.
// 상위클래스는 그냥 피자에대해서 준비하고 굽고 자르고 포장하는 것에만 집중하면 된다.

abstract Pizza createPizza(String item);

 

       public Pizza orderPizza(String type) {

Pizza pizza = createPizza(type);

              System.out.println("--- Making a " + pizza.getName() + " ---");

              pizza.prepare();

              pizza.bake();

              pizza.cut();

              pizza.box();

             

              return pizza;

       }

}

 

 

이와 같이되면 다음 예와 같이 뉴욕에있는 피자 가게에서는 자신의 피자를 생성하게 될것이다.

 

 

package headfirst.factory.pizzafm;

 

public class NYPizzaStore extends PizzaStore {

 

       /* (non-Javadoc)

        * @see headfirst.factory.pizzafm.PizzaStore#createPizza(java.lang.String)

        */

       @Override

       Pizza createPizza(String item) {

              if (item.equals("cheese")) {

                     return new NYStyleCheesePizza();

              } else if (item.equals("veggie")) {

                     return new NYStyleVeggiePizza();

              } else if (item.equals("clam")) {

                     return new NYStyleClamPizza();

              } else if (item.equals("pepperoni")) {

                     return new NYStylePepperoniPizza();

              } else

                     return null;

       }

}

 

 

다음은 위의 설계된 모델을 테스트 하는 클라이언트 코드이다.

 

 

package headfirst.factory.pizzafm;

 

public class PizzaTestDrive {

 

       public static void main(String[] args) {

              PizzaStore nyStore = new NYPizzaStore();

              PizzaStore chicagoStore = new ChicagoPizzaStore();

 

              Pizza pizza = nyStore.orderPizza("cheese");

              System.out.println("Ethan ordered a " + pizza.getName() + "\n");

 

              pizza = chicagoStore.orderPizza("cheese");

              System.out.println("Joel ordered a " + pizza.getName() + "\n");

 

       }

}

 

 

병렬클래스 구조

위의 패턴을 다른 형태의 패턴으로 바라볼 수도 있는데 제품에 관한 지식을 생산자에 캡슐화하는 방법에 초점을 맞춰 다음 그림과 같이 보는 것이다.

 

 

따라서서브클래스에서 실행중에 어떤 클래스의 인스턴스를 만들어진다는 관점의 내용보다 상위 클래스에서는 어떤 종류의 인스턴스가 만들어 지는지에대한 지식이 없기 때문에 사용하는 패턴이라고 정의하는것이 원래의 패턴목적에 맞는다.

 

디자인원칙 : 추상화된 것에 의존하도록 만들어라. 구상 클래스에 의존하도록 만들지 않도록 한다.

 

이것은 추상화에대한 보다 강한 강조라고 볼수있는데 고수준 구성요소가 저수준 구성요소에 의존하면 안된 다는것이 내포되어 있다. 이원칙을 지키기 위한 가이드 라인든 다음과 같다.

 

ü  어떤 변수에도 구상 클래스에 대한 레퍼런스를 저장하지 말자.

ü  구상 클래스에서 유도된 클래스를 만들지 말자.

ü  베이스 클래스에 이미 구현되어 있던 메소드를 오버라이드 하지 말자.

è  오버라이드한다는 것은 이미 제대로 추상화가 안되어 있다는 의미가 된다.

 

 

Posted by Steven J.S Min
,