[java] 디자인 패턴 : 팩토리 vs 팩토리 메소드 vs 추상 팩토리

웹 사이트에서 디자인 패턴을 읽고있었습니다

거기에서 Factory, Factory method 및 Abstract factory에 대해 읽었지만 혼란스럽고 정의에 명확하지 않습니다. 정의에 따르면

팩토리-인스턴스화 로직을 클라이언트에 노출시키지 않고 객체를 작성하고 공통 인터페이스를 통해 새로 작성된 객체를 참조합니다. Factory Method의 단순화 된 버전입니다

팩토리 메소드-오브젝트를 작성하기위한 인터페이스를 정의하지만 서브 클래스가 인스턴스화 할 클래스를 결정하고 공통 인터페이스를 통해 새로 작성된 오브젝트를 참조하도록합니다.

Abstract Factory-클래스를 명시 적으로 지정하지 않고 관련 객체 패밀리를 작성하기위한 인터페이스를 제공합니다.

또한 Abstract Factory와 Factory Method에 관한 다른 stackoverflow 스레드를 보았지만 거기에 그려진 UML 다이어그램은 이해를 훨씬 더 악화시킵니다.

누구든지 제게 말해 줄 수 있습니까

  1. 이 세 가지 패턴은 어떻게 다른가요?
  2. 언제 사용합니까?
  3. 또한 가능한 경우 이러한 패턴과 관련된 Java 예제가 있습니까?


답변

세 가지 팩토리 유형 모두 동일한 작업을 수행합니다. “스마트 생성자”입니다.

Apple과 Orange라는 두 가지 종류의 과일을 만들 수 있다고 가정 해 봅시다.

공장

팩토리는 “고정”되었습니다. 서브 클래 싱없이 구현이 하나뿐이기 때문입니다. 이 경우 다음과 같은 클래스가 있습니다.

class FruitFactory {

  public Apple makeApple() {
    // Code for creating an Apple here.
  }

  public Orange makeOrange() {
    // Code for creating an orange here.
  }

}

사용 사례 : Apple 또는 Orange를 생성하는 것은 생성자를 처리하기에 너무 복잡합니다.

공장 방법

팩토리 메소드는 일반적으로 클래스에 일반 처리가 있지만 실제로 사용하는 과일의 종류를 변경하려는 경우에 사용됩니다. 그래서:

abstract class FruitPicker {

  protected abstract Fruit makeFruit();

  public void pickFruit() {
    private final Fruit f = makeFruit(); // The fruit we will work on..
    <bla bla bla>
  }
}

FruitPicker.pickFruit()하위 클래스에서 팩토리 메소드를 구현 하여 공통 기능을 재사용 할 수 있습니다 .

class OrangePicker extends FruitPicker {

  @Override
  protected Fruit makeFruit() {
    return new Orange();
  }
}

추상 공장

Abstract factory는 일반적으로 의존성 주입 / 전략과 같은 것들에 사용되는데, “동일한 종류”가 필요하고 공통적 인 기본 클래스를 갖는 전체 객체 계열을 생성하고자 할 때. 다음은 모호한 과일 관련 예입니다. 여기서 유스 케이스는 실수로 Apple에서 OrangePicker를 사용하지 않도록하려는 것입니다. 우리가 같은 공장에서 과일과 피커를 얻는 한 일치합니다.

interface PlantFactory {

  Plant makePlant();

  Picker makePicker(); 

}

public class AppleFactory implements PlantFactory {
  Plant makePlant() {
    return new Apple();
  }

  Picker makePicker() {
    return new ApplePicker();
  }
}

public class OrangeFactory implements PlantFactory {
  Plant makePlant() {
    return new Orange();
  }

  Picker makePicker() {
    return new OrangePicker();
  }
}


답변

  1. 이 세 가지 패턴은 어떻게 다른가요?

팩토리 : 인스턴스화 로직을 클라이언트에 노출시키지 않고 객체를 만듭니다.

팩토리 메소드 : 객체를 생성하기위한 인터페이스를 정의하지만 서브 클래스가 인스턴스화 할 클래스를 결정하도록합니다. Factory 메소드는 클래스가 서브 클래스에 대한 인스턴스화를 연기하게합니다

Abstract Factory : 구체적인 클래스를 지정하지 않고 관련 또는 종속 객체의 패밀리를 작성하기위한 인터페이스를 제공합니다.

AbstractFactory 패턴은 컴포지션을 사용하여 객체 생성 책임을 다른 클래스에 위임하는 반면 Factory 메소드 디자인 패턴은 상속을 사용하고 파생 클래스 또는 서브 클래스를 사용하여 객체 생성

  1. 언제 사용합니까?

팩토리 : 클라이언트는 클래스 만 필요하며 어떤 구체적인 구현을하고 있는지 상관하지 않습니다.

팩토리 메소드 : 클라이언트는 런타임에 작성해야하는 구체적인 클래스를 알지 못하지만 작업을 수행 할 클래스를 가져 오려고합니다.

AbstactFactory : 시스템이 여러 제품군을 작성해야하거나 구현 세부 사항을 노출하지 않고 제품 라이브러리를 제공하려는 경우.

