firsthead 책을 공부하고 요약한 것입니다.
new는 구상객체다.
new 지시자는 구상클래스의 인스턴스를 만드는것. new는 나중에 코드를 수정할 가능성이 높아지며 유연성이 떨어진다.
// 인터페이스를 Animal을 사용하였지만 new 지시자를 이용해 구상클래스 생성
Animal dog = new Dog();
다음과 같이 코드를 짜야할 순간이 있다.
if(dogType === 'Maltese'){
dog = new Maltese();
}else if(dogType === 'Pomeranian'){
dog = new Pomeranian();
}else if(dogType === 'ShihTzu'){
dog = new ShihTzu();
}
이런 코드는 만들어지는 인스턴스 형식은 실행시 주어진 로직에 따라 결정된다.
이런 코드는 관리 및 갱신하기가 어려워 지며 사이드 이펙트를 생성한다.
new 지시자는 당연히 안 쓸 수 없다. new는 변화에 약하다. 인터페이스에 맞춰서 코드를 짜는것은 소프트웨어에서 일어날
변화를 극복할 수 있다. 다형성 때문에 어떤 클래스든 특정 인터페이스만 구현하면 사용이 유연해지기 때문이다.
변화에는 닫혀있고 확장에는 열려있어야 한다.
문제점
피자가게를 운영하고 있는 코드를 작성해보자
public orderPizza(type:string): Pizza{
let pizza : Pizza;
if(type === 'cheese'){
pizza = new CheesePizza();
}else if(type === 'greek'){
pizza = new GreekPizza();
}else if(type === 'pepperoni'){
pizza = new PepperoniPizza();
}
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
return pizza;
}
만약 여기서 메뉴를 추가하거나 삭제해야 한다면...
else if(type === 'potato'){
pizza = new PotatoPizza();
}
이렇게 코드를 직접 변경해야합니다. 변경에 열려있으며 피자 종류에 따라 코드를 직접 건드려야 겠네요.
디자인 원칙 중 하나는 변경되는 부분을 분리해라
구상 클래스를 생성하는 저 코드를 분리합시다. 피자를 생성하는 코드를 클래스를 이용해 다음과 같이 작성합니다.
class PizzaFactory{
public createPizza(type:string): Pizza{
let pizza:Pizza;
if(type === 'cheese'){
pizza = new CheesePizza();
}else if(type === 'greek'){
pizza = new GreekPizza();
}else if(type === 'pepperoni'){
pizza = new PepperoniPizza();
}
return pizza;
}
}
단순 객체생성 코드를 다른 클래스에 위임한 것 뿐인데 뭐가 다른걸까요?
다른 클라이언트 코드 부분에서 피자팩토리를 많이 사용할 때 유용합니다. 피자 생성 팩토리 클래스를 캡슐화 시켜
놓으면 여기저기 고칠 필요 없이 이 팩토리 클래스 하나만 수정하면 됩니다.
다음은 전체적인 클라이언트 코드부분입니다.
abstract class Pizza{}
class DefaultPizza extends Pizza{}
class CheesePizza extends Pizza{}
class GreekPizza extends Pizza{}
class PepperoniPizza extends Pizza{}
class PizzaFactory{
private pizza:Pizza;
constructor(){
this.pizza = new DefaultPizza();
}
public createPizza(pizzaType: string): Pizza{
if(pizzaType === 'cheese'){
this.pizza = new CheesePizza();
}else if(pizzaType === 'greek'){
this.pizza = new GreekPizza();
}else if(pizzaType === 'pepperoni'){
this.pizza = new PepperoniPizza();
}
return this.pizza;
}
}
class PizzaStore{
private pizzaFactory : PizzaFactory;
constructor(){
this.pizzaFactory = new PizzaFactory();
}
public orderPizza(pizzaType: string){
let pizza:Pizza;
pizza = this.pizzaFactory.createPizza('cheese');
return pizza;
}
}
간단하게 팩토리 패턴에 대해 알아보았지만 아직 문제점은 많습니다.
피자스토어가 너무 잘되어 여러 지점에서 운영을 하고 싶다면 어떻게 작성해야 할까요?
다음에 게시하도록 하겠습니다.
'디자인패턴' 카테고리의 다른 글
퍼사드 패턴(Facade Pattern) (0) | 2022.02.04 |
---|---|
전략패턴 (Strategy Pattern ) (0) | 2021.09.21 |
데코레이터 패턴(Decorator Pattern) (0) | 2021.09.21 |
싱글톤 패턴 (singleton pattern) (0) | 2021.09.16 |
댓글