factory-pattern 메소드 - 추상 팩터 리 패턴과 팩토리 방법의 차이점




단점 템플릿 (13)

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

필자가 읽은 바에 따르면 팩토리 메서드 패턴을 사용하면 하나의 구체적인 제품을 만드는 방법을 정의 할 수 있지만 일반 제품을 볼 때 클라이언트에서 구현을 숨길 수 있습니다. 나의 첫 번째 질문은 추상적 인 공장에 관한 것이다. 하나의 구체적인 객체가 아닌 구체적인 객체의 패밀리를 만들 수있게 해주는 역할입니까? 추상 팩토리는 호출하는 메서드에 따라 매우 큰 객체 하나 또는 많은 객체 만 반환합니까?

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

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

필자가 알기로는 팩토리 메서드 패턴에 Creator 인터페이스가있어 ConcreteCreator가 인스턴스화 할 ConcreteProduct를 알 수 있도록 할 것이다. 개체 인스턴스화를 처리하기 위해 상속을 사용하면 이것이 의미하는 바입니까?

이제 해당 견적과 관련하여 Abstract Factory 패턴은 작곡을 통해 객체 인스턴스화의 책임을 다른 객체에 얼마나 위임합니까? 이것은 무엇을 의미 하는가? 초록 공장 패턴도 상속을 사용하여 내 눈에서 건설 프로세스를 수행하는 것처럼 보입니다.하지만 다시 이러한 패턴에 대해 배우고 있습니다.

특히 마지막 질문에 도움이된다면 크게 감사하겠습니다.


Answers

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

  • Factory Method 는 하나의 제품 만 생성하는 데 사용되지만 Abstract Factory 는 관련 제품 또는 종속 제품의 패밀리를 만드는 방법입니다.
  • Factory Method 패턴은 객체를 생성하기 위해 메소드를 클라이언트에 노출하는 반면, Abstract Factory의 경우에는 Factory 메소드로 구성 될 수있는 관련 객체 패밀리를 노출합니다.
  • 팩토리 메서드 패턴은 단일 객체의 구성을 숨 깁니다. 추상 팩터 리 메서드 는 관련 객체 패밀리의 구성을 숨 깁니다. 추상 팩토리는 보통 (일련의) 팩토리 메소드를 사용해 구현됩니다.
  • AbstractFactory 패턴은 composition을 사용하여 객체 생성의 책임을 다른 클래스에 위임하는 반면 Factory Design 패턴은 상속을 사용하고 파생 클래스 나 하위 클래스를 사용하여 객체를 만듭니다.
  • 팩토리 메서드 패턴의 배경은 클라이언트가 런타임에서 생성해야하는 구체적인 클래스를 모르는 경우를 허용하지만 AbstractFactory 패턴이 가장 좋은 동안 작업을 수행 할 클래스를 얻고 싶다는 것입니다 시스템이 여러 제품 군을 생성해야하거나 구현 세부 사항을 노출시키지 않고 제품 라이브러리를 제공하고자 할 때 활용됩니다.

공장 방법 패턴 구현 :

AbstractFactory 패턴 구현 :


두 사람의 차이점

"팩토리 메서드"와 "추상 팩터 리"의 주요 차이점은 팩토리 메서드가 단일 메서드이며 추상 팩터 리가 개체라는 점입니다. 나는 많은 사람들이이 두 용어를 혼란스럽게 만들고 그것들을 서로 바꾸어 사용하기 시작한다고 생각한다. 내가 그걸 배웠을 때 그 차이가 무엇인지 정확히 알아 내기 힘들었던 것을 기억합니다.

팩토리 메소드는 단지 메소드 일 뿐이므로 서브 클래스에서 오버라이드 될 수 있습니다. 따라서 상 인용의 후반 부분에서 오버라이드 될 수 있습니다.

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

이 인용문은 객체가 여기에서 자체 factory 메소드를 호출한다고 가정합니다. 따라서 반환 값을 변경할 수있는 유일한 것은 하위 클래스입니다.

abstract 팩토리는, 거기에 복수의 팩토리 메소드를 가지는 오브젝트입니다. 견적의 전반부를 살펴보면 :

... 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