추상 팩토리 클래스는 종종 팩토리 메소드로 구현됩니다. 팩토리 메소드는 일반적으로 템플리트 메소드 내에서 호출됩니다.

  1. 또한 가능한 경우 이러한 패턴과 관련된 Java 예제가 있습니까?

공장 및 공장 방법

의지:

객체를 생성하기위한 인터페이스를 정의하되 하위 클래스가 인스턴스화 할 클래스를 결정하도록합니다. 팩토리 메소드는 클래스가 인스턴스화를 서브 클래스로 연기하도록합니다.

UML 다이어그램 :

여기에 이미지 설명을 입력하십시오

제품 : Factory 메소드가 작성하는 오브젝트의 인터페이스를 정의합니다.

ConcreteProduct : 제품 인터페이스 구현

제작자 : Factory 메서드 선언

ConcreateCreator : Factory 메서드를 구현하여 ConcreteProduct의 인스턴스를 반환

문제 설명 : 게임 인터페이스를 정의하는 팩토리 메소드를 사용하여 게임 팩토리를 작성하십시오.

코드 스 니펫 :

공장 패턴. 팩토리 메소드는 언제 사용합니까?

다른 창조 패턴과 비교 :

  1. Factory Method를 사용하여 디자인을 시작하고 (더 복잡하고, 사용자 정의가 가능하며, 서브 클래스가 확산 됨) 설계자가 더 많은 유연성이 필요한 곳을 발견함에 따라 Abstract Factory, Prototype 또는 Builder (보다 유연하고 더 복잡한)로 발전

  2. 추상 팩토리 클래스는 종종 팩토리 메소드 로 구현되지만 프로토 타입을 사용하여 구현할 수도 있습니다.

추가 참고 자료 : 소스 제작 디자인 패턴


답변

Factory- 복잡한 객체를 만들기 위해 별도의 Factory 클래스입니다.

예 : Fruit 객체를 생성하는 FruitFactory 클래스

class FruitFactory{

public static Fruit getFruit(){...}

}

팩토리 메소드 -팩토리에 대한 별도의 전체 클래스 대신 해당 클래스 자체에 하나의 메소드를 팩토리로 추가하십시오.

전의:

Calendar.getInstance() (Java's Calendar)

추상 공장 방법 -공장 공장

예 : 컴퓨터 부품을 위해 공장을 짓고 싶다고합시다. 따라서 랩탑, 데스크탑, 서버와 같은 여러 유형의 컴퓨터가 있습니다.

따라서 각 compter 유형마다 공장이 필요합니다. 그래서 우리는 아래와 같이 하나의 높은 수준의 공장을 만듭니다.

ComputerTypeAbstractFactory.getComputerPartFactory(String computerType) ---> This will return PartFactory which can be one of these ServerPartFactory, LaptopPartFactory, DesktopPartFactory.

이제이 3 가지 자체는 다시 공장입니다. (PartFactory 자체를 다루게 될 것이지만, 추상 팩토리에서 제공 한 것에 따라 별도의 구현이있을 것입니다)

  Interface-> PartFactory. getComputerPart(String s), 
Implementations -> ServerPartFactory, LaptopPartFactory, DesktopPartFactory.

Usage:
new ComputerTypeAbstractFactory().getFactory(“Laptop”).getComputerPart(“RAM”)

편집 : 의견의 반대에 따라 Abstract Factory에 정확한 인터페이스를 제공하도록 편집되었습니다.


답변

모든 디자인 패턴은 작성된 작업 코드를 건드리지 않도록하기 위해 노력하고 있습니다. 우리는 일단 작업 코드를 만지면 기존 작업 흐름에 결함이 있으며, 아무것도 깨지 않도록 많은 테스트가 필요하다는 것을 알고 있습니다.

팩토리 패턴은 입력 기준에 따라 객체를 생성하므로 코드와 같은 코드를 작성하지 않아도되고이 객체를 만들지 않아도됩니다. 이에 대한 좋은 예는 여행 웹 사이트입니다. 여행 웹 사이트는 여행 (비행, 기차, 버스) 또는 호텔 만 제공하거나 관광 명소 패키지를 제공 할 수 있습니다. 이제 사용자가 다음을 선택하면 웹 사이트에서 생성해야 할 객체를 결정해야합니다. 여행 또는 호텔 객체 만 생성해야합니다.

이제 포트폴리오에 다른 웹 사이트를 추가 할 계획이고 동일한 코어가 사용된다고 생각하는 경우 (예 : 택시를 검색하고 온라인으로 지불하는 카풀 링 웹 사이트) 코어에서 추상 팩토리를 사용할 수 있습니다. 이 방법으로 운전실과 카풀을 하나 더 공장에 설치할 수 있습니다.

두 공장은 서로 관련이 없으므로 서로 다른 공장에 보관할 수있는 좋은 디자인입니다.

이것이 분명하기를 바랍니다. 이 예제를 염두에두고 웹 사이트를 다시 공부하십시오. 그리고 나는 패턴을 올바르게 표현하기를 정말로 희망합니다 :).


답변

