CodeGym/Java Blog/무작위의/디자인 패턴: 추상 공장
John Squirrels
레벨 41
San Francisco

디자인 패턴: 추상 공장

무작위의 그룹에 게시되었습니다
회원
안녕! 오늘 우리는 디자인 패턴을 계속 공부하고 추상 팩토리 패턴에 대해 논의할 것입니다. 디자인 패턴: 추상 공장 - 1강의에서 다룰 내용은 다음과 같습니다.
  • 추상 공장이 무엇이며 이 패턴이 해결하는 문제에 대해 논의할 것입니다.
  • 사용자 인터페이스를 통해 커피를 주문하기 위한 크로스 플랫폼 애플리케이션의 뼈대를 만들 것입니다.
  • 다이어그램과 코드 보기를 포함하여 이 패턴을 사용하는 방법에 대한 지침을 학습합니다.
  • 보너스로 이 수업에는 Java를 사용하여 운영 체제의 이름을 결정하고 결과에 따라 다른 작업을 수행하는 방법을 배우는 데 도움이 되는 숨겨진 이스터 에그가 포함되어 있습니다.
이 패턴을 완전히 이해하려면 다음 항목에 정통해야 합니다.
  • 자바의 상속
  • Java의 추상 클래스 및 메소드

추상 공장은 어떤 문제를 해결합니까?

모든 팩토리 패턴과 마찬가지로 추상 팩토리는 새 객체가 올바르게 생성되도록 도와줍니다. 우리는 이를 사용하여 다양한 상호 연결된 개체 제품군의 "생산"을 관리합니다. 상호 연결된 개체의 다양한 제품군... 그게 무슨 뜻인가요? 걱정하지 마십시오. 실제로 모든 것이 생각보다 간단합니다. 우선, 상호 연결된 객체의 패밀리는 무엇일 수 있습니까? 여러 유형의 유닛을 포함하는 군사 전략을 개발한다고 가정합니다.
  • 보병
  • 기병대
  • 궁수
이러한 유형의 부대는 같은 군대에서 복무하기 때문에 서로 연결되어 있습니다. 위에 나열된 카테고리는 상호 연결된 객체의 패밀리라고 말할 수 있습니다. 우리는 이것을 이해합니다. 그러나 추상 팩토리 패턴은 상호 연결된 객체의 다양한 패밀리 생성을 조정하는 데 사용됩니다. 여기에도 복잡한 것은 없습니다. 군사 전략 예를 계속 살펴보겠습니다. 일반적으로 군대는 여러 전쟁 당사자에 속합니다. 어느 편에 있느냐에 따라 군대의 외형이 크게 달라질 수 있습니다. 로마 군대의 보병, 기병, 궁수는 바이킹 보병, 기병, 궁수와 다릅니다. 군사 전략에서 서로 다른 군대의 병사들은 상호 연결된 개체의 서로 다른 가족입니다. 프로그래머라면 재미있을 텐데' 그의 실수로 인해 나폴레옹 시대의 프랑스 제복을 입고 머스킷 총을 든 병사가 로마 보병 대열 사이를 걷고 있는 것이 발견되었습니다. 추상 팩토리 디자인 패턴은 이 문제를 해결하기 위해 정확하게 필요합니다. 아니, 시간 여행에서 올 수 있는 당혹감의 문제가 아니라 서로 연결된 다양한 개체 그룹을 만드는 문제입니다. 추상 팩토리는 사용 가능한 모든 제품(객체 패밀리)을 만들기 위한 인터페이스를 제공합니다. 추상 팩토리에는 일반적으로 여러 구현이 있습니다. 그들 각각은 가족 중 하나의 제품을 만드는 책임이 있습니다. 우리의 군사 전략에는 추상 보병, 궁수 및 기병을 생성하는 추상 공장과 이 공장의 구현이 포함됩니다. 예를 들어, 로마 군단병을 만드는 공장과 카르타고 군인을 만드는 공장. 추상화는 이 패턴의 가장 중요한 지침 원칙입니다. 공장의 클라이언트는 추상 인터페이스를 통해서만 공장 및 해당 제품과 함께 작업합니다. 결과적으로 현재 어떤 병사가 생성되고 있는지 생각할 필요가 없습니다. 대신 이 책임을 추상 팩토리의 구체적인 구현에 넘깁니다.

커피숍을 계속 자동화합시다

지난 수업 에서, 공장 방법 패턴을 연구했습니다. 우리는 그것을 커피 사업을 확장하고 여러 새로운 지점을 여는 데 사용했습니다. 오늘날 우리는 계속해서 비즈니스를 현대화할 것입니다. 추상 팩토리 패턴을 사용하여 온라인 커피 주문을 위한 새로운 데스크톱 애플리케이션의 토대를 마련할 것입니다. 데스크톱 애플리케이션을 작성할 때 항상 크로스 플랫폼 지원에 대해 생각해야 합니다. 우리의 응용 프로그램은 macOS와 Windows 모두에서 작동해야 합니다(스포일러: Linux에 대한 지원은 숙제로 구현해야 합니다). 우리의 애플리케이션은 어떤 모습일까요? 매우 간단합니다. 텍스트 필드, 선택 필드 및 버튼으로 구성된 양식입니다. 다른 운영 체제를 사용해 본 경험이 있다면 Windows의 버튼이 Mac과 다르게 렌더링된다는 사실을 분명히 눈치챘을 것입니다. 다른 모든 것과 마찬가지로... 자, 시작하겠습니다.
  • 버튼
  • 텍스트 필드
  • 선택 필드
