Abstract Factory와 Factory 디자인 패턴의 차이점은 무엇입니까?


454

이 두 패턴의 차이점에 대해 많은 게시물이 있지만, 찾을 수없는 것이 몇 가지 있습니다.

내가 읽은 내용에서 팩토리 메소드 패턴을 사용하면 단일 콘크리트 제품을 작성하는 방법을 정의 할 수 있지만 일반 제품을 볼 때 클라이언트에서 구현을 숨기는 방법을 알 수 있습니다. 첫 번째 질문은 추상 팩토리에 관한 것입니다. 하나의 콘크리트 객체가 아닌 콘크리트 객체 패밀리를 만들 수있는 역할이 있습니까 (사용중인 공장에 따라 다름)? 추상 팩토리는 호출하는 메소드에 따라 하나의 매우 큰 객체 또는 많은 객체를 반환합니까?

마지막 두 질문은 여러 곳에서 본 것을 완전히 이해할 수없는 작은 따옴표에 관한 것입니다.

두 가지 차이점 중 하나는 Abstract Factory 패턴을 사용하면 클래스가 컴포지션을 통해 객체 인스턴스화의 책임을 다른 객체에 위임하는 반면 Factory Method 패턴은 상속을 사용하고 원하는 객체 인스턴스화를 처리하기 위해 서브 클래스에 의존한다는 것입니다.

팩토리 메소드 패턴에는 ConcreteCreator가 인스턴스화 할 ConcreteProduct를 아는 것을 담당하는 Creator 인터페이스가 있습니다. 이것이 상속을 사용하여 객체 인스턴스화를 처리한다는 의미입니까?

이제 인용문과 관련하여 Abstract Factory 패턴은 컴포지션을 통해 객체 인스턴스화의 책임을 다른 객체에 얼마나 정확하게 위임합니까? 이것은 무엇을 의미 하는가? Abstract Factory 패턴도 상속을 사용하여 시공 프로세스를 수행하는 것처럼 보이지만 여전히 이러한 패턴에 대해 배우고 있습니다.

특히 마지막 질문에 대한 도움이 있다면 대단히 감사하겠습니다.



클라이언트 관점에서 "인스턴스가 생성 된 방법"을 보면 인용문을 이해하는 데 도움이됩니다.
Karthik Bose

@nawfal, 그 스레드의 답변은 끔찍합니다.
jaco0646

답변:


494

둘의 차이점

"factory method"와 "abstract factory"의 주요 차이점은 factory method가 단일 방법이고 abstract factory가 객체라는 것입니다. 많은 사람들이이 두 용어를 혼동하여 바꾸어 사용할 수 있다고 생각합니다. 나는 그것들을 배웠을 때 그 차이점이 무엇인지 정확히 찾기가 힘들었다는 것을 기억합니다.

팩토리 메소드는 메소드 일 뿐이므로 서브 클래스에서 대체 할 수 있습니다.

... 팩토리 메소드 패턴은 상속을 사용하고 원하는 객체 인스턴스화를 처리하기 위해 서브 클래스에 의존합니다.

인용문은 객체가 여기에서 자체 팩토리 메소드를 호출한다고 가정합니다 . 따라서 리턴 값을 변경할 수있는 유일한 것은 서브 클래스 일 것입니다.

추상 팩토리는 여러 팩토리 메소드가있는 오브젝트입니다. 견적의 전반부를 살펴보십시오.

... Abstract Factory 패턴으로 클래스는 객체 인스턴스화의 책임을 컴포지션을 통해 다른 객체에 위임합니다 ...

그들이 말하는 것은 Foo 객체를 만들고 싶은 객체 A가 있다는 것입니다. Foo 객체 자체 (예 : 팩토리 메서드)를 만드는 대신 Foo 객체를 만들기 위해 다른 객체 (추상 팩토리)를 가져옵니다 .

코드 예

차이점을 보여주기 위해 사용중인 팩토리 방법은 다음과 같습니다.

class A {
    public void doSomething() {
        Foo f = makeFoo();
        f.whatever();   
    }

    protected Foo makeFoo() {
        return new RegularFoo();
    }
}

class B extends A {
    protected Foo makeFoo() {
        //subclass is overriding the factory method 
        //to return something different
        return new SpecialFoo();
    }
}

다음은 사용중인 추상 팩토리입니다.

class A {
    private Factory factory;

    public A(Factory factory) {
        this.factory = factory;
    }

    public void doSomething() {
        //The concrete class of "f" depends on the concrete class
        //of the factory passed into the constructor. If you provide a
        //different factory, you get a different Foo object.
        Foo f = factory.makeFoo();
        f.whatever();
    }
}

interface Factory {
    Foo makeFoo();
    Bar makeBar();
    Aycufcn makeAmbiguousYetCommonlyUsedFakeClassName();
}

//need to make concrete factories that implement the "Factory" interface here

15
이것은 훌륭한 설명입니다. 그러나 가장 중요한 부분은 무엇인가에 대한 답을 얻지 못한 것입니다. 즉, 하나를 사용할 때와 다른 패턴이 언제입니까?
croraf