실생활의 예. (기억하기 쉽다)

공장

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

초록 공장

자, 같은 문 예를 생각해보십시오. 목수에 가거나 플라스틱 문앞이나 PVC 가게에 갈 수 있습니다. 모두 문고리 공장입니다. 상황에 따라 어떤 종류의 공장에 접근해야하는지 결정합니다. 이것은 추상 공장과 같습니다.

여기에서는 팩토리 메서드 패턴과 추상 팩터 리 패턴을 모두 설명했지만 문제를 설명하지 않고 위의 패턴을 사용하여 문제를 해결했습니다. https://github.com/vikramnagineni/Design-Patterns/tree/master


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

객체를 가지고 있고 객체의 상호 관계를 구체적으로 구현 한 툴을 구축한다고 가정합니다. 객체의 변형을 예측하기 때문에 객체의 변형을 만드는 책임을 다른 객체에 할당하여 간접 참조를 작성 했습니다 ( 우리는 추상 팩토리라고 부릅니다 ). 이러한 추상화는 이러한 객체의 변형을 필요로하는 향후 확장을 예측하므로 강력한 이점이 있습니다.

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

GoF에서 아이디어를 빌리는 간단한 GUI 애플리케이션은 MS 또는 Mac 또는 Fedora OS의 룩앤필을 에뮬레이트하는 가상 모니터라고합니다. 예를 들어 윈도우, 버튼 등과 같은 모든 위젯 객체가 MAC 변형에서 파생 된 스크롤 막대를 제외하고 MS 변형을 가지고있을 때 도구의 목적은 나쁘게 실패합니다.

위의 경우는 추상 팩터 리 패턴 의 기본적인 필요성을 형성합니다.

다른 한편으로, 프레임 워크를 작성하여 많은 사람들이 프레임 워크를 사용하여 다양한 도구 ( 예 : 위의 예제와 같이 )를 작성할 수 있다고 가정 해보십시오. 프레임 워크라는 개념에 의해, 당신은 당신의 논리에서 구체적인 객체를 사용할 수는 없지만 그렇게 할 필요는 없습니다. 오히려 다양한 오브젝트 사이에 몇 가지 상위 레벨 계약을 맺고 어떻게 상호 작용하는지. 프레임 워크 개발자로서 매우 추상적 인 수준을 유지 하는 동안 도구의 각 빌더는 프레임 워크 구조를 따라야합니다. 그러나 도구 작성자 는 어떤 개체를 만들지 결정하고 개체가 만드는 모든 개체가 상호 작용할 방법을 자유롭게 결정할 수 있습니다. 이전 사례 ( 추상 팩토리 패턴 )와 달리, 프레임 워크 작성자로서이 경우 구체적인 객체로 작업 할 필요가 없습니다. 오히려 객체의 계약 수준에 머무를 수 있습니다. 또한, 이전 동기의 두 번째 부분과 달리, 당신이나 도구 작성자는 변형 된 객체를 혼합하는 상황을 결코 가질 수 없습니다. 여기서 프레임 워크 코드는 계약 수준으로 유지되지만 모든 도구 작성자는 자체 사례의 특성에 따라 자체 개체 사용이 제한됩니다. 이 경우 개체 생성은 각 구현 자에게 위임되며 프레임 워크 공급자는 개체를 만들고 반환하기위한 균일 한 메서드 만 제공합니다. 이러한 메소드는 프레임 워크 개발자가 코드를 진행하는 데 필연적이며 팩토리 메소드 ( 기본 패턴의 팩토리 메소드 패턴) 라는 특수한 이름이 있습니다.

몇 가지주의 사항 :

  • '템플릿 메소드'에 익숙하다면 어떤 프레임 워크 형태에 속하는 프로그램의 경우에도 템플릿 메소드에서 팩토리 메소드가 호출되는 것을 볼 수 있습니다. 반대로, 응용 프로그램의 템플릿 방법은 종종 특정 알고리즘의 단순 구현이며 공장 방법의 무효입니다.
  • 또한, 위에서 언급 한 프레임 워크를 사용하여 사고의 완성을 위해, 툴 빌더가 툴을 구축 할 때 각 팩토리 메소드 내에서 구체적인 객체를 생성하는 대신 책임을 추상적으로 위임 할 수 있습니다 도구 빌더는 향후 확장을 위해 구체적인 객체의 변형을 예견 할 수 있어야합니다.

