에릭 프리먼 님의 "헤드퍼스트 디자인 패턴" 책을 정리한 포스팅 입니다
1. new 키워드
- 특정 구현이 아닌 인터페이스로 프로그래밍해야 함
- 그러나, 객체 생성시 특정 구현체를 생성해야 함
- 구현체 클래스에 의존적인 코드가 발생함
- 변경에만 닫혀있는 코드가 생겨남
2. 팩토리 메서드 패턴
- 객체를 생성할 때, 어떤 클래스의 인스턴스를 만들지를 서브클래스에서 결정하도록 하는 패턴
- 클라이언트 코드와 구현체 생성 코드를 분리시킴
Factory
public class PizzaStore {
SimplePizzaFactory factory;
public PizzaStore(SimplePizzaFactory factory) { this.factory = factory; }
public Pizza orderPizza(String type) {
Pizza pizza = factory.createPizza(type);
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
return pizza;
}
}
- 객체 생성을 캡슐화하여 처리하는 클래스
- 호출자는 구체적인 구현을 알 필요 없음
- 확장에 열려있고 변경에 닫혀있게 할 수 있음
추상 클래스화
public abstract class PizzaStore {
public Pizza orderPizza(String type) {
Pizza pizza = createPizza(type);
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
return pizza;
}
public abstract Pizza createPizza(String type);
}
- 서브클래스에 피자 생성을 위임함
- 어떤 종류의 피자를 만들지에 대한것은 어떤 서브클래스를 생성했느냐에 따라 결정됨
NYPizzaStore
public class NYPizzaStore extends PizzaStore {
public Pizza orderPizza(String item) {
if (item.equals("cheese") return new NYStyleCheesePizza();
if (item.equals("veggie") return new NYStyleVeggiePizza();
if (item.equals("clam") return new NYStyleClamPizza();
if (item.equals("pepperoni") return new NYStylePepperoniPizza();
return null;
}
}
3. 의존성 뒤집기 원칙
- 고수준 구성요소가 저수준 구성 요소에 의존하면 안됨
- 추상화된 것에 의존하게 만들기
- 구현체 클래스에 의존하지 않기
의존성 뒤집기 전
public class DependentPizzaStore {
public Pizza createPizza(String style, String type) {
Pizza pizza = null;
if (style.equals("NY")) {
if (item.equals("cheese") return new NYStyleCheesePizza();
if (item.equals("veggie") return new NYStyleVeggiePizza();
if (item.equals("clam") return new NYStyleClamPizza();
if (item.equals("pepperoni") return new NYStylePepperoniPizza();
} else if (style.equals("Chicago")) {
if (item.equals("cheese") return new ChicagoStyleCheesePizza();
if (item.equals("veggie") return new ChicagoStyleVeggiePizza();
if (item.equals("clam") return new ChicagoStyleClamPizza();
if (item.equals("pepperoni") return new ChicagoStylePepperoniPizza();
}
return pizza;
}
}
- 모든 구현체 클래스를 의존함
- 구현체 클래스가 변경되면 수정이 필요할 수 있음
의존성 뒤집기
- 추상 팩토리 메서드 패턴을 사용하여 의존성을 역전시킴
4. 추상 팩토리 패턴
- 서로 연관되거나 의존적인 객체로 이루어진 제품군을 생산하는 인터페이스 제공
- Composition으로 객체 생성
Pizza
추상클래스
public abstract class Pizza {
String name;
Dough dough;
Sauce sauce;
Veggies[] veggies;
Cheese cheese;
Pepperoni pepperoni;
Clams clam;
abstract void prepare();
void bake() { // ... }
void cut() { // ... }
void box() { // ... }
void setName(String name) { this.name = name; }
String getName() { return name; }
}
- 구현체 클래스에 추상계층 추가
서브클래스
public class CheesePizza extends Pizza {
PizzaIngredientFactory pizzaIngredientFactory;
public CheesePizza(PizzaIngredientFactory pizzaIngredientFactory) {
this.pizzaIngredientFactory = pizzaIngredientFactory;
}
void prepare() {
dough = ingredientFactory.createDough();
sauce = ingredientFactory.createSauce();
cheese = ingredientFactory.createCheese();
}
}
PIzzaIngredientFactory
인터페이스
public interface PizzaIngredientFactory {
Dough createDough();
Sauce createSauce();
Cheese createCheese();
Veggies[] createVeggies();
Pepperoni createPepperoni();
Clams createClam();
}
서브클래스
public class NYPizzaIngredientFactory implements PizzaIngredientFactory {
public Dough createDough() { return new ThinCrustDough(); }
public Sauce createSauce() { return new MarinaraSauce(); }
public Cheese createCheese() { return new ReggianoCheese(); }
public Veggie[] createVeggies() { return new[] {new Galic(), new Onion(), new Mushroom(), new RedPepper() }; }
public Pepperoni createPepperoni() { return new SlicedPepperoni(); }
public Clams createClam() { return new FreshClams(); }
}
- 지역별 재료 공장 생성
가이드라인
- 변수에 구현체 클래스의 레퍼런스 저장 X
- 구현체 클래스에서 유도된 클래스 생성 X
- 베이스 클래스의 메서드 오버라이딩 X
'Java > Design Pattern' 카테고리의 다른 글
[헤드퍼스트 디자인 패턴] 6. 커맨드 패턴 (0) | 2024.12.17 |
---|---|
[헤드퍼스트 디자인 패턴] 5. 싱글턴 패턴 (1) | 2024.12.16 |
[헤드퍼스트 디자인 패턴] 3. 데코레이터 패턴 (1) | 2024.12.16 |
[헤드퍼스트 디자인 패턴] 2. 옵저버 패턴 (0) | 2024.12.16 |
[헤드퍼스트 디자인 패턴] 0. 디자인 패턴이란 (1) | 2024.12.16 |