11
이것이 올바른지 확실하지 않습니다. 팩토리 메소드는 팩토리 메소드의 이름을 딴 디자인 패턴 이지만 클래스 구조와 상속이 포함됩니다. 단일 방법이 아닙니다.
Aviv Cohn 2016 년

2
팩토리 메소드는 다른 목적을 가진 모든 일반 클래스의 메소드가 될 수 있습니다. 그러나 Abstract Factory는 클라이언트가 사용하는 클래스 / 객체이며 가족에서 일부 제품을 생성하는 책임 만 있습니까?
Hieu Nguyen

"SuperFoo"에서 "Super"라는 단어를 사용하여 Foo의 특별한 경우를 의미합니까, 아니면 실제로 슈퍼 클래스를 의미합니까? 내가 가정 한 것처럼 하위 클래스 여야합니다.
dahui

@dahui 네, 그것은 서브 클래스입니다. SpecialFoo더 명확하게 변경했습니다 .
Tom Dalling

125

추상 팩토리는 작성해야하는 객체에 대한 메소드를 정의하는 추상 메소드가있는 기본 클래스를 작성합니다. 기본 클래스를 파생시키는 각 팩토리 클래스는 각 객체 유형의 자체 구현을 만들 수 있습니다.

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

팩토리 메소드 는 클래스에서 오브젝트를 작성하는 데 사용되는 간단한 메소드입니다. 일반적으로 집계 루트에 추가됩니다 ( Order클래스에는라는 메소드가 있습니다 CreateOrderLine)

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

추상 공장

아래 예에서는 메시징 시스템에서 큐 작성을 분리하여 코드 기반을 변경하지 않고도 다른 큐 시스템에 대한 구현을 작성할 수 있도록 인터페이스를 설계합니다.

interface IMessageQueueFactory
{
  IMessageQueue CreateOutboundQueue(string name);
  IMessageQueue CreateReplyQueue(string name);
}

public class AzureServiceBusQueueFactory : IMessageQueueFactory
{
      IMessageQueue CreateOutboundQueue(string name)
      {
           //init queue
           return new AzureMessageQueue(/*....*/);
      }

      IMessageQueue CreateReplyQueue(string name)
      {
           //init response queue
           return new AzureResponseMessageQueue(/*....*/);
      }

}

public class MsmqFactory : IMessageQueueFactory
{
      IMessageQueue CreateOutboundQueue(string name)
      {
           //init queue
           return new MsmqMessageQueue(/*....*/);
      }

      IMessageQueue CreateReplyQueue(string name)
      {
           //init response queue
           return new MsmqResponseMessageQueue(/*....*/);
      }
}

공장 방법

HTTP 서버의 문제점은 모든 요청에 ​​대해 항상 응답이 필요하다는 것입니다.

public interface IHttpRequest
{
    // .. all other methods ..

    IHttpResponse CreateResponse(int httpStatusCode);
}

팩토리 메소드가 없으면 HTTP 서버 사용자 (예 : 프로그래머)는 IHttpRequest인터페이스 의 목적을 무시하는 구현 특정 클래스를 사용해야합니다 .

따라서 팩토리 메소드를 도입하여 응답 클래스 작성도 추상화합니다.

요약

차이점은 팩토리 메소드를 포함하는 클래스 의 의도 된 목적오브젝트를 작성 하는 것이 아니라 추상 팩토리는 오브젝트를 작성하는 데만 사용해야한다는 것입니다.

팩토리 메소드를 사용할 때 오브젝트를 작성할 때 LSP ( Liskov 대체 원칙 )를 쉽게 깨기 때문에주의해야 합니다.


3
구체적인 제품이 필요한 이유는 무엇입니까?
Andrew S

60
아무도 아이디어에 투자하기를 원하지 않기 때문입니다.
jgauffin

4
Abstract Factory는 Button()"관련 제품 제품군"을 만드는 것 이상을 창조해야합니다 . 예를 들어 표준 GoF 예제는 ScrollBar()및을 만듭니다 Window(). 추상 팩토리는 여러 제품에 공통 테마를 적용 할 수 있다는 장점이 있습니다.
jaco0646

Jaco가 옳습니다. 두 UML 다이어그램이 본질적으로 동일하다는 것을 고려하십시오 (Abstract Factory UML이 잘못되었다는 것 제외). 두 경우 모두 클라이언트는 하나의 단일 제품을 만들기 위해 팩토리 메소드를 호출합니다.
cobby

1
@AndrewS : 질문에 대답합니다. 동일한 추상화 (인터페이스)에 대해 다른 구체적인 제품 (클래스)이 필요하지 않은 경우 팩토리 패턴이 아닌 빌더 패턴이 필요할 수 있습니다. (never보다 늦음;)
jgauffin

95

