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

Factory 클래스 대신 객체 내에서 factory 메소드를 사용하는 것이 좋은 생각은 언제입니까?



답변

나는 수업이 ‘사람’이라는 관점에서 디자인 패턴에 대해 생각하는 것을 좋아하며 패턴은 사람들이 서로 이야기하는 방식입니다.

나에게 공장 패턴은 고용 기관과 같습니다. 다양한 수의 근로자가 필요한 사람이 있습니다. 이 사람은 그들이 고용 한 사람들에게 필요한 정보를 알고 있을지 모르지만 그게 전부입니다.

따라서 신입 사원이 필요할 때 고용 기관에 연락하여 필요한 것을 알려줍니다. 이제 실제로 누군가를 고용 하려면 혜택, 적격성 검증 등 많은 것을 알아야합니다. 그러나 고용하는 사람은이를 알 필요가 없습니다. 고용 기관이 모든 것을 처리합니다.

같은 방식으로 팩토리를 사용하면 소비자는 자신이 생성 된 방법이나 종속성이 무엇인지에 대한 세부 정보를 알 필요없이 새로운 객체를 만들 수 있습니다. 실제로 원하는 정보 만 제공하면됩니다.

public interface IThingFactory
{
    Thing GetThing(string theString);
}

public class ThingFactory : IThingFactory
{
    public Thing GetThing(string theString)
    {
        return new Thing(theString, firstDependency, secondDependency);
    }
}

따라서 ThingFactory의 소비자는 소비자로부터 오는 문자열 데이터를 제외하고 Thing의 종속성에 대해 알 필요없이 Thing을 얻을 수 있습니다.


답변

팩토리 메소드는 생성자에 대한 대안으로 고려해야합니다. 주로 생성자가 표현력이 충분하지 않은 경우입니다.

class Foo{
  public Foo(bool withBar);
}

다음과 같이 표현 적이 지 않습니다.

class Foo{
  public static Foo withBar();
  public static Foo withoutBar();
}

팩토리 클래스는 객체를 생성하기 위해 복잡한 프로세스가 필요할 때, 구성에 실제 클래스에 대해 원하지 않는 종속성이 필요할 때, 다른 객체를 생성해야 할 때 유용합니다.


답변

개인적으로 이해하기 위해 별도의 Factory 클래스를 찾는 한 가지 상황은 만들려는 최종 객체가 다른 여러 객체에 의존하는 경우입니다. 예를 들면, PHP에서 : 당신이 있다고 가정 House차례로이 객체 KitchenLivingRoom객체 및 LivingRoom객체는이 TV객체의 내부뿐만 아니라.

이를 달성하는 가장 간단한 방법은 각 객체가 구성 메소드에서 하위를 House작성하는 것입니다. 그러나 특성이 상대적으로 중첩 된 경우 작성에 실패하면 실패한 항목을 정확하게 분리하는 데 약간의 시간이 소요됩니다.

대안은 다음을 수행하는 것입니다 (멋진 용어가 마음에 들면 의존성 주입).

$TVObj = new TV($param1, $param2, $param3);
$LivingroomObj = new LivingRoom($TVObj, $param1, $param2);
$KitchenroomObj = new Kitchen($param1, $param2);
$HouseObj = new House($LivingroomObj, $KitchenroomObj);

여기서 House실패 를 만드는 과정은 볼 곳이 하나 뿐이지 만 새로운 것을 원할 때 마다이 청크를 사용해야하는 것은 House편리하지 않습니다. 공장을 입력하십시오 :

class HouseFactory {
    public function create() {
        $TVObj = new TV($param1, $param2, $param3);
        $LivingroomObj = new LivingRoom($TVObj, $param1, $param2);
        $KitchenroomObj = new Kitchen($param1, $param2);
        $HouseObj = new House($LivingroomObj, $KitchenroomObj);

        return $HouseObj;
    }
}

$houseFactory = new HouseFactory();
$HouseObj = $houseFactory->create();

