CodeGym/Java Blog/무작위의/디자인 패턴: 팩토리 방식
John Squirrels
레벨 41
San Francisco

디자인 패턴: 팩토리 방식

무작위의 그룹에 게시되었습니다
회원
안녕! 오늘 우리는 계속해서 디자인 패턴을 공부하고 팩토리 메소드 패턴에 대해 논의할 것입니다. 디자인 패턴: 팩토리 방식 - 1 그것이 무엇인지, 이 패턴이 어떤 작업에 적합한지 알게 될 것입니다. 우리는 이 디자인 패턴을 실제로 고려하고 그 구조를 연구할 것입니다. 모든 것을 명확하게 하려면 다음 항목을 이해해야 합니다.
  1. 자바의 상속.
  2. Java의 추상 메서드 및 클래스

팩토리 메소드는 어떤 문제를 해결합니까?

모든 팩토리 디자인 패턴에는 작성자(팩토리 자체)와 제품(팩토리에서 생성된 객체)의 두 가지 유형의 참여자가 있습니다. 다음과 같은 상황을 상상해 보십시오. CodeGym 브랜드 자동차를 생산하는 공장이 있습니다. 다양한 유형의 차체로 자동차 모델을 만드는 방법을 알고 있습니다.
  • 세단
  • 스테이션 왜건
  • 쿠데타
우리 사업은 매우 번창하여 어느 화창한 날 또 다른 자동차 제조업체인 OneAuto를 인수했습니다. 합리적인 사업주로서 우리는 OneAuto 고객을 잃고 싶지 않기 때문에 다음을 생산할 수 있도록 생산 구조 조정 작업에 직면했습니다.
  • 코드짐 세단
  • 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;
    }
}

단순 공장 현대화

우리 커피숍은 아주 잘 운영되고 있습니다. 그래서 우리는 확장을 고려하고 있습니다. 우리는 몇 가지 새로운 위치를 열고 싶습니다. 우리는 대담하고 진취적이어서 지루한 커피숍을 꾸짖지 않을 것입니다. 우리는 각 상점에 특별한 트위스트가 있기를 바랍니다. 따라서 먼저 이탈리아와 미국의 두 위치를 열 것입니다. 이러한 변경 사항은 인테리어 디자인뿐만 아니라 제공되는 음료에도 영향을 미칩니다.
  • 이탈리아 커피숍에서는 특별한 그라인딩과 로스팅을 통해 독점적으로 이탈리아 커피 브랜드를 사용할 것입니다.
  • 미국 지역은 더 많은 부분을 차지할 것이며 주문할 때마다 마시멜로를 제공할 것입니다.
변하지 않는 유일한 것은 우수성이 입증된 우리의 비즈니스 모델입니다. 코드 측면에서 이것은 일어나는 일입니다. 제품에 해당하는 4가지 클래스가 있습니다.
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다양한 스타일의 커피를 만들 수 있도록 충분한 유연성을 유지하면서 동시에 커피를 만드는 과정과 주문을 서비스하는 과정을 연결하여 수업을 진행합니다. 대답은 '예'입니다. 할 수 있습니다. 이를 팩토리 메소드 디자인 패턴이라고 합니다.

단순 공장에서 공장 방식으로

가능한 한 효율적으로 작업을 해결하려면 다음을 수행하십시오.
  1. createCoffee(CoffeeType type)메서드를 클래스에 반환합니다 CoffeeShop.
  2. 우리는 이 방법을 추상적으로 만들 것입니다.
  3. 클래스 CoffeeShop자체가 추상화됩니다.
  4. 클래스 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
    }
}
CoffeeShop2단계 . 추상 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);
    }
}
축하해요. 우리는 커피숍을 예로 들어 공장 방식 디자인 패턴을 구현했습니다.

팩토리 메소드의 원리

이제 우리가 얻은 것을 더 자세히 살펴 보겠습니다. 아래 다이어그램은 결과 클래스를 보여줍니다. 녹색 블록은 작성자 클래스이고 파란색 블록은 제품 클래스입니다. 디자인 패턴: 팩토리 방식 - 2어떤 결론을 내릴 수 있습니까?
  1. 모든 제품은 추상 Coffee클래스의 구현입니다.
  2. 모든 작성자는 추상 CoffeeShop클래스의 구현입니다.
  3. 두 개의 병렬 클래스 계층이 표시됩니다.
    • 제품 계층 구조. 우리는 이탈리아 후손과 미국 후손을 봅니다.
    • 크리에이터의 계층 구조. 우리는 이탈리아 후손과 미국 후손을 봅니다.
  4. 슈퍼 클래스에는 어떤 특정 제품( )이 생성되는지 CoffeeShop에 대한 정보가 없습니다 .Coffee
  5. 수퍼 CoffeeShop클래스는 특정 제품의 생성을 자손에게 위임합니다.
  6. 클래스 의 각 자손은 고유한 특정 기능에 따라 팩토리 메서드를 CoffeeShop구현합니다 . createCoffee()즉, 생산자 클래스의 구현은 생산자 클래스의 세부 사항을 기반으로 특정 제품을 준비합니다.
이제 팩터리 메서드 패턴 을 정의할 준비가 되었습니다 . 팩토리 메소드 패턴은 객체 생성을 위한 인터페이스를 정의하지만 하위 클래스가 생성된 객체의 클래스를 선택할 수 있도록 합니다. 따라서 팩토리 메서드는 인스턴스 생성을 하위 클래스에 위임합니다. 일반적으로 정의를 기억하는 것은 모든 것이 어떻게 작동하는지 이해하는 것만큼 중요하지 않습니다.

팩토리 메소드의 구조

디자인 패턴: 팩토리 방식 - 3위의 다이어그램은 팩토리 메소드 패턴의 일반적인 구조를 보여줍니다. 여기서 또 뭐가 중요해?
  1. Creator 클래스는 팩토리 메서드를 제외하고 제품과 상호 작용하는 모든 메서드를 구현합니다.
  2. 추상 factoryMethod()메서드는 클래스의 모든 자손에 의해 구현되어야 합니다 Creator.
  3. 클래스 는 제품을 직접 생성하는 메서드를 ConcreteCreator구현합니다 .factoryMethod()
  4. 이 클래스는 특정 제품을 만드는 일을 담당합니다. 이것은 이러한 제품 생성에 대한 정보가 있는 유일한 클래스입니다.
  5. 모든 제품은 공통 인터페이스를 구현해야 합니다. 즉, 공통 제품 클래스의 자손이어야 합니다. 이는 제품을 사용하는 클래스가 특정 구현이 아닌 추상화로 작동할 수 있도록 하기 위해 필요합니다.

숙제

오늘 우리는 꽤 많은 일을 했고 팩토리 방식 디자인 패턴을 연구했습니다. 재료를 강화할 때입니다! 연습 1. 다른 커피숍을 여는 일을 하세요. 영국식 커피숍일 수도 있고 스페인식 커피숍일 수도 있습니다. 또는 우주선 스타일. 커피에 식용 색소를 첨가하여 빛을 발하면 커피가 이 세상에서 나올 것입니다! 연습 2. 지난 수업 에서는 가상 스시 바 또는 가상 피자 가게를 만드는 연습을 했습니다. 이제 당신의 운동은 가만히 있지 않는 것입니다. 오늘은 팩토리 메소드 패턴을 유리하게 사용하는 방법을 배웠습니다. 이제 이 지식을 활용하여 자신의 사업을 확장할 때입니다 ;)
코멘트
  • 인기
  • 신규
  • 이전
코멘트를 남기려면 로그인 해야 합니다
이 페이지에는 아직 코멘트가 없습니다