AbstractFactory와 Factory 디자인 패턴의 차이점은 다음과 같습니다.

  • 팩토리 메소드 는 하나의 제품 만 작성하는 데 사용되지만 Abstract Factory 는 관련 또는 종속 제품의 패밀리 작성에 관한 것입니다.
  • 팩토리 메소드 패턴은 오브젝트를 작성하기위한 메소드를 클라이언트에 노출시키는 반면 추상 팩토리 의 경우 이러한 팩토리 메소드로 구성 될 수있는 관련 오브젝트 패밀리를 노출합니다.
  • 팩토리 메소드 패턴은 단일 오브젝트 의 구성을 숨기고 추상 팩토리 는 관련 오브젝트의 패밀리 구성을 숨 깁니다. 추상 팩토리는 일반적으로 팩토리 메소드 세트를 사용하여 구현됩니다.
  • Abstract 팩토리 패턴은 컴포지션을 사용하여 객체 생성 책임을 다른 클래스에 위임하는 반면 팩토리 메소드 디자인 패턴은 상속을 사용하고 파생 클래스 또는 서브 클래스를 사용하여 객체를 생성합니다.
  • 팩토리 메소드 패턴 의 기본 개념 은 클라이언트가 런타임에 작성해야하는 구체적인 클래스를 모르지만 Abstract Factory 패턴이있는 동안 작업을 수행 할 클래스를 얻으려는 경우를 허용한다는 것 입니다. 시스템이 여러 제품군을 작성해야하거나 구현 세부 사항을 노출하지 않고 제품 라이브러리를 제공하려는 경우에 가장 유용합니다.!

팩토리 메소드 패턴 구현 : 팩토리 메소드 UML

추상 팩토리 패턴 구현 :

추상 공장 UML


13
음, 추상 팩토리 예제는 확실하지 않습니다. 쉐이프 팩토리와 컬러 팩토리는 동일한 방법을 구현해야한다고 생각합니다. 그러나 내가 옳다면 샘플은 의미가 없습니다.
호아킨 Iurchuk

4
글 머리 기호가 정확합니다. 그러나 두 다이어그램 모두 완전히 잘못되어 오도됩니다. Abstract Factory의 정확한 모델은 @Trying에서 아래 다이어그램을 참조하십시오.
jaco0646

1
나는 2 개의 도표가 실제로 오해의 소지가 있다는 것에 동의해야한다. 나는 tutorialspoint 웹 사이트에서 그들을 보았고 솔직히 100 % 동의하지 않습니다. 설명은 좋아 보인다
SoftwareDeveloper

이것은 매우 잘못된 것입니다.
diyoda_ 2016 년

50 개 이상의 투표 및 다이어그램이 매우 잘못되었습니다. 증명 많은 SO에 대한 디자인 패턴 답변을 신뢰할 수 없습니다.
Fuhrmanator

27

Abstract Factory와 Factory Method의 주요 차이점은 Abstract Factory 가 Composition에 의해 구현된다는 것입니다 . 그러나 Factory Method는 Inheritance에 의해 구현됩니다 .

그렇습니다, 당신은 그것을 올바르게 읽었습니다.이 두 패턴의 주요 차이점은 오래된 구성과 상속 토론입니다.

UML 다이어그램은 (GoF) 책에서 찾을 수 있습니다. 이 스레드에서 상위 두 답변의 예제를 결합하면 두 가지 답변보다 더 나은 데모를 제공 할 것이라고 생각하기 때문에 코드 예제를 제공하고 싶습니다. 또한이 책의 용어를 클래스 및 메소드 이름으로 사용했습니다.

추상 공장

  1. 여기서 파악해야 할 가장 중요한 점은 추상 팩토리가 클라이언트에 주입 된다는 것 입니다. 이것이 Abstract Factory가 Composition에 의해 구현되었다고 말하는 이유입니다. 종종 의존성 주입 프레임 워크가 그 작업을 수행 할 것입니다. DI에는 프레임 워크가 필요하지 않습니다.
  2. 두 번째 중요한 점은 여기서 구체적인 팩토리 팩토리 메소드 구현 이 아니라는 것입니다! Factory Method의 예제 코드는 아래에 자세히 나와 있습니다.
  3. 마지막으로,주의해야 할 세 번째 사항은 제품 간의 관계입니다.이 경우 아웃 바운드 및 응답 큐입니다. 하나의 콘크리트 팩토리는 Azure 큐를 생성하고 다른 하나는 MSMQ를 생성합니다. GoF는이 제품 관계를 "패밀리"라고하며이 경우 패밀리가 클래스 계층 구조를 의미하지 않는다는 점을 알고 있어야합니다.
public class Client {
    private final AbstractFactory_MessageQueue factory;

    public Client(AbstractFactory_MessageQueue factory) {
        // The factory creates message queues either for Azure or MSMQ.
        // The client does not know which technology is used.
        this.factory = factory;
    }

    public void sendMessage() {
        //The client doesn't know whether the OutboundQueue is Azure or MSMQ.
        OutboundQueue out = factory.createProductA();
        out.sendMessage("Hello Abstract Factory!");
    }

    public String receiveMessage() {
        //The client doesn't know whether the ReplyQueue is Azure or MSMQ.
        ReplyQueue in = factory.createProductB();
        return in.receiveMessage();
    }
}

public interface AbstractFactory_MessageQueue {
    OutboundQueue createProductA();
    ReplyQueue createProductB();
}

public class ConcreteFactory_Azure implements AbstractFactory_MessageQueue {
    @Override
    public OutboundQueue createProductA() {
        return new AzureMessageQueue();
    }

    @Override
    public ReplyQueue createProductB() {
        return new AzureResponseMessageQueue();
    }
}

