팩토리 메소드 패턴 c. 팩토리 메소드 패턴 - 클래스 수준. 팩토리 메소드 설명




팩토리 메소드를 사용하면 서브클래스가 공통 인터페이스를 사용하여 일부 클래스를 생성할 수 있으며, 서브클래스는 구현해야 할 상위 객체를 결정합니다. 즉, 일종의 공통 인터페이스가 필요합니다. C# 프로그래밍 언어의 이 인터페이스는 추상 클래스 또는 인터페이스일 수 있습니다.

다음과 같은 추상 클래스를 상상해 보세요.

추상 클래스 제품( 공개 추상 십진수 BuyPrice(get; set;) 공개 추상 십진수 가격(get; 설정;) 공개 추상 문자열 설명(get; set;) )

이 클래스를 상속받으려면 다형성 원칙을 준수해야 합니다. 즉, 재정의라는 단어를 사용하여 이 클래스의 모든 속성을 재정의합니다. 그걸하자. 특정 제품의 논리를 캡슐화하는 Product 클래스에서 상속된 클래스를 만듭니다.

클래스 컴퓨터: 제품( 개인 십진수 _구매_가격; 개인 십진수 _price; 개인 문자열 _description; 공용 컴퓨터() : this(null) ( ) 공용 컴퓨터(문자열 _description) : this(_description, 0) ( ) 공용 컴퓨터(문자열 _설명, 십진수) _purchase_price) : this (_description, _purchase_price, 0) ( ) public Computer(string _description, 소수점 _purchase_price, 소수점 _price) ( this._description = _description; this._purchase_price = _purchase_price; this._price = _price; ) 공개 재정의 문자열 설명 ( get( return _description; ) set( _description = value; ) ) 공개 재정의 십진수 Price( get( return _price; ) set( _price = value; ) ) 공개 재정의 십진수 BuyPrice( get( return _purchase_price; ) set( _purchase_price = value; ) ) )

Product 클래스는 팩토리 메소드에 의해 생성된 객체의 인터페이스를 정의하기 위한 것입니다. 이는 제품의 기본 쉘과 같습니다. 상품에는 가격 등이 있습니다. 원하는 경우 Product 클래스에 몇 가지 추가 속성과 메서드를 추가하고 상속된 클래스에서 다시 정의합니다. 지금은 모든 것이 명확해지기를 바랍니다. 계속하기 전에 패턴 자체에 대해 몇 마디 말씀드리겠습니다. 일반적으로 우리는 구체적인 클래스를 사용하고 다음과 같이 작성합니다.

컴퓨터 컴퓨터 = 새 컴퓨터();

그러나 이 패턴은 프로그램 텍스트에서 특정 클래스가 아닌 추상 표현으로 작업할 수 있음을 나타냅니다. 여기에 논의된 패턴을 사용하는 것이 적합한 가장 일반적인 사례는 다음과 같습니다.

  • 하위 클래스를 생성하는 클래스는 하위 클래스가 무엇인지 미리 알 수 없습니다.
  • 클래스는 자신이 생성하는 객체가 하위 클래스에 의해 지정되도록 설계되었습니다.
  • 클래스는 자신의 책임을 보조 하위 클래스 중 하나에 위임한 후 어떤 클래스가 이러한 책임을 맡는지에 대한 지식을 지역화할 계획입니다.

의미는 다음과 같습니다.

다이어그램에 두 개의 클래스가 더 추가되었습니다. 패턴을 따르면 팩토리 메소드를 포함하는 또 다른 추상 클래스가 있어야 합니다. 특정 유형의 제품을 생산하는 공장과 같습니다. 팩토리 메소드가 포함된 추상 클래스 Creator가 정의되면 특정 제품에 대해 고유한 상속 클래스를 만들 수 있습니다. 이해하기 쉽도록 다이어그램을 단순화해 보겠습니다.

그게 전부 파이입니다. 추상적인 제품과 팩토리 메소드를 갖는 생성자 클래스가 있습니다. 특정 제품( Product 에서 상속됨) 경주에 대한 클래스를 생성하고, 특정 제품( Creator 에서 상속됨)의 제작자를 위한 특정 클래스를 생성합니다.

추상 클래스 Creator는 다음과 같습니다.

추상 클래스 생성자( 공개 추상 Product FactoryMethod(); 공개 추상 Product FactoryMethod(string _description); 공개 추상 Product FactoryMethod(string _description, 소수점 _purchase_price); 공개 추상 Product FactoryMethod(string _description, 소수점 _purchase_price, 소수점 _price); ) 이 클래스에서는 Computer 클래스의 모든 종류의 생성자에 대한 메서드를 정의했습니다. 다음은 Computer 클래스에 대한 생성자 클래스입니다. class ComputerCreator: Creator ( public override Product FactoryMethod() ( return new Computer(); ) public override Product FactoryMethod(string _description) ( return new Computer(_description); ) public override Product FactoryMethod( 문자열 _description, 소수 _purchase_price) ( 새 컴퓨터 반환(_description, _purchase_price); ) 공개 재정의 Product FactoryMethod(string _description, 소수 _purchase_price, 소수 _price) ( 반환 새 컴퓨터(_description,_purchase_price,_price); ) )

이제 모든 것이 그림과 같습니다. 1. Computer 클래스의 필수 생성자를 호출할 수 있도록 팩토리 메소드가 오버로드되어 있음을 알 수 있습니다.