샘플 코드 :

//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
    }
    ….
}

언제든지 Factory Methods를 통해 Abstract Factory를 선호 할 것입니다. 위의 Tom Dalling의 예제 (훌륭한 설명 btw)에서 우리는 추상 팩토리가 더 복잡하다는 것을 알 수 있습니다. 우리가해야 할 일은 생성자에 다른 팩토리를 전달하는 것입니다 (여기에서 사용되는 생성자 종속성 주입). 그러나 Factory Method는 우리가 새로운 클래스 (더 많은 것들을 관리)를 소개하고 서브 클래 싱을 사용해야한다고 요구합니다. 상속보다 컴포지션을 항상 선호합니다.


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

팩토리 메서드 는 클래스에서 객체를 만드는 데 사용되는 단순한 메서드입니다. 일반적으로 집계 루트에 추가됩니다 ( 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 인터페이스의 목적을 IHttpRequest 하는 특정 구현 클래스를 사용해야 할 것입니다.

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

개요

차이점은 팩토리 메소드를 포함하는 클래스의 의도 된 목적객체를 생성하지 않는 반면 추상 팩토리는 객체를 생성하는 데에만 사용해야한다는 것입니다.

객체를 만들 때 LSP ( Liskovs 대체 원칙 )를 깨기 쉽기 때문에 팩토리 메소드를 사용할 때는주의해야합니다.


쉬운 이해를 위해이 예제를 고려하십시오.

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

일반적으로 여기에서하는 일은 광대역, 전화선 및 모바일과 같은 제품을 만드는 것입니다. 공장 방법을 통해 제품의 특성을 알 수 있습니다.

이제 회사는 고객에게 광대역, 전화선 및 모바일 등의 제품 번들을 제공하기를 원하며 Abstract Factory 가 제공됩니다.

Abstract Factory 는 다시 말해서 자신의 제품을 만드는 책임이있는 다른 공장의 구성이며 Abstract Factory 는 이러한 제품을 자신의 책임과 관련하여보다 의미있는 방법으로 배치하는 방법을 알고 있습니다.

이 경우 BundleFactory 는 Abstract Factory, BroadbandFactory , PhonelineFactoryMobileFactoryFactory 입니다. 간단히 말하면,이 팩토리에는 개별 제품을 초기화하는 팩토리 메소드 가 있습니다.

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

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
    }
}

위의 답변 중 많은 부분은 추상 팩토리와 팩토리 메서드 패턴 간의 코드 비교를 제공하지 않습니다. 다음은 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();
            }

        }

최소한의 인터페이스로 매우 간단하게 만들고 "// 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)는 concrete 타입을 알고 있으므로, caller (Main)에게 concrete 타입 객체를 반환합니다. 추상적 인 팩토리 리턴 타입은 Interface이다.

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"를 만들 것입니다. 2. 왜 두 인터페이스? 하나는 제조업체 유형 (IVehicleFactory)이고 다른 하나는 제품 공장 (IVehicle) 용입니다. 2 개의 인터페이스를 이해하는 다른 방법은 추상적 인 팩토리는 관련된 객체를 만드는 것입니다. 2. catch는 IVehicleFactory의 자식 반환 및 IVehicle (공장의 콘크리트 대신)입니다. 그래서 부모 변수 (IVehicle)를 얻습니다. CreateSingleVehicle을 호출 한 다음 실제 자식 개체에 부모 개체를 캐스팅하여 실제 구체적인 형식을 만듭니다. RegularBike heroRegularBike = (RegularBike)hero.CreateSingleVehicle("Regular"); ; 당신은 ApplicationException을 얻을 것이고, 그래서 우리는 필연적으로 설명 할 일반 추상 팩토리가 필요합니다. 희망은 초급에서 중급의 시청자에게 도움이되기를 바랍니다.