public class ConcreteFactory_Msmq implements AbstractFactory_MessageQueue {
    @Override
    public OutboundQueue createProductA() {
        return new MsmqMessageQueue();
    }

    @Override
    public ReplyQueue createProductB() {
        return new MsmqResponseMessageQueue();
    }
}

공장 방법

  1. 여기 파악하는 가장 중요한 점은이 있다는 것입니다 ConcreteCreator 이다 클라이언트. 즉, 클라이언트는 부모가를 정의하는 하위 클래스입니다 factoryMethod(). 이것이 팩토리 메소드가 상속에 의해 구현되었다고 말하는 이유입니다.
  2. 두 번째 중요한 점은 팩토리 메소드 패턴은 템플리트 메소드 패턴의 전문화에 지나지 않는다는 점을 기억하는 것입니다. 두 패턴은 동일한 구조를 공유합니다. 그것들은 단지 목적이 다릅니다. 팩토리 메소드는 창조적이며 (뭔가를 구축) 템플릿 메소드는 행동 적이다 (무엇을 계산한다).
  3. 마지막으로, 세 번째로 주목할 점은 Creator(부모) 클래스가 자체 클래스를 호출 한다는 것 factoryMethod()입니다. anOperation()하나의 메소드 만 남겨두고 부모 클래스에서 제거하면 더 이상 팩토리 메소드 패턴이 아닙니다. 즉, 팩토리 메소드는 상위 클래스에서 두 개 미만의 메소드로 구현할 수 없습니다. 하나는 다른 하나를 호출해야합니다.
public abstract class Creator {
    public void anOperation() {
        Product p = factoryMethod();
        p.whatever();
    }

    protected abstract Product factoryMethod();
}

public class ConcreteCreator extends Creator {
    @Override
    protected Product factoryMethod() {
        return new ConcreteProduct();
    }
}

기타 & Sundry Factory 패턴

GoF는 두 개의 다른 팩토리 패턴을 정의하지만 존재하는 유일한 팩토리 패턴은 아닙니다. 그것들은 반드시 가장 일반적으로 사용되는 팩토리 패턴 일 필요는 없습니다. 유명한 세 번째 예는 Josh Bloch의 Effective Java의 정적 팩토리 패턴입니다. Head First Design Patterns 책에는 Simple Factory라고하는 또 다른 패턴이 포함되어 있습니다.

모든 팩토리 패턴이 GoF의 패턴과 일치해야한다고 가정하면 함정에 빠지지 마십시오.


3
이 주제 IMO에서 가장 좋은 좋은 예를 기반으로 한 훌륭하고 명확한 답변.
Luke Duda

좋은 설명입니다. 팩토리 메소드의 경우 +1은 추상 팩토리 메소드 포인트를 호출해야합니다. 이 점을 알면이 점을 이해하지 않고 훨씬 명확합니다. 우리가 자체적으로 호출하지 않는 팩토리 메소드가 있으면 그것을 구성하는 다른 클래스에서 사용되며 하위 클래스가 주입된다는 것을 암시합니다. , 차이는 추상 팩토리 메소드가 템플릿 메소드 패턴처럼 공장 자체에 의해 호출해야한다는 점을 이해하지 않는 경우 덜 분명해진다
nits.kk을

질문 하나 더. 은해야 factoryMethod()항상 일 protected "공장 방법"패턴 방법을? (그렇다고 생각합니다)
Yaroslav Fedoruk

1
@YaroslavFedoruk, GoF 책은 public팩토리 메소드를 허용 하며 메소드도 필요하지 않습니다 abstract. 그러나 중요한 점은이 메소드가 상속을위한 것이므로 (예를 들어) static또는이 될 수 없다는 것 final입니다. 나는 방법을했습니다 protected그리고 abstract여기 (필수) 확장 성을 강조 할 수 있습니다.
jaco0646

@ nits.kk, 당신은 관련 답변에 관심이있을 수 있습니다 .
jaco0646

26

Abstract Factory는 관련 제품을 만들기위한 인터페이스이지만 Factory Method는 하나의 방법 일뿐입니다. Abstract Factory는 여러 팩토리 메소드로 구현할 수 있습니다.

추상 공장 UML


10
이미 동일한 답변을 여기에 게시했습니다 . 이 질문이 비슷하다고 생각되면 대신 중복으로 표시하십시오.
Ja͢ck

11

이해하기 쉽도록이 예를 고려하십시오.

통신 회사는 무엇을 제공합니까? 예를 들어 광대역, 전화선 및 모바일을 사용하면 고객에게 제품을 제공하는 응용 프로그램을 만들어야합니다.

일반적으로 여기서 할 일은 광대역, 전화선 및 모바일과 같은 제품을 만드는 것은 Factory Method를 통해 해당 제품에 대해 어떤 속성을 가지고 있으며 매우 간단하다는 것입니다.

이제이 회사는 고객에게 광대역, 전화선 및 모바일 제품을 번들로 제공하려고합니다. 여기에 Abstract Factory 가 있습니다.

즉, Abstract Factory 는 자체 제품을 만드는 다른 공장의 구성 요소이며 Abstract Factory 는 이러한 제품을 자체 책임과 관련하여보다 의미있게 배치하는 방법을 알고 있습니다.

