안녕! 오늘 우리는 계속해서 디자인 패턴을 공부하고 팩토리 메소드 패턴에 대해 논의할 것입니다.
그것이 무엇인지, 이 패턴이 어떤 작업에 적합한지 알게 될 것입니다. 우리는 이 디자인 패턴을 실제로 고려하고 그 구조를 연구할 것입니다. 모든 것을 명확하게 하려면 다음 항목을 이해해야 합니다.
어떤 결론을 내릴 수 있습니까?
위의 다이어그램은 팩토리 메소드 패턴의 일반적인 구조를 보여줍니다. 여기서 또 뭐가 중요해?

- 자바의 상속.
- Java의 추상 메서드 및 클래스
팩토리 메소드는 어떤 문제를 해결합니까?
모든 팩토리 디자인 패턴에는 작성자(팩토리 자체)와 제품(팩토리에서 생성된 객체)의 두 가지 유형의 참여자가 있습니다. 다음과 같은 상황을 상상해 보십시오. CodeGym 브랜드 자동차를 생산하는 공장이 있습니다. 다양한 유형의 차체로 자동차 모델을 만드는 방법을 알고 있습니다.- 세단
- 스테이션 왜건
- 쿠데타
- 코드짐 세단
- CodeGym 스테이션 왜건
- CodeGym 쿠데타
- 원오토 세단
- 원오토 스테이션 왜건
- 원오토 쿠페
팩토리 패턴에 대해 조금
우리가 이전에 작은 가상 커피숍을 만들었다는 것을 상기시켜 드리겠습니다. 간단한 공장의 도움으로 우리는 다양한 종류의 커피를 만드는 방법을 배웠습니다. 오늘 우리는 이 예제를 다시 작업할 것입니다. 공장이 단순한 우리 커피숍의 모습을 떠올려 봅시다. 우리는 커피 수업을 가졌습니다:
public class Coffee {
public void grindCoffee(){
// Grind the coffee
}
public void makeCoffee(){
// Brew the coffee
}
public void pourIntoCup(){
// Pour into a cup
}
}
그리고 공장에서 생산할 수 있는 특정 유형의 커피에 해당하는 여러 하위 클래스:
public class Americano extends Coffee {}
public class Cappuccino extends Coffee {}
public class CaffeLatte extends Coffee {}
public class Espresso extends Coffee {}
쉽게 주문할 수 있도록 enum을 만들었습니다.
public enum CoffeeType {
ESPRESSO,
AMERICANO,
CAFFE_LATTE,
CAPPUCCINO
}
커피 공장 자체는 다음과 같이 생겼습니다.
public class SimpleCoffeeFactory {
public Coffee createCoffee(CoffeeType type) {
Coffee coffee = null;
switch (type) {
case AMERICANO:
coffee = new Americano();
break;
case ESPRESSO:
coffee = new Espresso();
break;
case CAPPUCCINO:
coffee = new Cappuccino();
break;
case CAFFE_LATTE:
coffee = new CaffeLatte();
break;
}
return coffee;
}
}
그리고 마지막으로 커피숍 자체는 다음과 같이 생겼습니다.
public class CoffeeShop {
private final SimpleCoffeeFactory coffeeFactory;
public CoffeeShop(SimpleCoffeeFactory coffeeFactory) {
this.coffeeFactory = coffeeFactory;
}
public Coffee orderCoffee(CoffeeType type) {
Coffee coffee = coffeeFactory.createCoffee(type);
coffee.grindCoffee();
coffee.makeCoffee();
coffee.pourIntoCup();
System.out.println("Here's your coffee! Thanks! Come again!");
return coffee;
}
}
단순 공장 현대화
우리 커피숍은 아주 잘 운영되고 있습니다. 그래서 우리는 확장을 고려하고 있습니다. 우리는 몇 가지 새로운 위치를 열고 싶습니다. 우리는 대담하고 진취적이어서 지루한 커피숍을 꾸짖지 않을 것입니다. 우리는 각 상점에 특별한 트위스트가 있기를 바랍니다. 따라서 먼저 이탈리아와 미국의 두 위치를 열 것입니다. 이러한 변경 사항은 인테리어 디자인뿐만 아니라 제공되는 음료에도 영향을 미칩니다.- 이탈리아 커피숍에서는 특별한 그라인딩과 로스팅을 통해 독점적으로 이탈리아 커피 브랜드를 사용할 것입니다.
- 미국 지역은 더 많은 부분을 차지할 것이며 주문할 때마다 마시멜로를 제공할 것입니다.
public class Americano extends Coffee {}
public class Cappuccino extends Coffee {}
public class CaffeLatte extends Coffee {}
public class Espresso extends Coffee {}
그러나 이제 우리는 8을 갖게 될 것입니다:
public class ItalianStyleAmericano extends Coffee {}
public class ItalianStyleCappucino extends Coffee {}
public class ItalianStyleCaffeLatte extends Coffee {}
public class ItalianStyleEspresso extends Coffee {}
public class AmericanStyleAmericano extends Coffee {}
public class AmericanStyleCappucino extends Coffee {}
public class AmericanStyleCaffeLatte extends Coffee {}
public class AmericanStyleEspresso extends Coffee {}
orderCoffee(CoffeeType type)
우리는 현재 비즈니스 모델을 유지하고 싶기 때문에 방법이 가능한 한 적게 변경되기를 원합니다 . 한번 보세요:
public Coffee orderCoffee(CoffeeType type) {
Coffee coffee = coffeeFactory.createCoffee(type);
coffee.grindCoffee();
coffee.makeCoffee();
coffee.pourIntoCup();
System.out.println("Here's your coffee! Thanks! Come again!");
return coffee;
}
어떤 옵션이 있습니까? 글쎄, 우리는 이미 공장을 작성하는 방법을 알고 있습니다. 즉시 떠오르는 가장 간단한 것은 두 개의 유사한 팩토리를 작성한 다음 원하는 구현을 커피숍의 생성자에게 전달하는 것입니다. 이렇게 해도 다방의 품격은 달라지지 않는다. 먼저 새 팩터리 클래스를 만들고 간단한 팩터리를 상속하도록 만든 다음 메서드를 재정의해야 합니다 createCoffee(CoffeeType type)
. 이탈리아식 커피와 미국식 커피를 만드는 공장을 작성해 보겠습니다.
public class SimpleItalianCoffeeFactory extends SimpleCoffeeFactory {
@Override
public Coffee createCoffee(CoffeeType type) {
Coffee coffee = null;
switch (type) {
case AMERICANO:
coffee = new ItalianStyleAmericano();
break;
case ESPRESSO:
coffee = new ItalianStyleEspresso();
break;
case CAPPUCCINO:
coffee = new ItalianStyleCappuccino();
break;
case CAFFE_LATTE:
coffee = new ItalianStyleCaffeLatte();
break;
}
return coffee;
}
}
public class SimpleAmericanCoffeeFactory extends SimpleCoffeeFactory{
@Override
public Coffee createCoffee (CoffeeType type) {
Coffee coffee = null;
switch (type) {
case AMERICANO:
coffee = new AmericanStyleAmericano();
break;
case ESPRESSO:
coffee = new AmericanStyleEspresso();
break;
case CAPPUCCINO:
coffee = new AmericanStyleCappuccino();
break;
case CAFFE_LATTE:
coffee = new AmericanStyleCaffeLatte();
break;
}
return coffee;
}
}
이제 원하는 팩토리 구현을 CoffeeShop에 전달할 수 있습니다. 다른 커피숍에서 커피를 주문하는 코드가 어떻게 생겼는지 봅시다. 예를 들어, 이탈리아식 및 미국식 카푸치노:
public class Main {
public static void main(String[] args) {
/*
Order an Italian-style cappuccino:
1. Create a factory for making Italian coffee
2. Create a new coffee shop, passing the Italian coffee factory to it through the constructor
3. Order our coffee
*/
SimpleItalianCoffeeFactory italianCoffeeFactory = new SimpleItalianCoffeeFactory();
CoffeeShop italianCoffeeShop = new CoffeeShop(italianCoffeeFactory);
italianCoffeeShop.orderCoffee(CoffeeType.CAPPUCCINO);
/*
Order an American-style cappuccino
1. Create a factory for making American coffee
2. Create a new coffee shop, passing the American coffee factory to it through the constructor
3. Order our coffee
*/
SimpleAmericanCoffeeFactory americanCoffeeFactory = new SimpleAmericanCoffeeFactory();
CoffeeShop americanCoffeeShop = new CoffeeShop(americanCoffeeFactory);
americanCoffeeShop.orderCoffee(CoffeeType.CAPPUCCINO);
}
}
우리는 원하는 공장을 각각 전달하면서 두 개의 서로 다른 커피숍을 만들었습니다. 한편으로 우리는 목표를 달성했지만 다른 한편으로는... 어쩐지 이것은 기업가들에게 잘 어울리지 않습니다... 무엇이 잘못되었는지 알아봅시다. 첫째, 풍부한 공장. 무엇? 이제 모든 새로운 위치에 대해 자체 공장을 만들어야 하고, 그 외에도 커피숍을 만들 때 해당 공장이 생성자에게 전달되는지 확인해야 합니까? 둘째, 여전히 단순한 공장입니다. 약간 현대화되었습니다. 그러나 우리는 새로운 패턴을 배우기 위해 여기에 있습니다. 셋째, 다른 접근법이 가능하지 않습니까? 커피 준비와 관련된 모든 문제를CoffeeShop
다양한 스타일의 커피를 만들 수 있도록 충분한 유연성을 유지하면서 동시에 커피를 만드는 과정과 주문을 서비스하는 과정을 연결하여 수업을 진행합니다. 대답은 '예'입니다. 할 수 있습니다. 이를 팩토리 메소드 디자인 패턴이라고 합니다.
단순 공장에서 공장 방식으로
가능한 한 효율적으로 작업을 해결하려면 다음을 수행하십시오.createCoffee(CoffeeType type)
메서드를 클래스에 반환합니다CoffeeShop
.- 우리는 이 방법을 추상적으로 만들 것입니다.
- 클래스
CoffeeShop
자체가 추상화됩니다. - 클래스
CoffeeShop
에는 하위 클래스가 있습니다.
CoffeeShop
구현하는 클래스 의 후손에 지나지 않습니다 . createCoffee(CoffeeType type)
이제, 한 번에 한 걸음씩. 1단계. Coffee
클래스를 추상화합니다. 우리는 서로 다른 제품의 두 가지 전체 제품군을 보유하고 있습니다. 그럼에도 불구하고 이탈리아와 미국 커피에는 공통 조상인 Coffee
클래스가 있습니다. 추상화하는 것이 적절할 것입니다.
public abstract class Coffee {
public void makeCoffee(){
// Brew the coffee
}
public void pourIntoCup(){
// Pour into a cup
}
}
CoffeeShop
2단계 . 추상 createCoffee(CoffeeType type)
메소드 로 추상 만들기
public abstract class CoffeeShop {
public Coffee orderCoffee(CoffeeType type) {
Coffee coffee = createCoffee(type);
coffee.makeCoffee();
coffee.pourIntoCup();
System.out.println("Here's your coffee! Thanks! Come again!");
return coffee;
}
protected abstract Coffee createCoffee(CoffeeType type);
}
3단계. 추상 커피숍의 후예인 이탈리안 커피숍을 만듭니다. 우리는 createCoffee(CoffeeType type)
이탈리아 레시피의 특성을 고려하여 그 안에 방법을 구현합니다.
public class ItalianCoffeeShop extends CoffeeShop {
@Override
public Coffee createCoffee (CoffeeType type) {
Coffee coffee = null;
switch (type) {
case AMERICANO:
coffee = new ItalianStyleAmericano();
break;
case ESPRESSO:
coffee = new ItalianStyleEspresso();
break;
case CAPPUCCINO:
coffee = new ItalianStyleCappuccino();
break;
case CAFFE_LATTE:
coffee = new ItalianStyleCaffeLatte();
break;
}
return coffee;
}
}
4단계. 미국식 커피숍에도 동일하게 적용
public class AmericanCoffeeShop extends CoffeeShop {
@Override
public Coffee createCoffee(CoffeeType type) {
Coffee coffee = null;
switch (type) {
case AMERICANO:
coffee = new AmericanStyleAmericano();
break;
case ESPRESSO:
coffee = new AmericanStyleEspresso();
break;
case CAPPUCCINO:
coffee = new AmericanStyleCappuccino();
break;
case CAFFE_LATTE:
coffee = new AmericanStyleCaffeLatte();
break;
}
return coffee;
}
}
5단계. 미국식 및 이탈리아식 라떼가 어떻게 보이는지 확인합니다.
public class Main {
public static void main(String[] args) {
CoffeeShop italianCoffeeShop = new ItalianCoffeeShop();
italianCoffeeShop.orderCoffee(CoffeeType.CAFFE_LATTE);
CoffeeShop americanCoffeeShop = new AmericanCoffeeShop();
americanCoffeeShop.orderCoffee(CoffeeType.CAFFE_LATTE);
}
}
축하해요. 우리는 커피숍을 예로 들어 공장 방식 디자인 패턴을 구현했습니다.
팩토리 메소드의 원리
이제 우리가 얻은 것을 더 자세히 살펴 보겠습니다. 아래 다이어그램은 결과 클래스를 보여줍니다. 녹색 블록은 작성자 클래스이고 파란색 블록은 제품 클래스입니다.
- 모든 제품은 추상
Coffee
클래스의 구현입니다. - 모든 작성자는 추상
CoffeeShop
클래스의 구현입니다. - 두 개의 병렬 클래스 계층이 표시됩니다.
- 제품 계층 구조. 우리는 이탈리아 후손과 미국 후손을 봅니다.
- 크리에이터의 계층 구조. 우리는 이탈리아 후손과 미국 후손을 봅니다.
- 슈퍼 클래스에는 어떤 특정 제품( )이 생성되는지
CoffeeShop
에 대한 정보가 없습니다 .Coffee
- 수퍼
CoffeeShop
클래스는 특정 제품의 생성을 자손에게 위임합니다. - 클래스 의 각 자손은 고유한 특정 기능에 따라 팩토리 메서드를
CoffeeShop
구현합니다 .createCoffee()
즉, 생산자 클래스의 구현은 생산자 클래스의 세부 사항을 기반으로 특정 제품을 준비합니다.
팩토리 메소드의 구조

- Creator 클래스는 팩토리 메서드를 제외하고 제품과 상호 작용하는 모든 메서드를 구현합니다.
- 추상
factoryMethod()
메서드는 클래스의 모든 자손에 의해 구현되어야 합니다Creator
. - 클래스 는 제품을 직접 생성하는 메서드를
ConcreteCreator
구현합니다 .factoryMethod()
- 이 클래스는 특정 제품을 만드는 일을 담당합니다. 이것은 이러한 제품 생성에 대한 정보가 있는 유일한 클래스입니다.
- 모든 제품은 공통 인터페이스를 구현해야 합니다. 즉, 공통 제품 클래스의 자손이어야 합니다. 이는 제품을 사용하는 클래스가 특정 구현이 아닌 추상화로 작동할 수 있도록 하기 위해 필요합니다.
GO TO FULL VERSION