onClick고지 사항: 각 인터페이스에서 , onValueChanged또는 와 같은 메서드를 정의할 수 있습니다 onInputChanged. 즉, 다양한 이벤트(버튼 누르기, 텍스트 입력, 선택 상자에서 값 선택)를 처리할 수 있는 메서드를 정의할 수 있습니다. 예제에 과부하가 걸리지 않고 공장 패턴을 연구할 때 더 명확하게 하기 위해 이 모든 것은 여기서 의도적으로 생략되었습니다. 제품에 대한 추상 인터페이스를 정의해 보겠습니다.
public interface Button {}
public interface Select {}
public interface TextField {}
각 운영 체제에 대해 운영 체제 스타일로 인터페이스 요소를 만들어야 합니다. 우리는 Windows와 MacOS용 코드를 작성할 것입니다. Windows용 구현을 만들어 보겠습니다.
public class WindowsButton implements Button {
}

public class WindowsSelect implements Select {
}

public class WindowsTextField implements TextField {
}
이제 MacOS에서도 동일한 작업을 수행합니다.
public class MacButton implements Button {
}

public class MacSelect implements Select {
}

public class MacTextField implements TextField {
}
훌륭한. 이제 사용 가능한 모든 추상 제품 유형을 생성하는 추상 공장으로 진행할 수 있습니다.
public interface GUIFactory {

    Button createButton();
    TextField createTextField();
    Select createSelect();

}
훌륭한. 보시다시피 아직 복잡한 작업을 수행하지 않았습니다. 다음의 모든 것도 간단합니다. 제품과 유추하여 각 OS에 대한 다양한 공장 구현을 생성합니다. Windows부터 시작하겠습니다.
public class WindowsGUIFactory implements GUIFactory {
    public WindowsGUIFactory() {
        System.out.println("Creating GUIFactory for Windows OS");
    }

    public Button createButton() {
        System.out.println("Creating Button for Windows OS");
        return new WindowsButton();
    }

    public TextField createTextField() {
        System.out.println("Creating TextField for Windows OS");
        return new WindowsTextField();
    }

    public Select createSelect() {
        System.out.println("Creating Select for Windows OS");
        return new WindowsSelect();
    }
}
무슨 일이 일어나고 있는지 자세히 설명하기 위해 메소드와 생성자 내부에 일부 콘솔 출력을 추가했습니다. 이제 macOS의 경우:
public class MacGUIFactory implements GUIFactory {
    public MacGUIFactory() {
        System.out.println("Creating GUIFactory for macOS");
    }

    @Override
    public Button createButton() {
        System.out.println("Creating Button for macOS");
        return new MacButton();
    }

    @Override
    public TextField createTextField() {
        System.out.println("Creating TextField for macOS");
        return new MacTextField();
    }

    @Override
    public Select createSelect() {
        System.out.println("Creating Select for macOS");
        return new MacSelect();
    }
}
각 메서드 서명은 메서드가 추상 형식을 반환함을 나타냅니다. 그러나 메서드 내에서 우리는 제품의 특정 구현을 만들고 있습니다. 이것은 우리가 특정 인스턴스의 생성을 제어하는 ​​유일한 장소입니다. 이제 양식에 대한 클래스를 작성할 시간입니다. 이것은 필드가 인터페이스 요소인 Java 클래스입니다.
public class CoffeeOrderForm {
    private final TextField customerNameTextField;
    private final Select coffeeTypeSelect;
    private final Button orderButton;

    public CoffeeOrderForm(GUIFactory factory) {
        System.out.println("Creating coffee order form");
        customerNameTextField = factory.createTextField();
        coffeeTypeSelect = factory.createSelect();
        orderButton = factory.createButton();
    }
}
인터페이스 요소를 생성하는 추상 팩터리는 폼의 생성자에게 전달됩니다. 특정 OS에 대한 인터페이스 요소를 생성하기 위해 필요한 팩토리 구현을 생성자에 전달합니다.
public class Application {
    private CoffeeOrderForm coffeeOrderForm;

    public void drawCoffeeOrderForm() {
        // Determine the name of the operating system through System.getProperty()
        String osName = System.getProperty("os.name").toLowerCase();
        GUIFactory guiFactory;

        if (osName.startsWith("win")) { // For Windows
            guiFactory = new WindowsGUIFactory();
        } else if (osName.startsWith("mac")) { // For Mac
            guiFactory = new MacGUIFactory();
        } else {
            System.out.println("Unknown OS. Unable to draw form :(");
            return;
        }
        coffeeOrderForm = new CoffeeOrderForm(guiFactory);
    }