이 경우,이 BundleFactory요약서 공장입니다 BroadbandFactory, PhonelineFactory그리고 MobileFactory있습니다 Factory. 더 단순화하기 위해,이 팩토리 에는 개별 제품을 초기화하는 팩토리 방법 이 있습니다.

아래 코드 샘플을 참조하십시오.

public class BroadbandFactory : IFactory {
    public static Broadband CreateStandardInstance() {
        // broadband product creation logic goes here
    }
}

public class PhonelineFactory : IFactory {
    public static Phoneline CreateStandardInstance() {
        // phoneline product creation logic goes here
    }
}

public class MobileFactory : IFactory {
    public static Mobile CreateStandardInstance() {
        // mobile product creation logic goes here
    }
}

public class BundleFactory : IAbstractFactory {

    public static Bundle CreateBundle() {
        broadband = BroadbandFactory.CreateStandardInstance();
        phoneline = PhonelineFactory.CreateStandardInstance();
        mobile = MobileFactory.CreateStandardInstance();

        applySomeDiscountOrWhatever(broadband, phoneline, mobile);
    }

    private static void applySomeDiscountOrWhatever(Broadband bb, Phoneline pl, Mobile m) {
        // some logic here
        // maybe manange some variables and invoke some other methods/services/etc.
    }
}

도움이 되었기를 바랍니다.


1
staticGoF 팩토리 패턴 에는 방법 이 없습니다 . 이것은 잘못이다.
jaco0646

5

실제 예. (기억하기 쉽다)

공장

당신이 집을 짓고 문을 위해 목수에게 접근한다고 상상해보십시오. 당신은 문과 요구 사항에 대한 측정을하고, 그는 당신을 위해 문을 구성합니다. 이 경우 목수는 문 공장입니다. 사양은 공장의 입력이며, 도어는 공장의 출력 또는 제품입니다.

추상 공장

이제 같은 문 예를 고려하십시오. 목수 나 플라스틱 문 상점 또는 PVC 상점에 갈 수 있습니다. 그들 모두는 문 공장입니다. 상황에 따라 어떤 종류의 공장에 접근해야하는지 결정합니다. 이것은 추상 팩토리와 같습니다.

여기서는 팩토리 메소드 패턴과 추상 팩토리 패턴을 모두 설명하지 않았습니다. 문제를 설명하지 않고 위 패턴을 사용하여 문제를 해결하는 것으로 시작 하십시오 https://github.com/vikramnagineni/Design-Patterns/tree/master


3

클래스 A가 인터페이스 B로 프로그래밍 되었기 때문에 프로덕션 코드에서 대부분의 경우 추상 팩토리 패턴을 사용한다는 점을 분명히하자. A는 B의 인스턴스를 작성해야하므로 A에는 B의 인스턴스를 생성하는 팩토리 오브젝트가 있어야합니다. 따라서 A는 B의 구체적인 사례에 의존하지 않습니다.


3

동기의 차이점을 이해하십시오.

개체가있는 도구를 만들고 개체의 상호 관계를 구체적으로 구현한다고 가정합니다. 객체의 변형을 예측할 수 있으므로 객체의 변형을 생성하는 책임을 다른 객체에 할당하여 간접 지정을 생성 했습니다 ( 우리는이를 추상 팩토리라고합니다) ) . 이러한 추상화는 해당 객체의 변형이 필요한 향후 확장을 예상하므로 강력한 이점을 제공합니다.

이 생각의 라인에서 또 다른 흥미로운 동기는 전체 그룹의 모든 개체가 해당 변형을 갖는 경우입니다. 일부 조건에 따라 변형 중 하나가 사용되며 각 경우에 모든 객체는 동일한 변형이어야합니다. 이것은 객체의 변형이 공통의 균일 계약을 따르는 한 우리가 종종 생각하는 것처럼 이해하기에 다소 반대 일 수 있습니다. 더 넓은 의미의 인터페이스)을 , 구체적인 구현 코드는 절대로 깨지지 않아야 . 여기서 흥미로운 사실은 프로그래밍 계약으로 예상되는 동작을 모델링 할 수 없을 때 특히 그렇다는 사실입니다.

간단한 ( GoF에서 아이디어를 빌리기) ) GUI 응용 프로그램은 MS 또는 Mac 또는 Fedora OS의 느낌을 모방하는 가상 모니터를 말합니다. 예를 들어, 창, 버튼 등과 같은 모든 위젯 객체에 MAC 변형에서 파생 된 스크롤 막대를 제외한 MS 변형이있는 경우 도구의 목적이 잘못됩니다.

이러한 사례는 추상 팩토리 패턴 의 근본적인 요구를 형성합니다 .