비슷한 방식으로 또 다른 CDPlayer 클래스와 이를 위한 생성자 클래스를 만들어 보겠습니다.

CDPlayer 클래스:

클래스 CDPlayer: 제품( 개인 소수점 _purchase_price; // 구매 가격 개인 소수점 _price; // 판매 가격 // CD 플레이어가 지원하는 형식의 배열 개인 문자열 _description; public CDPlayer() : this(null) ( ) public CDPlayer(string _description ) : this(_description, 0) ( ) public CDPlayer(string _description, 소수점 _purchase_price) : this(_description, _purchase_price, 0) ( ) public CDPlayer(string _description, 소수점 _purchase_price, 소수점 _price) ( this._description = _description; this ._purchase_price = _purchase_price; this._price = _price; ) 공개 재정의 문자열 설명 ( get ( return _description; ) set ( _description = value; ) ) 공개 재정의 소수 가격 ( get ( return _price; ) set( _price = value;) ) 공개 재정의 십진수 BuyPrice ( get ( return _purchase_price; ) set ( _purchase_price = value;) ) )

CDPlayer 클래스의 Creator 클래스:

클래스 CDPlayerCreator: Creator ( 공개 재정의 Product FactoryMethod() ( 새 CDPlayer() 반환; ) 공개 재정의 Product FactoryMethod(string _description) ( 새 CDPlayer(_description) 반환; ) 공개 재정의 Product FactoryMethod(string _description, 십진수 _purchase_price) ( 새 반환 CDPlayer(_description, _purchase_price); ) 공개 재정의 Product FactoryMethod(string _description, 소수점 _purchase_price, 소수점 _price) ( return new CDPlayer(_description, _purchase_price, _price); ) )

우리에게 남은 것은 우리의 작업에 감탄할 클라이언트 코드를 작성하는 것뿐입니다.

정적 무효 Main(string args) ( 목록 ProductList = 새 목록 (); 크리에이터 크리에이터 = 새로운 크리에이터; 제작자 = 새로운 ComputerCreator(); creators = 새로운 CDPlayerCreator(); foreach (크리에이터의 크리에이터 cr) ( if (cr은 ComputerCreator입니다) productList.Add(cr.FactoryMethod("Laptop", 600, 800)); if (cr은 CDPlayerCreator입니다) productList.Add(cr.FactoryMethod("audio, mp3 ,mp4",250,360)); ) foreach (productList의 제품 홍보) ( Console.WriteLine("클래스 개체 (0);\n" + "설명: (1);\n" + "구매 가격: (2 ) ;\n" + "판매 가격: (3);\n", pr.GetType().Name, pr.Description, pr.PurchasePrice, pr.Price); ) Console.ReadLine(); )

프로그램 결과는 다음과 같습니다.

나에게는 이것이 흥미로운 사실이다. 추상 클래스의 인스턴스를 만들 수 없습니다.그러나 아무도 그것이 기본 역할을 할 수 없다고 말하지 않았습니다. 다음과 같이 작성하면 모든 것이 잘 될 것입니다.

제품 홍보 = 새 컴퓨터();

링크는 여기 홍보(추상 클래스)는 Computer 클래스의 개체를 나타냅니다. 이러한 이유로 예전처럼 전문적인 컬렉션을 쉽게 만들 수 있습니다. 이 템플릿을 보고 즉시 다음과 같은 개발 단계를 알아차렸습니다.

  • 객체에 대한 추상 클래스 -> 반대로 자신의 목적에 맞게 구현하는 클래스입니다.
  • 객체를 생성하기 위한 추상 클래스 -> 반대로 이를 구현하여 자신의 객체를 생성하는 클래스입니다.
다시 말해서:

제품- 제품 자체. 팩토리 메소드로 생성된 객체의 인터페이스를 정의하도록 설계되었습니다.

콘크리트제품(컴퓨터, CDPlayer) - 계획에 참여하고 추상 클래스(인터페이스) 구현을 담당하는 특정 제품입니다.

창조자창조주이시니 그의 이름이 그 자체로 말하느니라. 이 객체는 Product 유형의 객체를 반환하는 팩토리 메서드를 선언하기 위한 것입니다.

콘크리트크리에이터- 특정 창작자. 여기에서 모든 것이 분명합니다. 제작자의 특정 구현은 특정 제품 반환에 참여합니다. 이 예에서 두 가지 구체적인 생성자 구현은 ComputerCreator와 CDPlayerCreator입니다.

작성자는 적절한 특정 제품을 구현하기 위해 하위 클래스를 신뢰합니다. 그게 요점이야 팩토리 메소드.

이제 이 패턴의 장점과 단점을 살펴보겠습니다.

팩토리 메소드의 가장 명백한 단점은 새로운 유형의 제품(즉, 새로운 ConcreteProduct)을 얻을 계획을 세울 때마다 Creator 후속 제품을 생성해야 한다는 것입니다. 그리고 아쉽게도 이것은 피할 수 없습니다. 그러나 비슷한 문제가 많은 생성 패턴에 존재합니다. 장점에는 특정 클래스에 초점을 맞추지 않고 공통 인터페이스를 사용하지 않고 보다 보편적으로 객체를 생성할 수 있는 기능이 포함됩니다.

1. 이름: 팩토리 메소드

2. 임무:

    시스템은 새로운 유형의 객체를 추가하여 확장성을 유지해야 합니다. new 표현식을 직접 사용하는 것은 특정 유형의 객체를 생성하는 코드가 애플리케이션 전체에 분산될 수 있으므로 권장되지 않습니다. 그러면 시스템에 새로운 유형의 객체를 추가하거나 한 유형의 객체를 다른 유형으로 바꾸는 것과 같은 작업이 어려울 것입니다(자세한 내용은 섹션 참조). 생성 패턴). 팩토리 메소드 패턴을 사용하면 시스템이 객체 생성 프로세스와 해당 유형 모두에 독립적으로 유지될 수 있습니다.

    객체를 언제 생성할지 미리 알 수 있지만 그 유형은 알 수 없습니다.