내가 정확하게 그것을 넣어 수 있습니다. 대부분의 해답은 다이어그램과 예제를 제공하여 이미 설명했습니다. 그래서 내 anwer는 단지 하나의 라이너가 될 것입니다. 내 자신의 말 : "추상 팩터 리 패턴은 여러 팩토리 메소드 구현에 대한 추상 레이어에 추가됩니다. 추상 팩토리 1 개 또는 복수의 팩토리 메소드 패턴을 포함 또는 합성하고있는 것을 의미한다 "


생산 코드의 대부분은 클래스 A가 인터페이스 B로 프로그램되어 있기 때문에 추상적 인 팩토리 패턴을 사용한다는 것을 분명히 알리십시오. 그리고 A는 B의 인스턴스를 생성해야합니다. 따라서 A는 B의 인스턴스를 생성하는 팩토리 객체를 가져야합니다 그래서 A는 B의 구체적인 인스턴스에 의존하지 않습니다. 도움이 되길 바랍니다.


Abstract Factory와 Factory Method의 주요 차이점은 Abstract Factory는 Composition에 의해 구현 된다는 점입니다. Factory Method는 상속에 의해 구현됩니다 .

네, 올바르게 읽었습니다.이 두 패턴의 주요 차이점은 오래된 구성 대 상속 논쟁입니다.

나는 여러 곳에서 볼 수있는 UML 다이어그램을 여기서 재현하지 않을 것이다. 코드 예제를 제공하고 싶습니다. 그러나이 스레드에서 상위 2 개 답변의 예제를 결합하면 두 가지 답변 중 하나보다 더 나은 데모가 제공됩니다. 또한 (GoF) 서적에 사용 된 용어를 클래스 및 메소드 이름에 추가했습니다.

초록 공장

  1. 여기서 가장 중요한 점은 추상 팩토리가 클라이언트에 삽입 된다는 것입니다. 이것이 추상적 인 공장이 작곡으로 구현되었다고 말하는 이유입니다. 종종 의존성 주입 프레임 워크가 해당 작업을 수행합니다. 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() 정의하는 서브 클래스입니다. 이것이 Factory Method가 상속으로 구현되었다고 말하는 이유입니다.
  2. 두 번째 중요한 점은 팩토리 메서드 패턴이 템플릿 메서드 패턴의 특수화에 지나지 않음을 기억하는 것입니다. 두 패턴은 동일한 구조를 공유합니다. 그들은 단지 목적이 다릅니다. 팩토리 메쏘드는 창조적입니다 (무언가를 만듭니다) 반면에 템플리트 메쏘드는 행동 적입니다 (무언가를 계산합니다).
  3. 마지막으로, 세 번째 요점은 Creator (상위) 클래스가 자체 factoryMethod() 호출한다는 점입니다. 부모 클래스에서 anOperation() 을 제거하고 하나의 메소드 만 남겨두면 더 이상 팩토리 메소드 패턴이 아닙니다. 즉, 팩토리 메소드는 상위 클래스에서 2 개 미만의 메소드로 구현 될 수 없습니다. 하나는 다른 하나를 호출해야합니다.
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();
    }
}

기타. & 잡화 공장 패턴

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

모든 공장 ​​패턴이 GoF의 패턴과 일치해야한다고 가정하는 함정에 빠지지 마십시오.


나는 명심해야 할 가장 중요한 것 : 충분히 설명하는 이름인가? 클래스가 무엇을해야하는지에 대한 이름을 보면서 말할 수 있습니까? 클래스 이름에 "Manager", "Service"또는 "Handler"와 같은 단어를 사용하는 것은 너무 일반적인 것으로 간주 될 수 있지만 많은 프로그래머가 사용하므로 클래스의 용도를 이해하는 데 도움이됩니다.

저는 제 자신이 facade-pattern을 많이 사용하고 있습니다 (적어도, 그것이 그것이라고 불리는 것입니다). 한 User 를 설명하는 User 클래스와 "사용자 컬렉션"을 추적하는 Users 클래스를 가질 수 있습니다. 실생활에서 관리자가 마음에 들지 않아 클래스를 UserManager 라고 부르지는 않습니다. 그리고 나는 그것들을 생각 나게하고 싶지 않습니다 :) 단순히 복수형을 사용하면 클래스가하는 것을 이해하는 데 도움이됩니다.