반면에 많은 사람들이 프레임 워크를 사용하여 다양한 도구 ( 예 : 위의 예와 같은 도구)를 작성할 수 있도록 프레임 워크를 작성한다고 가정 하십시오. 프레임 워크라는 아이디어만으로도 논리에 구체적인 객체를 사용할 수는 없지만 필요하지는 않습니다. 당신은 차라리 다양한 객체들과 그것들이 어떻게 상호 작용하는지에 대해 약간의 계약을합니다. ( 프레임 워크 개발자로서 ) 매우 추상적 인 수준을 유지 하는 동안 도구의 각 빌더는 프레임 워크 구성을 따라야합니다. 그러나, 그들은 ( 도구 제작자 ) 어떤 객체를 만들 것인지와 그들이 만든 모든 객체가 어떻게 상호 작용할 것인지를 자유롭게 결정할 수 있습니다. 앞의 경우 (달리 추상 팩토리 패턴의 ), 당신 ( 같은 프레임 워크 작성자)이 경우 콘크리트 물체로 작업 할 필요가 없습니다. 오히려 객체의 계약 수준에 머무를 수 있습니다. 또한 이전 동기의 두 번째 부분과 달리 사용자 또는 도구 제작자는 변형의 객체를 혼합하는 상황이 없습니다. 여기서 프레임 워크 코드는 계약 수준으로 유지되지만 모든 툴 빌더는 ( 사건 자체의 특성상 ) 자체 객체를 사용하도록 제한 됩니다. 이 경우 오브젝트 작성은 각 구현 자에게 위임되며 프레임 워크 제공자는 오브젝트 작성 및 리턴을위한 균일 한 메소드 만 제공합니다. 이러한 메소드는 프레임 워크 개발자가 코드를 처리하는 것이 불가피하며 Factory 메소드 ( 기본 패턴의 팩토리 메소드 패턴) 라는 특수 이름이 있습니다.

몇 가지 참고 사항 :

  • '템플릿 메소드'에 익숙하다면 어떤 형태의 프레임 워크와 관련된 프로그램의 경우 템플릿 메소드에서 팩토리 메소드가 호출되는 경우가 종종 있습니다. 대조적으로, 응용 프로그램의 템플릿 방법은 종종 특정 알고리즘의 간단한 구현이며 공장 방법이없는 경우가 많습니다.
  • 또한 프레임 워크 ( 위에서 언급 한 )를 사용하여 툴 빌더가 구체적인 객체를 생성하는 대신 각 팩토리 방법 내에서 툴을 빌드 할 때 생각의 완전성 을 위해 추상적 인 책임을 더 위임 할 수 있습니다. 툴 팩터는 향후 확장을 위해 콘크리트 객체의 변형을 예견합니다.

샘플 코드 :

//Part of framework-code
BoardGame {
    Board createBoard() //factory method. Default implementation can be provided as well
    Piece createPiece() //factory method

    startGame(){        //template method
         Board borad = createBoard()
         Piece piece = createPiece()
         initState(board, piece)
    }
}


//Part of Tool-builder code
Ludo inherits  BoardGame {
     Board createBoard(){ //overriding of factory method
         //Option A: return new LudoBoard() //Lodu knows object creation
         //Option B: return LudoFactory.createBoard() //Lodu asks AbstractFacory
     }
….
}

//Part of Tool-builder code
Chess inherits  BoardGame {
    Board createBoard(){ //overriding of factory method
        //return a Chess board
    }
    ….
}

3
  1. 첫 번째 질문은 추상 팩토리에 관한 것입니다. 하나의 콘크리트 객체가 아닌 콘크리트 객체 패밀리를 만들 수있는 역할이 있습니까 (사용중인 공장에 따라 다름)?

예. Abstract Factory의 의도는 다음과 같습니다.

구체적인 클래스를 지정하지 않고 관련 또는 종속 객체의 패밀리를 작성하기위한 인터페이스를 제공하십시오.


  1. 추상 팩토리는 호출하는 메소드에 따라 하나의 매우 큰 객체 또는 많은 객체를 반환합니까?

클라이언트가 호출하는 메소드 당 하나의 오브젝트를 리턴하는 것이 이상적입니다.

  1. 팩토리 메소드 패턴에는 ConcreteCreator가 인스턴스화 할 ConcreteProduct를 아는 것을 담당하는 Creator 인터페이스가 있습니다. 이것이 상속을 사용하여 객체 인스턴스화를 처리한다는 의미입니까?

예. 팩토리 메소드는 상속을 사용합니다.

  1. Abstract Factory 패턴은 객체 인스턴스화의 책임을 컴포지션을 통해 다른 객체에 위임합니까? 이것은 무엇을 의미 하는가?

AbstractFactory는 FactoryMethod를 정의하고 ConcreteFactory는 ConcreteProduct를 빌드합니다. 이 기사 의 코드 예제를 따르십시오 .

관련 SE 게시물에서 자세한 내용을 찾을 수 있습니다.

팩토리 패턴과 추상 팩토리 패턴의 기본 차이점은 무엇입니까?

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


3

팩토리 메소드 는 상속에 의존합니다 : 오브젝트 생성은 서브 클래스에 위임됩니다. 서브 클래스는 팩토리 메소드를 구현하여 오브젝트를 생성합니다.

Abstract Factory 는 객체 구성에 의존합니다. 객체 생성은 팩토리 인터페이스에 노출 된 메소드로 구현됩니다.

공장 및 추상 공장 패턴의 높은 수준의 다이어그램

도표

팩토리 메소드에 대한 자세한 정보는 이 기사를 참조 하십시오 .

추상 팩토리 메소드에 대한 자세한 정보는 이 기사를 참조 하십시오 .


2

최소한의 인터페이스로 아주 ​​간단하게 만들고 "// 1"에 집중하십시오 :