3. 해결책:

시스템이 다양한 객체 유형과 독립적으로 유지되도록 하기 위해 팩토리 메소드 패턴은 다형성 메커니즘을 사용합니다. 즉, 모든 최종 유형의 클래스는 다형성 사용을 위해 의도된 하나의 추상 기본 클래스에서 상속됩니다. 이 기본 클래스는 사용자가 최종 유형의 객체를 조작하는 데 사용할 단일 인터페이스를 정의합니다.

시스템에 새로운 유형을 비교적 쉽게 추가할 수 있도록 팩토리 메소드 패턴은 특수 팩토리 클래스에서 특정 유형의 객체 생성을 지역화합니다. 특정 클래스의 객체를 생성하는 이 클래스의 메소드를 팩토리 메소드(Factory Method)라고 합니다.

팩토리 메소드의 인터페이스는 독립된 팩토리 클래스에서 선언되며 해당 구현은 이 클래스의 특정 하위 클래스에 의해 결정됩니다.

4. 팩토리 메소드 패턴의 UML 클래스 다이어그램. 클래식 구현

제품- 제품 자체. 팩토리 메소드로 생성된 객체의 인터페이스를 정의하도록 설계되었습니다.

콘크리트제품(컴퓨터) - 계획에 참여하고 추상 클래스(인터페이스) 제품 구현을 담당하는 특정 제품입니다.

창조자창조주이시니 그의 이름이 그 자체로 말하느니라. 이 객체는 Product 유형의 객체를 반환하는 팩토리 메서드를 선언하기 위한 것입니다.

콘크리트크리에이터- 특정 창작자. 여기에서 모든 것이 분명합니다. 제작자의 특정 구현은 특정 제품 반환에 참여합니다. 이 예에서 작성자의 구체적인 구현은 ComputerCreator입니다.

작성자는 적절한 특정 제품을 구현하기 위해 하위 클래스를 신뢰합니다. 그게 요점이야 팩토리 메소드.

5. 팩토리 메소드 구현의 예:

Product 클래스는 팩토리 메소드에 의해 생성된 객체의 인터페이스를 정의하기 위한 것입니다. 이는 제품의 기본 쉘과 같습니다. 상품에는 가격 등이 있습니다.

    추상적인 수업제품

    공공의 추상적인 소수구매 가격( 얻다; 세트;}

    공공의 추상적인 소수가격 ( 얻다; 세트;}

    공공의 추상적인 설명 ( 얻다; 세트;}

특정 제품의 논리를 캡슐화하는 Product 클래스에서 상속된 클래스를 만듭니다.

    수업컴퓨터: 제품

    사적인 소수 _구매 가격;

    사적인 소수 _가격;

    사적인 _설명;

    공공의컴퓨터( _설명, 소수 _구매 가격,

    소수 _가격)

    이것._설명 = _설명;

    이것._구매_가격 = _구매_가격;

    이것._가격 = _가격;

    공공의 우세하다 설명

    얻다 { 반품 _설명; )

    세트( _설명 = 값; )

    공공의 우세하다 소수가격

    얻다 { 반품 _가격; )

    세트( _가격 = 가치; )

    공공의 우세하다 소수구매 가격

    얻다 { 반품 _구매 가격; )

    세트( _구매_가격 = 가치; )

팩토리 메소드가 있는 추상 생성자 클래스를 설명하겠습니다.

    추상적인 수업창조자

    공공의 추상적인제품공장방식( _설명,

    소수 _구매 가격, 소수 _가격);

특정 제품의 제작자를 위한 특정 클래스를 만듭니다(Creator에서 상속됨). 이 클래스는 Computer 클래스의 생성자에 대한 메서드를 정의합니다. 생성자가 여러 개인 경우 각 생성자에는 자체 팩토리 메서드가 있습니다.

    수업 ComputerCreator: 창조자

    공공의 우세하다제품공장방식( _설명,

    소수 _구매 가격, 소수 _가격)

    반품 새로운컴퓨터(_설명,_구매_가격,_가격);