이 답변에 대해서는 “Gang of Four”책을 참조하십시오.

이 책 에는 “공장”, “단순 공장”또는 “가상 공장”정의가 없습니다. 일반적으로 사람들이 “공장”패턴에 대해 이야기 할 때 클래스의 특정 객체 ( “빌더”패턴이 아님) 를 생성하는 것에 대해 이야기 할 수 있습니다 . 그들은 수도 있고하지 않을 수 있습니다 “공장 방법”또는 “추상 팩토리”패턴을 참조하십시오. “공장”은 공식적인 용어가 아니기 때문에 “공장”을 구현할 수 있습니다 (일부 사람들 \ 회사 \ 커뮤니티는 자체 어휘를 ​​가질 수 있음을 명심하십시오).

이 책 에는 “Abstract Factory”및 “Factory Method”에 대한 정의 포함되어 있습니다.

다음은이 책의 정의와 왜 그렇게 혼동 될 수 있는지에 대한 간단한 설명입니다. 다른 답변에서 찾을 수 있기 때문에 코드 예제를 생략합니다.

팩토리 메소드 (GOF) : 객체를 생성하기위한 인터페이스를 정의하지만 서브 클래스가 인스턴스화 할 클래스를 결정하도록합니다. 팩토리 메소드는 클래스가 서브 클래스로 인스턴스화를 연기하도록합니다.

GOF (Abstract Factory) : 구체적인 클래스를 지정하지 않고 관련 또는 종속 객체의 패밀리를 작성하기위한 인터페이스를 제공합니다.

혼란의 근원 : 종종 “Factory Method”패턴에서 “Factory”로 사용 된 클래스를 호출 할 수 있습니다. 이 클래스는 정의에 따라 추상적입니다. 이것이 바로이 클래스를 “Abstract Factory”라고 부르는 이유입니다. 그러나 그것은 단지 클래스의 이름 일뿐입니다. “Abstract Factory”패턴 (클래스 이름! = 패턴 이름)과 혼동해서는 안됩니다. “Abstract Factory”패턴은 다릅니다- 추상 클래스를 사용 하지 않습니다 . 더 큰 객체 또는 서로 관련이 있거나 특정 방식으로 작성해야하는 객체의 일부를 작성하기위한 인터페이스 (프로그래밍 언어 인터페이스는 아님)를 정의합니다.


답변

AbstractProductA, A1 and A2 both implementing the AbstractProductA
AbstractProductB, B1 and B2 both implementing the AbstractProductB

interface Factory {
    AbstractProductA getProductA(); //Factory Method - generate A1/A2
}

Factory Method를 사용하면 AbstractProductA의 A1 또는 A2를 만들 수 있습니다.

interface AbstractFactory {
    AbstractProductA getProductA(); //Factory Method
    AbstractProductB getProductB(); //Factory Method
}

그러나 Abstract Factory는 하나 이상의 팩토리 메소드 (예 : 2 팩토리 메소드)를 가지고 있으며, 이러한 팩토리 메소드를 사용하여 객체 / 관련 객체 세트를 만듭니다. Abstract Factory를 사용하면 AbstractProductA, AbstractProductB의 A1, B1 객체를 만들 수 있습니다.


답변

“창조적 인 패턴에 대한 토론”(강조 광산) 섹션의 첫 두 단락에 대한 답변을 제공 하는 원본 책 Design Patterns : Elements of Reusable Object-Oriented Software 를 인용 한 사람은 없습니다 .

시스템을 생성하는 객체의 클래스로 시스템을 매개 변수화하는 두 가지 일반적인 방법이 있습니다. 한 가지 방법은 객체를 생성하는 클래스 를 서브 클래 싱 하는 것입니다 . 이것은 팩토리 메소드 (107) 패턴 사용에 해당합니다. 이 방법의 주요 단점은 제품 클래스를 변경하기 위해 새로운 서브 클래스가 필요할 수 있다는 것입니다. 이러한 변화는 연속 될 수 있습니다. 예를 들어, 제품 작성자가 팩토리 메소드로 작성되면 해당 작성자도 대체해야합니다.

시스템을 매개 변수화하는 다른 방법은 오브젝트 구성 에 더 의존 합니다. 제품 오브젝트의 클래스를 알고있는 오브젝트를 정의하고이를 시스템의 매개 변수로 만듭니다. 이는 추상 팩토리 (87), 빌더 (97) 및 프로토 타입 (117) 패턴의 주요 측면입니다. 세 가지 모두 제품 객체를 생성하는 새로운 “공장 객체”를 생성합니다. Abstract Factory에는 여러 클래스의 객체를 생성하는 팩토리 객체가 있습니다. 빌더에는 해당하는 복잡한 프로토콜을 사용하여 복잡한 제품을 증분 빌드하는 팩토리 오브젝트가 있습니다. 프로토 타입에는 프로토 타입 오브젝트를 복사하여 제품을 빌드하는 팩토리 오브젝트가 있습니다. 이 경우 프로토 타입이 제품 반품을 담당하기 때문에 팩토리 오브젝트와 프로토 타입은 동일한 오브젝트입니다.