여기 팩토리 덕분에 a 생성 프로세스 House가 추상화되어 (만 생성하려고 할 때 모든 단일 종속성을 생성하고 설정할 필요가 없음 House) 동시에 중앙 집중화되어 유지 관리가 더 쉽습니다. 별도의 팩토리를 사용하는 것이 유리한 이유 (예 : 테스트 가능성)가 있지만 Factory 클래스가 유용한 방법을 가장 잘 설명하기 위해이 특정 사용 사례를 찾습니다.


답변

팩토리 또는 팩토리 방법을 사용하여 아이디어를 명확하게 구별하는 것이 중요합니다. 둘 다 상호 배타적 인 다른 종류의 객체 생성 문제를 해결하기위한 것입니다.

“공장 방법”에 대해 구체적으로 설명하겠습니다.

첫 번째는 추가 응용 프로그램 개발에 사용될 라이브러리 또는 API를 개발할 때 팩토리 방법이 작성 패턴에 가장 적합한 선택 중 하나라는 것입니다. 뒤에 이유; 필요한 기능을 가진 객체를 언제 만들지 만 객체 유형이 결정되지 않은 상태이거나 동적 매개 변수가 전달되는 것으로 결정됩니다 .

요점은 팩토리 패턴 자체를 사용하여 거의 동일하게 달성 할 수 있지만 팩토리 패턴이 강조 표시된 문제에 사용될 경우 하나의 큰 단점이 시스템에 도입 될 것입니다. 이는 다른 객체 (하위 클래스 객체)를 만드는 논리가 미래에는 다른 플랫폼을 위해 라이브러리의 기능을 확장해야 할 때 일부 비즈니스 조건에 특정해야합니다 (보다 기술적으로는 기본 인터페이스 또는 추상 클래스의 하위 클래스를 더 추가해야 팩토리가 기존 객체 외에도 해당 객체를 반환합니다) 일부 동적 매개 변수를 기반으로) 비용이 많이 들며 디자인 관점에서 좋지 않은 팩토리 클래스의 논리를 변경 (확장) 할 때마다. 다른 한편으로, “공장 방법”

interface Deliverable
{
    /*********/
}

abstract class DefaultProducer
{

    public void taskToBeDone()
    {
        Deliverable deliverable = factoryMethodPattern();
    }
    protected abstract Deliverable factoryMethodPattern();
}

class SpecificDeliverable implements Deliverable
{
 /***SPECIFIC TASK CAN BE WRITTEN HERE***/
}

class SpecificProducer extends DefaultProducer
{
    protected Deliverable factoryMethodPattern()
    {
        return new SpecificDeliverable();
    }
}

public class MasterApplicationProgram
{
    public static void main(String arg[])
    {
        DefaultProducer defaultProducer = new SpecificProducer();
        defaultProducer.taskToBeDone();
    }
}


답변

매개 변수 유형은 동일하지만 동작이 다른 여러 “생성자”가 필요한 경우에도 유용합니다.


답변

다음과 같은 경우 객체 내부에서 팩토리 메소드 를 사용하는 것이 좋습니다 .

  1. 객체의 클래스는 정확히 어떤 서브 클래스를 생성해야하는지 모른다
  2. 객체의 클래스는 객체가 생성하는 객체가 하위 클래스에 의해 지정되도록 설계되었습니다.
  3. Object 클래스는 직무를 보조 서브 클래스에 위임하고 어떤 클래스가이 직무를 수행 할 것인지 정확히 모릅니다

다음과 같은 경우 추상 팩토리 클래스 를 사용하는 것이 좋습니다 .

  1. 객체는 내부 객체를 만들고 디자인하는 방법에 의존해서는 안됩니다.
  2. 연결된 개체 그룹을 함께 사용해야하며이 제약 조건을 제공해야합니다.
  3. 개체는 부모 개체의 일부가 될 수있는 여러 연결된 개체 그룹 중 하나에 의해 구성되어야합니다.
  4. 인터페이스 만 보여 주지만 구현은 아닌 자식 객체를 공유해야합니다.

답변

에서 UML

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

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

ConcreteProduct : 제품 인터페이스 구현

제작자 : Factory 메서드 선언

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

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