클라이언트 코드:

    공전 무효의기본( 인수)

    목록 제품목록 = 새로운목록

    크리에이터 크리에이터 = 새로운창조자;

    창작자 = 새로운컴퓨터크리에이터();

    각각(크리에이터 cr ~에크리에이터)

    만약에(cr ~이다컴퓨터크리에이터)

    productList.Add(cr.FactoryMethod("노트북", 600, 800));

    각각(제품 홍보 ~에상품 목록)

    Console.WriteLine("클래스 객체 (0);\n" +

    "설명: (1);\n" +

    "구매 가격: (2);\n" +

    "판매 가격: (3);\n",

    pr.GetType().이름,

  1. pr.구매가격,

프로그램 결과:

6. 이 패턴의 장점과 단점:

팩토리 메소드의 가장 명백한 단점은 새로운 유형의 제품(즉, 새로운 ConcreteProduct)을 얻을 계획을 세울 때마다 Creator 후속 제품을 생성해야 한다는 것입니다. 그리고 아쉽게도 이것은 피할 수 없습니다. 그러나 비슷한 문제가 많은 생성 패턴에 존재합니다. 장점에는 특정 클래스에 초점을 맞추지 않고 공통 인터페이스를 사용하지 않고 보다 보편적으로 객체를 생성할 수 있는 기능이 포함됩니다.

팩토리 메소드- 클래스를 생성하는 패턴 - 참조 생성 패턴(템플릿)

목적

객체를 생성하기 위한 인터페이스를 정의하지만 인스턴스화할 클래스(제품)를 결정하는 것은 하위 클래스에 맡깁니다.
팩토리 메소드를 사용하면 클래스가 인스턴스화를 하위 클래스에 위임할 수 있습니다.

별명

팩토리 메소드 패턴은 VirtualConstructor라고도 합니다.

동기 부여

신청을 해보자 - 글쎄, 아니면 우리가 쓰고 싶은데 -그럴 수 있다는 게 무슨 뜻이야? 다양한 유형의 문서 만들기- 하지만 어떤 종류의 문서인지 미리 알 수 없습니다 (= 제품)사용자가 선택합니다-
그러나 외부에서 보면 이러한 문서를 생성하는 메커니즘은 유사해 보입니다. 이 유사성은 추상 클래스로 설명되는 반면 추상 클래스는 인스턴스화할 수 없습니다. 즉, 이러한 클래스의 개체를 생성할 수 없습니다.
어떻게 될까요?

패턴은 우리에게 해결책을 제공합니다 팩토리 메소드, 이를 생성하는 애플리케이션 클래스에서 특정 문서의 이름을 숨깁니다.

보시다시피, 여기서는 개체 계층 구조, 또는 오히려 두 개의 병렬 계층 구조, 즉 제품 계층 구조와 이러한 제품 작성자의 계층 구조를 구축하는 것이 제안되었습니다.

그건 그렇고, 이것은 다음 무료 다이어그램으로 더 명확하게 설명됩니다.

적용 가능성

다음과 같은 경우 팩토리 메서드 패턴을 사용하세요.

  1. 수업 어떤 클래스의 어떤 객체를 생성해야 하는지 미리 알 수 없습니다.
  2. 수업은 다음과 같이 설계되었습니다. 생성된 객체는 하위 클래스에 의해 지정됩니다.;
  3. 클래스는 여러 도우미 하위 클래스 중 하나에 책임을 위임하고 계획을 세웁니다. 어떤 클래스가 이러한 책임을 맡는지에 대한 지식을 현지화합니다.

구조

이 템플릿의 구조는 다음 다이어그램으로 나타낼 수 있습니다.

참가자들

  1. 제품(문서) - 제품: 팩토리 메소드로 생성된 객체의 인터페이스를 정의합니다.
  2. 콘크리트제품(MyDocument) 특정 제품: 인터페이스제품을 구현합니다.
  3. 창조자(애플리케이션) = 생성자: Product 유형의 객체를 반환하는 팩토리 메서드를 선언합니다. 창조자 팩토리 메소드의 기본 구현을 정의할 수도 있습니다. ConcreteProduct 객체를 반환합니다. Product 객체를 생성하기 위해 팩토리 메소드를 호출할 수 있습니다.
  4. 콘크리트크리에이터(MyApplication) = 구체적인 생성자: ConcreteProduct 개체를 반환하는 팩토리 메서드를 재정의합니다.

관계

창조자 하위 클래스에 "의존"(특정 Creator 구현) 적절한 특정 제품의 인스턴스를 반환하는 팩토리 메서드를 정의합니다.

결과

팩토리 메소드 디자이너가 애플리케이션 종속 클래스를 코드에 포함해야 하는 필요성을 덜어줍니다.코드는 Product 클래스 인터페이스만 다루므로 사용자가 정의한 구체적인 제품 클래스와 함께 작동할 수 있습니다.

잠재적인 단점

팩토리 메소드의 잠재적인 단점은 클라이언트가 단 하나의 ConcreteProduct 객체를 생성하기 위해 Creator를 하위 클래스로 분류해야 할 수도 있다는 것입니다. 클라이언트가 어떻게든 Creator의 하위 클래스를 생성해야 하는 경우 하위 클래스 지정이 정당화됩니다.그렇지 않으면 클라이언트에게 서브클래스의 추가 레이어를 처리해야 합니다.

frabrik 메서드 패턴을 적용할 수 있는 두 가지 추가 기능은 다음과 같습니다.

후크 작업으로 하위 클래스 제공

팩토리 메소드를 사용하여 클래스 내부에 객체를 생성하는 것은 직접 생성하는 것보다 항상 더 유연합니다. 팩토리 메소드는 하위 클래스에 후크 작업을 생성하여 확장 버전을 제공합니다.
물체.

문서 예제에서 Document 클래스는 기존 문서에서 파일을 선택하기 위한 대화 상자를 만드는 CreateFileDialog 팩터리 메서드를 정의할 수 있습니다. 이 클래스의 하위 클래스는 다음을 정의할 수 있습니다.
이 팩토리 메서드를 대체하는 응용 프로그램별 대화 상자입니다. 이 경우 팩토리 메소드는 추상이 아니지만 합리적인 기본 구현을 포함합니다.

팩토리 메소드는 작성자만 호출할 수 있는 것이 아닙니다. 클라이언트도 팩토리 메소드를 사용할 수 있습니다, 특히 면전에서.

예를 들어 마우스를 사용하여 늘리거나 이동하거나 회전하는 등 대화형으로 조작할 수 있는 그래픽 모양을 생각해 보세요.
이러한 사용자 상호 작용을 구현하는 것이 항상 쉬운 것은 아닙니다. 현재 조작 상태에 대한 정보를 저장하고 업데이트해야 하는 경우가 많습니다. 하지만 이 상태는 조작 자체 중에만 필요하므로 도형을 나타내는 객체에 배치하면 안 됩니다. 또한, 수치는 다음과 같이 동작합니다.

예를 들어, 세그먼트를 늘이는 것은 끝점의 위치를 ​​변경하는 것으로 축소될 수 있고, 텍스트를 늘이는 것은 끝점의 위치를 ​​변경하는 것으로 축소될 수 있습니다.
줄 간격.

이러한 제한으로 인해 상호 작용을 구현하고 현재 상태를 제어하는 ​​별도의 Manipulator 객체를 사용하는 것이 더 좋습니다. 모양에 따라 Manipulator의 하위 클래스인 Manipulator가 달라집니다. Manipulator 클래스의 결과 계층 구조는 Figure 클래스의 계층 구조와 (적어도 부분적으로) 유사합니다. Figure 클래스는 클라이언트가 Figure에 해당하는 조작기를 생성할 수 있도록 하는 CreateManipulator 팩토리 메서드를 제공합니다. Figure의 하위 클래스는 적절한 Manipulator 하위 클래스를 반환하도록 이 메서드를 재정의합니다. 대신 Figure 클래스는 CreateManipulator를 구현하여 Manipulator 클래스의 기본 인스턴스를 반환하고 Figure 하위 클래스는 상속할 수 있습니다.
이는 기본값입니다.

설명된 원리에 따라 기능하는 모양 클래스에는 특별한 조작자가 필요하지 않으므로 계층 구조는
부분적으로만 평행합니다. 팩토리 메소드가 둘 사이의 연결을 어떻게 정의하는지 주목하세요.
클래스 계층. 여기에는 어떤 클래스가 함께 작업할 수 있는지에 대한 지식이 포함되어 있습니다.

다이어그램은 다음과 같습니다.

다시 한번 (결과에 대해):

  1. 팩토리 메소드를 사용하면 디자이너가 애플리케이션별 클래스를 코드에 구축할 필요가 없습니다.
  2. 당신은 만들 수 있습니다 (만약 원한다면)확장 객체 - 추상 생성자의 특정 구현을 재정의할 수 있도록 허용 - 필요한 경우 여러 메서드(파일 대화 상자의 예에서와 같이)
  3. 병렬 계층의 연결

구현

이 섹션에서는 구현 기능을 언급할 가치가 있으며 다음과 같습니다.

  • 구현에는 두 가지 기본 사례가 있습니다.
    1. 작성자 클래스가 추상인 경우
    2. Creator가 구체적인("일반") 클래스인 경우
    3. 글쎄, 여전히 혼합 유형이 있습니다. 추상 클래스에 기본 구현이 포함되어 있는 경우
  • 매개변수화된 팩토리 메소드- 이 기능은 일반적으로 팩토리 메소드를 사용하여 전달된 매개변수에 따라 다양한 유형의 제품을 생성할 수 있음을 의미합니다.
  • 특정 구현 언어와 관련된 다양한 기능

샘플 코드

알려진 응용 프로그램

팩토리 메소드는 어디에서나 발견됩니다. 대부분의 라이브러리와 프레임워크는 어떤 방식으로든 팩토리 메서드 패턴을 사용합니다.- 특히 ET++ 라이브러리

관련 패턴

종종 팩토리 메소드를 사용하여 구현됩니다.

추상 팩토리 설명의 동기 부여 섹션에 있는 예제도 팩토리 메소드 패턴을 보여줍니다.
팩토리 메서드 패턴은 종종 템플릿 메서드 내에서 호출됩니다.

프로토타입은 Creator 클래스에서 하위 클래스로 분류될 필요가 없습니다. 그러나 Product 클래스에 대한 초기화 작업이 필요한 경우가 많습니다.
Creator는 초기화를 사용하여 객체를 초기화합니다. 공장
이 방법에는 그러한 작업이 필요하지 않습니다.

팩토리 메소드슈퍼클래스에서 객체를 생성하기 위한 공통 인터페이스를 정의하여 서브클래스가 생성된 객체의 유형을 변경할 수 있도록 하는 생성적 디자인 패턴입니다.

문제

화물 관리 프로그램을 만들고 있다고 상상해 보세요. 처음에는 자동차로만 물품을 운송할 것으로 예상합니다. 따라서 모든 코드는 Truck 클래스의 객체와 함께 작동합니다.

어떤 시점에서는 귀하의 프로그램이 너무 유명해져서 해양 운송업체가 줄을 서서 프로그램에 해상 물류 지원을 추가해 줄 것을 요청할 정도입니다.


모든 코드가 이미 특정 클래스에 연결되어 있으면 새 클래스를 추가하는 것이 쉽지 않습니다.

좋은 소식이죠? 하지만 코드는 어떻습니까? 기존 코드의 대부분은 Truck 클래스와 엄격하게 연결되어 있습니다. 프로그램에 해양 선박 클래스를 추가하려면 전체 프로그램을 자세히 살펴보아야 합니다. 또한 나중에 프로그램에 다른 유형의 전송을 추가하기로 결정한 경우 이 모든 작업을 반복해야 합니다.

결과적으로 차량 클래스에 따라 하나 또는 다른 작업을 수행하는 조건문으로 가득 찬 무서운 코드가 생성됩니다.

해결책

팩토리 메소드 패턴은 new 연산자를 직접 사용하지 않고 특수 연산자를 호출하여 객체를 생성하도록 제안합니다. 공장방법. 걱정하지 마십시오. 객체는 여전히 new 를 사용하여 생성되지만 팩토리 메서드가 이를 수행합니다.


서브클래스는 자신이 생성하는 객체의 클래스를 변경할 수 있습니다.

언뜻 보면 이것은 무의미해 보일 수 있습니다. 우리는 단순히 프로그램의 한쪽 끝에서 다른 쪽 끝으로 생성자 호출을 이동했을 뿐입니다. 하지만 이제는 하위 클래스의 팩토리 메서드를 재정의하여 생성하는 제품 유형을 변경할 수 있습니다.

이 시스템이 작동하려면 반환된 모든 개체에 공통 인터페이스가 있어야 합니다. 서브클래스는 동일한 인터페이스를 따르는 다양한 클래스의 객체를 생성할 수 있습니다.


모든 제품 개체에는 공통 인터페이스가 있어야 합니다.

예를 들어 Truck 및 Vessel 클래스는 Deliver 메소드를 사용하여 Transport 인터페이스를 구현합니다. 이러한 각 클래스는 고유한 방식으로 메서드를 구현합니다. 즉, 트럭은 육로로 물품을 운반하고 선박은 해상으로 물품을 운반합니다. RoadLogistics 클래스의 팩토리 메소드는 트럭 객체를 반환하고 MarineLogistics 클래스는 선박 객체를 반환합니다.


모든 제품이 공통 인터페이스를 구현하는 한 해당 객체는 클라이언트 코드에서 상호 교환될 수 있습니다.

팩토리 메소드 클라이언트의 경우 이러한 객체 사이에는 차이가 없습니다. 왜냐하면 객체를 일종의 추상 전송으로 처리하기 때문입니다. 객체에 전달 방법이 있다는 것이 그에게 중요하지만 그것이 정확히 어떻게 작동하는지는 중요하지 않습니다.

구조



    제품작성자와 해당 하위 클래스가 생성할 수 있는 개체에 대한 공통 인터페이스를 정의합니다.

    특정 제품다양한 제품에 대한 코드가 포함되어 있습니다. 제품은 구현 방식이 다르지만 공통 인터페이스를 갖습니다.

    창조자새로운 제품 객체를 반환해야 하는 팩토리 메서드를 선언합니다. 결과 유형이 제품의 일반적인 인터페이스와 일치하는 것이 중요합니다.

    종종 팩토리 메소드는 모든 서브클래스가 다르게 구현하도록 강제하기 위해 추상으로 선언됩니다. 그러나 특정 표준 제품을 반환할 수도 있습니다.

    이름에도 불구하고 제품을 만드는 것이 중요하다는 점을 이해하는 것이 중요합니다. 아니다창작자의 유일한 기능. 일반적으로 제품 작업에 유용한 다른 코드가 포함되어 있습니다. 비유: 대규모 소프트웨어 회사에는 프로그래머 교육 센터가 있을 수 있지만 회사의 주요 임무는 프로그래머를 교육하는 것이 아니라 소프트웨어 제품을 만드는 것입니다.

    특정 크리에이터자신만의 방식으로 팩토리 메소드를 구현하여 특정 제품을 생산합니다.

    팩토리 메소드는 항상 새로운 객체를 생성할 필요가 없습니다. 일부 저장소나 캐시에서 기존 개체를 반환하도록 다시 작성할 수 있습니다.

의사코드

이 예에서는 팩토리 메소드기본 프로그램 코드를 특정 요소 클래스에 묶지 않고도 크로스 플랫폼 인터페이스 요소를 생성하는 데 도움이 됩니다.


크로스 플랫폼 대화의 예.

팩토리 메소드는 대화 상자 클래스에서 선언됩니다. 해당 하위 클래스는 다양한 운영 체제와 관련됩니다. 팩토리 메소드 덕분에 각 시스템에 대한 대화 로직을 다시 작성할 필요가 없습니다. 서브클래스는 기본 대화 상자에서 거의 모든 코드를 상속하여 기본 코드가 GUI 창을 구성하는 버튼 및 기타 요소의 유형을 변경할 수 있습니다.

기본 대화 상자 클래스는 공통 프로그래밍 인터페이스를 통해 버튼과 함께 작동합니다. 따라서 팩토리 메서드가 반환하는 버튼의 변형에 관계없이 대화 상자는 계속 작동합니다. 기본 클래스는 특정 버튼 클래스에 의존하지 않으므로 어떤 유형의 버튼을 생성할지 결정하는 것은 하위 클래스에 맡깁니다.

이 접근 방식은 다른 인터페이스 요소를 만드는 데 사용할 수 있습니다. 각각의 새로운 요소 유형은 Abstract Factory에 더 가까이 다가가게 해줄 것입니다.

// 프로그램에 제품 클래스의 계층 구조가 있을 때 // Factory 메서드 패턴을 적용할 수 있습니다. 인터페이스 Button은 render() 메서드 onClick(f) 클래스 WindowsButton은 Button은 render(a, b) 메서드는 // Windows 스타일로 버튼을 렌더링합니다. onClick(f) 메소드는 // Windows 이벤트 핸들러를 버튼에 연결합니다. HTMLButton 클래스는 Button is 메소드 render(a, b) is // 버튼의 HTML 코드를 반환합니다. onClick(f) 메소드는 // 브라우저 이벤트 핸들러를 버튼에 연결합니다. // 팩토리의 기본 클래스입니다. "팩토리"는 // 클래스의 추가 역할일 뿐입니다. 아마도 // 다양한 제품을 생성해야 하는 // 일종의 비즈니스 로직이 이미 있을 것입니다. class Dialog is method render() is // 팩토리 메소드를 사용하려면 // 이 비즈니스 로직이 특정 제품 클래스에 의존하지 않는지 // 확인해야 합니다. 버튼은 // 일반적인 버튼 인터페이스이므로 모두 좋습니다. Button okButton = createButton() okButton.onClick(closeDialog) okButton.render() // 모든 제품 생성 코드를 // "팩토리"라는 특수 메서드에 넣습니다. 추상 메서드 createButton() // 콘크리트 팩토리는 팩토리 메서드를 재정의하고 // 해당 팩토리 메서드에서 자체 제품을 반환합니다. 클래스 WindowsDialog 확장 Dialog is 메서드 createButton() 반환 새 WindowsButton() 클래스 WebDialog 확장 Dialog is 메서드 createButton() 반환 새 HTMLButton() 클래스 Application is field 대화 상자: Dialog // 응용 프로그램은 // 구성 또는 환경. 메소드 초기화()는 config = readApplicationConfigFile() if (config.OS == "Windows") thenDialog = new WindowsDialog() else if (config.OS == "Web") thenDialog = new WebDialog() else throw new Exception("오류! 알 수 없는 운영 체제.") // 다른 모든 클라이언트 코드가 공통 인터페이스를 통해서만 팩토리 및 // 제품과 상호 작용하는 경우 // 처음에 어떤 팩토리가 생성되었는지는 중요하지 않습니다. main() 메소드는 this.initialize()입니다.

적용 가능성

코드에서 작업해야 하는 개체의 유형과 종속성을 미리 알 수 없는 경우.

팩토리 메서드는 제품을 생산하기 위한 코드를 해당 제품을 사용하는 나머지 코드와 분리합니다.

덕분에 메인 코드를 건드리지 않고도 프로덕션 코드를 확장할 수 있다. 따라서 새 제품에 대한 지원을 추가하려면 새 하위 클래스를 만들고 그 안에 팩토리 메서드를 정의한 후 거기에서 새 제품의 인스턴스를 반환해야 합니다.

사용자가 프레임워크나 라이브러리의 일부를 확장할 수 있도록 하려는 경우.

사용자는 상속을 통해 프레임워크의 클래스를 확장할 수 있습니다. 하지만 프레임워크가 표준 클래스가 아닌 이러한 새 클래스에서 객체를 생성하도록 하려면 어떻게 해야 할까요?

해결책은 사용자에게 원하는 구성 요소뿐만 아니라 해당 구성 요소를 생성하는 클래스도 확장할 수 있는 기능을 제공하는 것입니다. 그리고 이를 위해서는 클래스 생성에 정의할 수 있는 특정 생성 방법이 있어야 합니다.

예를 들어, 애플리케이션에 미리 만들어진 UI 프레임워크를 사용합니다. 하지만 여기에 문제가 있습니다. 표준 직사각형 버튼 대신 둥근 버튼이 필요합니다. RoundButton 클래스를 만듭니다. 하지만 기본 UIFramework 클래스에 표준 버튼 대신 둥근 버튼을 생성하도록 어떻게 지시합니까?

이렇게 하려면 프레임워크의 기본 클래스에서 하위 클래스 UIWithRoundButtons를 만들고 그 안에 있는 버튼 생성 메서드(createButton)를 재정의한 다음 거기에 버튼 클래스 생성을 입력합니다. 그런 다음 표준 UIFramework 대신 UIWithRoundButtons를 사용하십시오.

새 객체를 생성하는 대신 이미 생성된 객체를 재사용하여 시스템 리소스를 절약하려는 경우.

이 문제는 일반적으로 데이터베이스, 파일 시스템 등에 대한 연결과 같이 리소스를 많이 사용하는 개체를 작업할 때 발생합니다.

기존 객체를 재사용하려면 얼마나 많은 단계를 거쳐야 하는지 상상해 보세요.

  1. 먼저, 생성한 모든 객체를 저장할 공유 저장소를 생성해야 합니다.
  2. 새로운 객체를 요청할 때에는 저장소를 살펴보고 거기에 사용되지 않은 객체가 있는지 확인해야 합니다.
  3. 그런 다음 이를 클라이언트 코드로 반환합니다.
  4. 그러나 무료 개체가 없으면 저장소에 추가하는 것을 잊지 말고 새 개체를 만드십시오.

클라이언트 코드가 복잡해지지 않도록 이 모든 코드를 어딘가에 배치해야 합니다.

가장 편리한 장소는 객체 생성자입니다. 왜냐하면 이러한 모든 검사는 객체를 생성할 때만 필요하기 때문입니다. 하지만 아쉽게도 디자이너는 항상 창조합니다. 새로운개체인 경우 기존 인스턴스를 반환할 수 없습니다.

즉, 기존 개체와 새 개체를 모두 반환하는 또 다른 메서드가 필요합니다. 이것이 팩토리 메소드가 됩니다.

구현 단계

    생성된 모든 제품을 공통 인터페이스로 가져옵니다.

    제품을 생산하는 클래스에서는 빈 팩토리 메소드를 생성합니다. 제품의 일반 인터페이스를 반환 유형으로 지정합니다.

    그런 다음 클래스 코드를 살펴보고 제품을 만드는 모든 지역을 찾으십시오. 이러한 섹션을 팩토리 메소드 호출로 하나씩 대체하고 다양한 제품을 생성하기 위한 코드를 여기에 전송합니다.

    어떤 제품을 생성해야 하는지 제어하려면 팩토리 메서드에 몇 가지 매개변수를 추가해야 할 수도 있습니다.

    이 시점에서 팩토리 메소드는 우울해 보일 가능성이 높습니다. 여기에는 생성되는 제품의 클래스를 선택하는 대규모 조건부 연산자가 포함됩니다. 하지만 걱정하지 마세요. 곧 바로잡을 예정입니다.

    각 제품 유형에 대해 하위 클래스를 만들고 그 안에 팩토리 메서드를 재정의합니다. 슈퍼클래스에서 해당 제품을 생성하기 위한 코드를 그곳으로 이동합니다.

    생성되는 제품이 기존 생성자 하위 클래스에 비해 너무 많은 경우 동일한 하위 클래스 내에서 다양한 제품이 반환될 수 있도록 팩토리 메서드에 매개변수를 도입하는 것을 고려할 수 있습니다.

    예를 들어 AirMail 및 SurfaceMail 하위 클래스와 비행기, 트럭 및 기차 제품 클래스가 있는 Mail 클래스가 있습니다. Air는 비행기에 해당하지만 Surface Mail의 경우 한 번에 두 가지 제품이 있습니다. 기차에 대한 새 메일 하위 클래스를 만들 수 있지만 문제를 해결하는 다른 방법이 있습니다. 클라이언트 코드는 생성되는 제품 유형을 제어하는 ​​SurfaceMail 팩토리 메서드에 인수를 전달할 수 있습니다.

    모든 이동 후에 팩토리 메소드가 비어 있으면 이를 추상화할 수 있습니다. 그 안에 뭔가가 남아 있어도 상관없습니다. 이것이 기본 구현이 될 것입니다.

    반면에 팩토리 메서드는 상속을 기반으로 구축되지만 복잡한 초기화가 필요하지 않습니다.

    팩토리 메소드는 템플릿 메소드의 특별한 경우로 간주될 수 있습니다. 게다가, 팩토리 메소드종종 다음과 같은 대규모 수업의 일부가 됩니다. 템플릿 방법.

    팩토리 메소드 설명

    팩토리 메소드(Virtual Constructor라고도 함)는 클래스 인스턴스를 생성하기 위한 인터페이스를 하위 클래스에 제공하는 생성적 디자인 패턴입니다. 상속자는 클래스 생성 시 어떤 클래스를 생성할지 결정할 수 있습니다. 즉, Factory는 객체 생성을 상위 클래스의 자손에게 위임합니다. 이를 통해 프로그램 코드에서 특정 클래스를 사용하지 않고 더 높은 수준에서 추상 개체를 조작할 수 있습니다.

    객체를 생성하기 위한 인터페이스를 정의하지만 인스턴스화할 클래스를 결정하는 것은 하위 클래스에 맡깁니다. 팩토리 메소드를 사용하면 클래스가 하위 클래스 생성을 위임할 수 있습니다. 다음과 같은 경우에 사용됩니다.

    • 클래스는 어떤 서브클래스의 어떤 객체를 생성해야 하는지 미리 알 수 없습니다.
    • 클래스는 자신이 생성하는 객체가 하위 클래스에 의해 지정되도록 설계되었습니다.
    • 클래스는 여러 보조 하위 클래스 중 하나에 자신의 책임을 위임하며, 계획은 어떤 클래스가 이러한 책임을 맡는지에 대한 지식을 지역화하는 것입니다.

    구조

    • 제품- 제품
      • 추상 메소드로 생성된 객체의 인터페이스를 정의합니다.
    • 콘크리트제품- 특정 제품
      • 인터페이스를 구현합니다 제품;
    • 창조자- 창작자
      • 유형의 객체를 반환하는 팩토리 메소드를 선언합니다. 제품. 이 메서드의 "기본" 구현도 포함될 수 있습니다.
      • 유형의 객체를 생성하기 위해 팩토리 메소드를 호출할 수 있습니다. 제품;
    • 콘크리트크리에이터- 특정 창작자
      • 클래스 객체를 생성하고 반환하도록 팩토리 메서드를 재정의합니다. 콘크리트제품.