class FactoryProgram
    {
        static void Main()
        {
            object myType = Program.MyFactory("byte");
            Console.WriteLine(myType.GetType().Name);

            myType = Program.MyFactory("float"); //3
            Console.WriteLine(myType.GetType().Name);

            Console.ReadKey();
        }

        static object MyFactory(string typeName)
        {
            object desiredType = null; //1
            switch (typeName)
            {
                case "byte": desiredType = new System.Byte(); break; //2
                case "long": desiredType = new System.Int64(); break;
                case "float": desiredType = new System.Single(); break;
                default: throw new System.NotImplementedException();
            }
            return desiredType;
        }
    }

여기서 중요한 점 : 1. Factory & AbstractFactory 메커니즘은 상속 (System.Object-> byte, float ...)을 사용해야합니다. 따라서 프로그램에 상속이 있다면 Factory (Abstract Factory는 없을 것입니다)는 이미 디자인 2에 있습니다. Creator (MyFactory)는 콘크리트 유형에 대해 알고 있으므로 콘크리트 유형 객체를 호출자 (Main)에게 반환합니다. 추상 팩토리 리턴 유형은 인터페이스입니다.

interface IVehicle { string VehicleName { get; set; } }
interface IVehicleFactory
    {
        IVehicle CreateSingleVehicle(string vehicleType);
    }
class HondaFactory : IVehicleFactory
    {
        public IVehicle CreateSingleVehicle(string vehicleType)
        {
            switch (vehicleType)
            {
                case "Sports": return new SportsBike();
                case "Regular":return new RegularBike();
                default: throw new ApplicationException(string.Format("Vehicle '{0}' cannot be created", vehicleType));
            }
        }
    }
class HeroFactory : IVehicleFactory
    {
        public IVehicle CreateSingleVehicle(string vehicleType)
        {
            switch (vehicleType)
            {
                case "Sports":  return new SportsBike();
                case "Scooty": return new Scooty();
                case "DarkHorse":return new DarkHorseBike();
                default: throw new ApplicationException(string.Format("Vehicle '{0}' cannot be created", vehicleType));
            }
        }
    }

class RegularBike : IVehicle { public string VehicleName { get { return "Regular Bike- Name"; } set { VehicleName = value; } } }
class SportsBike : IVehicle { public string VehicleName { get { return "Sports Bike- Name"; } set { VehicleName = value; } } }
class RegularScooter : IVehicle { public string VehicleName { get { return "Regular Scooter- Name"; } set { VehicleName = value; } } }
class Scooty : IVehicle { public string VehicleName { get { return "Scooty- Name"; } set { VehicleName = value; } } }
class DarkHorseBike : IVehicle { public string VehicleName { get { return "DarkHorse Bike- Name"; } set { VehicleName = value; } } }

class Program
{
    static void Main(string[] args)
    {
        IVehicleFactory honda = new HondaFactory(); //1
        RegularBike hondaRegularBike = (RegularBike)honda.CreateSingleVehicle("Regular"); //2
        SportsBike hondaSportsBike = (SportsBike)honda.CreateSingleVehicle("Sports");
        Console.WriteLine("******* Honda **********"+hondaRegularBike.VehicleName+ hondaSportsBike.VehicleName);

        IVehicleFactory hero = new HeroFactory();
        DarkHorseBike heroDarkHorseBike = (DarkHorseBike)hero.CreateSingleVehicle("DarkHorse");
        SportsBike heroSportsBike = (SportsBike)hero.CreateSingleVehicle("Sports");
        Scooty heroScooty = (Scooty)hero.CreateSingleVehicle("Scooty");
        Console.WriteLine("******* Hero **********"+heroDarkHorseBike.VehicleName + heroScooty.VehicleName+ heroSportsBike.VehicleName);

        Console.ReadKey();
    }
}

중요 사항 : 1. 요구 사항 : Honda는 "Regular", "Sports"를 생성하지만 Hero는 "DarkHorse", "Sports"및 "Scooty"를 생성합니다. 왜 두 개의 인터페이스가 필요한가? 하나는 제조업체 유형 (IVehicleFactory)이고 다른 하나는 제품 공장 (IVehicle)입니다. 2 개의 인터페이스를 이해하는 다른 방법은 추상적 팩토리가 관련 객체를 생성하는 것입니다. 2. 캐치는 IVehicleFactory의 아이들이 돌아오고 IVehicle (공장의 콘크리트 대신)입니다. 그래서 나는 부모 변수를 얻습니다 (IVehicle); 그런 다음 CreateSingleVehicle을 호출 한 다음 상위 객체를 실제 하위 객체로 캐스팅하여 실제 콘크리트 유형을 만듭니다. 내가하면 어떻게 될까 RegularBike heroRegularBike = (RegularBike)hero.CreateSingleVehicle("Regular");; ApplicationException이 발생하므로 필요한 경우 설명 할 일반 추상 팩토리가 필요합니다.


1

초록 공장 : 공장 공장; 구체적인 클래스를 지정하지 않고 개별이지만 관련 / 종속 공장을 그룹화하는 공장. 추상 팩토리 예제

팩토리 : 인스턴스화 로직을 자식 클래스에 위임하는 방법을 제공합니다. 공장 패턴 예