코드 스 니펫 :

import java.util.HashMap;


/* Product interface as per UML diagram */
interface Game{
    /* createGame is a complex method, which executes a sequence of game steps */
    public void createGame();
}

/* ConcreteProduct implementation as per UML diagram */
class Chess implements Game{
    public Chess(){

    }
    public void createGame(){
        System.out.println("---------------------------------------");
        System.out.println("Create Chess game");
        System.out.println("Opponents:2");
        System.out.println("Define 64 blocks");
        System.out.println("Place 16 pieces for White opponent");
        System.out.println("Place 16 pieces for Black opponent");
        System.out.println("Start Chess game");
        System.out.println("---------------------------------------");
    }
}
class Checkers implements Game{
    public Checkers(){

    }
    public void createGame(){
        System.out.println("---------------------------------------");
        System.out.println("Create Checkers game");
        System.out.println("Opponents:2 or 3 or 4 or 6");
        System.out.println("For each opponent, place 10 coins");
        System.out.println("Start Checkers game");
        System.out.println("---------------------------------------");
    }
}
class Ludo implements Game{
    public Ludo(){

    }
    public void createGame(){
        System.out.println("---------------------------------------");
        System.out.println("Create Ludo game");
        System.out.println("Opponents:2 or 3 or 4");
        System.out.println("For each opponent, place 4 coins");
        System.out.println("Create two dices with numbers from 1-6");
        System.out.println("Start Ludo game");
        System.out.println("---------------------------------------");
    }
}

/* Creator interface as per UML diagram */
interface IGameFactory {
    public Game getGame(String gameName);
}

/* ConcreteCreator implementation as per UML diagram */
class GameFactory implements IGameFactory {

     HashMap<String,Game> games = new HashMap<String,Game>();
    /*
        Since Game Creation is complex process, we don't want to create game using new operator every time.
        Instead we create Game only once and store it in Factory. When client request a specific game,
        Game object is returned from Factory instead of creating new Game on the fly, which is time consuming
    */

    public GameFactory(){

        games.put(Chess.class.getName(),new Chess());
        games.put(Checkers.class.getName(),new Checkers());
        games.put(Ludo.class.getName(),new Ludo());
    }
    public Game getGame(String gameName){
        return games.get(gameName);
    }
}

public class NonStaticFactoryDemo{
    public static void main(String args[]){
        if ( args.length < 1){
            System.out.println("Usage: java FactoryDemo gameName");
            return;
        }

        GameFactory factory = new GameFactory();
        Game game = factory.getGame(args[0]);
        if ( game != null ){
            game.createGame();
            System.out.println("Game="+game.getClass().getName());
        }else{
            System.out.println(args[0]+  " Game does not exists in factory");
        }
    }
}

산출:

java NonStaticFactoryDemo Chess
---------------------------------------
Create Chess game
Opponents:2
Define 64 blocks
Place 16 pieces for White opponent
Place 16 pieces for Black opponent
Start Chess game
---------------------------------------
Game=Chess

이 예제는 Factory을 구현하여 클래스 를 보여줍니다 FactoryMethod.

  1. Game모든 유형의 게임을위한 인터페이스입니다. 복잡한 방법을 정의합니다.createGame()

  2. Chess, Ludo, Checkers 게임의 다양한 변형으로 createGame()

  3. public Game getGame(String gameName)이다 FactoryMethodIGameFactory클래스

  4. GameFactory생성자에서 다른 유형의 게임을 미리 만듭니다. IGameFactory팩토리 메소드를 구현 합니다.

  5. 게임 이름은 명령 행 인수로 전달됩니다 NotStaticFactoryDemo

  6. getGamein GameFactory은 게임 이름 을 받아들이고 해당 Game객체를 반환 합니다.

공장:

인스턴스화 논리를 클라이언트에 노출시키지 않고 객체를 만듭니다.

공장 방법

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

사용 사례 :

사용시기 : Client런타임에 어떤 구체적인 클래스를 작성해야하는지 모르지만 작업을 수행 할 클래스를 얻으려고합니다.