본 게시글은 '헤드퍼스트-디자인 패턴 (개정판)'을 기준으로 작성된 글입니다.
문제점 찾아보기
Duck duck;
if (picnic) {
duck = new MallardDuck();
}
else if (hunting){
duck = new DecoyDuck();
}
else if (inBathTub) {
duck = new RubberDuck();
}
다음 코드에서의 문제점은, 각 조건에 따라 다른 Duck이 생성이 된다.
만약 새로운 Duck을 추가하기 위해 확장한다면, 어떤 것을 추가하고 삭제해야할 지 코드를 다시 확인해야 한다.
결론
Concrete Class(구상 클래스)를 많이 사용하면, 새로운 구상 클래스가 추가될 때마다 코드를 고쳐야하므로 많은 문제가 생길 수 있다.
결국 변화에 닫혀 있는 코드가 된다 (OCP 위반) →(해결) 바뀔 수 있는 부분을 찾아내서 바뀌지 않는 부분하고 분리시켜야 한다.
코드의 reuse를 위한 목적으로 콘크리트 클래스를 쓰지 마라.
구상클래스 : new 키워드를 사용하여 인스턴스를 만드는 클래스
피자 만들기
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();
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
return pizza;
}
상황 : 피자 가게를 운영하고 있고 피자 가게 클래스를 만든다.
변화하는 부분 : if문 부분을 캡슐화 한다.
캡슐화한 코드
public class SimplePizzaFactory {
public Pizza createPizza(String type){
Pizza pizza = null;
if(type.equals("cheese")) pizza = new CheesePizza();
if(type.equals("pepper")) pizza = new PepperoniPizza();
if(type.equals("clam")) pizza = new ClamPizza();
if(type.equals("veggie")) pizza = new VeggiePizza();
return pizza;
}
}
피자를 생성하는 부분을, 정의한다.
코드 수정하기
public class PizzaStore{
SimplePizzaFactory simplePizzaFactory;
public PizzaStore(SimplePizzaFactory simplePizzaFactory) {
this.simplePizzaFactory = simplePizzaFactory;
}
public Pizza orderPizza(String type){
Pizza pizza;
pizza = simplePizzaFactory.createPizza(type);
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
return pizza;
}
}
PizzaStore에 SimplePizzaFactory의 레퍼런스를 저장한다.
생성자에 팩토리 객체가 전달이 된다.
주문 형식만 지정해주면, 피자 객체를 만들 수 있다.
new 연산자를 사용하는 대신 create 메소드를 사용했다.
새로운 상황
각 지역마다의 특색을 살려 지역별 다양한 스타일의 피자를 만들어야 하는 상황.
public abstract class PizzaStore{
public Pizza orderPizza(String type){
Pizza pizza;
pizza = createPizza(type);
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
return pizza;
}
abstract Pizza createPizza(String type);
각 분점을 위한 서브클래스를 만들어두고 피자의 각 스타일은 서브 클래스에서 결정하도록 하였다.
피자 객체 인스턴스를 만드는 일은 PizzaStore의 서브클래스의 createPizza() 메소드에서 처리한다.
public class NYPizzaStore extends PizzaStore{
@Override
public Pizza createPizza(String type){
Pizza pizza = null;
if(type.equals("cheese")) pizza = new NYStyleCheesePizza();
if(type.equals("peper")) pizza = new NYStylePepperoniPizza();
if(type.equals("clam")) pizza = new NYStyleClamPizza();
if(type.equals("veggie")) pizza = new NYStyleVeggiePizza();
return pizza;
}
}
public abstract class Pizza{
String name;
String dough;
String sauce;
ArrayList<String> toppings = new ArrayList<>();
public void prepare(){
System.out.println("Preparing : "+name);
System.out.println("Tossing dough...");
System.out.println("Adding source");
System.out.println("Adding toppings");
for (String topping : toppings) {
System.out.println("\ttopping : "+topping);
}
}
public void bake(){
System.out.println("Bake for 25 minutes at 350");
}
public void cut(){
System.out.println("Cutting the pizza into diagonal slices");
}
public void box(){
System.out.println("Place pizza in official PizzaStore box");
}
public String getname(){
return this.name;
}
}
```java
public class ChicagoStyleCheesePizza extends Pizza{
public ChicagoStyleCheesePizza() {
this.name = "Chicago Style CheesePizza";
this.dough = "Extra Thick Crust Dough";
this.sauce = "Plum Tomato Sauce";
this.toppings.add("Shredded mozzarella Cheese");
}
@Override
public void cut() {
System.out.println("Cutting the pizza into square slices");
}
}
```
팩토리 메소드 패턴
모든 팩토리 패턴에서는 객체 생성을 캡슐화한다. 팩토리 메소드 패턴에서는 어떤 서브클래스를 만들지 결정하게 함으로써 캡슐화를 한다.
팩토리 패턴을 통해 DIP를 지킨다
이유
[기존의 의존성]
PizzaStore -> NYStyleCheesePizza
PizzaStore -> ChicagoStypeCheesePizza
PizzaStore -> NYStyleVeggiePizza
[팩토리 패턴 적용 후 의존성]
PizzaStore -> Pizza
Pizza <- NYStyleCheesePizza
Pizza <- ChicagoStyleCheesePizza
Pizza <- NYStyleVeggiePizza
'디자인패턴' 카테고리의 다른 글
[디자인 패턴] - 데코레이터 패턴 (1) | 2023.09.01 |
---|---|
[디자인 패턴] - 옵저버 패턴 (0) | 2023.08.31 |
[디자인패턴] - 전략 패턴 (0) | 2023.08.30 |