    public static void main(String[] args) {
        Application application = new Application();
        application.drawCoffeeOrderForm();
    }
}
Windows에서 응용 프로그램을 실행하면 다음과 같은 결과가 나타납니다.
Creating GUIFactory for Windows OS
Creating coffee order form
Creating TextField for Windows OS
Creating Select for Windows OS
Creating Button for Windows OS
Mac에서 출력은 다음과 같습니다.
Creating GUIFactory for macOS
Creating coffee order form
Creating TextField for macOS
Creating Select for macOS
Creating Button for macOS
리눅스에서:
Unknown OS. Unable to draw form :(
이제 요약합니다. 인터페이스 요소가 관련 OS용으로 특별히 생성되는 GUI 기반 애플리케이션의 골격을 작성했습니다. 우리는 우리가 만든 것을 간결하게 반복할 것입니다:
  • 입력 필드, 선택 필드 및 버튼으로 구성된 제품군입니다.
  • Windows 및 macOS용 제품군의 다양한 구현.
  • 제품 생성을 위한 인터페이스를 정의하는 추상 공장입니다.
  • 우리 공장의 두 가지 구현은 각각 특정 제품군을 만드는 일을 담당합니다.
  • 필드가 추상 팩토리를 사용하여 생성자에서 필요한 값으로 초기화되는 추상 인터페이스 요소인 양식(Java 클래스)입니다.
  • 애플리케이션 클래스 이 클래스 내에서 원하는 팩토리 구현을 해당 생성자에 전달하여 양식을 만듭니다.
결론은 우리가 추상 팩토리 패턴을 구현했다는 것입니다.

추상 공장: 사용 방법

추상 공장은 구체적인 제품 클래스에 얽매이지 않고 다양한 제품군 생성을 관리하기 위한 디자인 패턴입니다. 이 패턴을 사용할 때 다음을 수행해야 합니다.
  1. 제품군을 정의합니다. 두 개가 있다고 가정합니다.
    • SpecificProductA1,SpecificProductB1
    • SpecificProductA2,SpecificProductB2
  2. 제품군 내의 각 제품에 대해 추상 클래스(인터페이스)를 정의합니다. 우리의 경우에는 다음이 있습니다.
    • ProductA
    • ProductB
  3. 각 제품군 내에서 각 제품은 2단계에서 정의된 인터페이스를 구현해야 합니다.
  4. 2단계에서 정의한 각 제품을 생성하는 메서드를 사용하여 추상 팩토리를 생성합니다. 이 경우 이러한 메서드는 다음과 같습니다.
    • ProductA createProductA();
    • ProductB createProductB();
  5. 각 구현이 단일 제품군의 제품 생성을 제어하도록 추상 팩터리 구현을 만듭니다. 이렇게 하려면 추상 팩토리의 각 구현 내에서 특정 제품 구현을 생성하고 반환하도록 모든 생성 메서드를 구현해야 합니다.
다음 UML 다이어그램은 위에서 설명한 지침을 보여줍니다. 디자인 패턴: 추상 공장 - 3이제 다음 지침에 따라 코드를 작성합니다.
// Define common product interfaces
public interface ProductA {}
public interface ProductB {}

// Create various implementations (families) of our products
public class SpecificProductA1 implements ProductA {}
public class SpecificProductB1 implements ProductB {}

public class SpecificProductA2 implements ProductA {}
public class SpecificProductB2 implements ProductB {}

// Create an abstract factory
public interface AbstractFactory {
    ProductA createProductA();
    ProductB createProductB();
}

// Implement the abstract factory in order to create products in family 1
public class SpecificFactory1 implements AbstractFactory {

    @Override
    public ProductA createProductA() {
        return new SpecificProductA1();
    }

    @Override
    public ProductB createProductB() {
        return new SpecificProductB1();
    }
}

// Implement the abstract factory in order to create products in family 2
public class SpecificFactory2 implements AbstractFactory {

    @Override
    public ProductA createProductA() {
        return new SpecificProductA2();
    }

    @Override
    public ProductB createProductB() {
        return new SpecificProductB2();
    }
}

숙제

재료를 강화하려면 다음 두 가지를 수행할 수 있습니다.
  1. Linux에서도 작동하도록 커피 주문 애플리케이션을 개선합니다.
  2. 모든 군사 전략과 관련된 유닛을 생산하기 위한 자신만의 추상 공장을 만드십시오. 이것은 실제 군대와 관련된 역사적인 군사 전략이거나 오크, 노움, 엘프가 있는 판타지 전략일 수 있습니다. 중요한 것은 관심있는 것을 선택하는 것입니다. 창의력을 발휘하고 콘솔에 메시지를 인쇄하고 패턴 학습을 즐겨보세요!
코멘트
  • 인기
  • 신규
  • 이전
코멘트를 남기려면 로그인 해야 합니다
이 페이지에는 아직 코멘트가 없습니다