0

언제든지 Factory Method보다 Abstract Factory를 선호합니다. 위의 Tom Dalling의 예제 (btw 설명)에서 Abstract Factory가 더 구성 가능하다는 것을 알 수 있습니다. 우리가해야 할 일은 다른 Factory를 생성자 (여기서는 생성자 종속성 주입)에 전달하는 것입니다. 그러나 Factory Method는 새로운 클래스 (관리 할 것)를 도입하고 서브 클래 싱을 사용해야합니다. 항상 상속보다 구성을 선호합니다.


0

정확하게 넣도록하겠습니다. 대부분의 답변은 이미 다이어그램과 예제를 제공하여 설명했습니다. 그래서 내 anwer는 하나의 라이너 일 것입니다. 내 자신의 말 :- “추상 팩토리 패턴은 여러 팩토리 메소드 구현에 추상 레이어를 추가합니다. "추상 팩토리 하나 이상의 팩토리 메소드 패턴을 포함하거나 복합 함을 의미 합니다."


이것은 정확하지 않습니다. 이것은 Abstract Factory가 공장의 공장에 지나지 않는다는 잘못된 생각입니다.
jaco0646

0

위의 많은 답변은 Abstract Factory와 Factory Method 패턴 사이의 코드 비교를 제공하지 않습니다. 다음은 Java를 통해 설명하려는 시도입니다. 간단한 설명이 필요한 사람에게 도움이되기를 바랍니다.

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

        public class Client {
            public static void main(String[] args) {
               ZooFactory zooFactory = new HerbivoreZooFactory();       
               Animal animal1 = zooFactory.animal1();
               Animal animal2 = zooFactory.animal2();
               animal1.sound();
               animal2.sound();

               System.out.println();

               AnimalFactory animalFactory = new CowAnimalFactory();
               Animal animal = animalFactory.createAnimal();
               animal.sound();
            }
        }

        public interface Animal {
            public void sound();
        }

        public class Cow implements Animal {

            @Override
            public void sound() {
                System.out.println("Cow moos");
            }

        }

        public class Deer implements Animal {

            @Override
            public void sound() {
                System.out.println("Deer grunts");
            }

        }

        public class Hyena implements Animal {

            @Override
            public void sound() {
                System.out.println("Hyena.java");
            }

        }

        public class Lion implements Animal {

            @Override
            public void sound() {
                System.out.println("Lion roars");
            }

        }

        public interface ZooFactory {
            Animal animal1();

            Animal animal2();
        }

        public class CarnivoreZooFactory implements ZooFactory {

            @Override
            public Animal animal1() {
                return new Lion();
            }

            @Override
            public Animal animal2() {
                return new Hyena();
            }

        }

        public class HerbivoreZooFactory implements ZooFactory{

            @Override
            public Animal animal1() {
                return new Cow();
            }

            @Override
            public Animal animal2() {
                return new Deer();
            }

        }

        public interface AnimalFactory {
            public Animal createAnimal();
        }

        public class CowAnimalFactory implements AnimalFactory{

            @Override
            public Animal createAnimal() {
                return new Cow();
            }

        }

        public class DeerAnimalFactory implements AnimalFactory{

            @Override
            public Animal createAnimal() {
                return new Deer();
            }

        }

        public class HyenaAnimalFactory implements AnimalFactory{

            @Override
            public Animal createAnimal() {
                return new Hyena();
            }

        }

        public class LionAnimalFactory implements AnimalFactory{

            @Override
            public Animal createAnimal() {
                return new Lion();
            }

        }

이것은 정확하지 않습니다. 이 코드는 Abstract Factory가 공장의 공장 일 뿐이라는 너무 일반적인 오해를 구현합니다.
jaco0646

1
@ jaco0646 팩토리 메소드 패턴에서 초점은 FactoryImpl에서 하나의 구체적인 제품을 얻는 것입니다. 추상 팩토리 패턴에서 FactoryImpl은 팩토리 인터페이스가 계약을 제공하는 여러 유사 / 관련 콘크리트 제품을 제공합니다. 따라서 ZooFactory는 공장의 공장이 아니라, Impls가 서로 관련된 콘크리트 제품을 제공하는 인터페이스입니다. 당신이 동의하지 않으면 내 이해를 수정하십시오.
Jatin Shashoo

팩토리 메소드는 템플릿 메소드 패턴의 특수화이기 때문에 서브 클래 싱을 통한 상속에 중점을 둡니다. 위의 최고 투표 답변은 적절한 코드 예제를 보여줍니다.
jaco0646

@ jaco0646 1. 이것은 위의 예에서 AnimalFactory에 인터페이스를 사용하고 구현을 제공하는 대신 클래스를 사용하고 서브 클래스에서 createAnimal () 메소드를 대체해야 함을 의미합니다. CowAnimalFactory, LionAnimalFactory 등 ?? 2. 또한 ZooFactory에 대해 표시된 예제에 대한 의견은 무엇입니까 ??
Jatin Shashoo

첫 번째 질문 : 예. 두 번째로, 나는 개별 답변을 계속 비판하기보다는이 글에 나 자신의 답변을 추가했습니다.
jaco0646
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.