[java] 언제 빌더 패턴을 사용 하시겠습니까? [닫은]

일부 무엇 일반 , 실제 사례 빌더 패턴을 사용하는가? 무엇을 사나요? 왜 팩토리 패턴을 사용하지 않습니까?



답변

빌더와 팩토리 IMHO의 주요 차이점은 오브젝트를 빌드하기 위해 많은 작업을 수행해야하는 경우 빌더가 유용하다는 것입니다. 예를 들어 DOM을 상상해보십시오. 최종 객체를 얻으려면 많은 노드와 속성을 만들어야합니다. 팩토리는 팩토리가 하나의 메소드 호출 내에서 전체 오브젝트를 쉽게 작성할 수있는 경우에 사용됩니다.

빌더를 사용하는 한 가지 예는 XML 문서를 작성하는 것입니다. 예를 들어 HTML 조각을 작성할 때이 모델을 사용했습니다. 예를 들어 특정 유형의 테이블을 작성하기위한 빌더가 있고 다음과 같은 메소드가있을 수 있습니다 (매개 변수는 표시되지 않음). :

BuildOrderHeaderRow()
BuildLineItemSubHeaderRow()
BuildOrderRow()
BuildLineItemSubRow()

그런 다음이 빌더는 HTML을 뱉어 냈습니다. 큰 절차 적 방법을 사용하는 것보다 읽기가 훨씬 쉽습니다.

Wikipedia 에서 빌더 패턴을 확인하십시오 .


답변

다음은 Java에서 패턴 및 예제 코드 사용을 주장하는 몇 가지 이유이지만, 디자인 패턴 에서 Gang of Four가 다루는 빌더 패턴의 구현입니다 . Java로 사용하는 이유는 다른 프로그래밍 언어에도 적용됩니다.

Joshua Bloch는 Effective Java, 2nd Edition 에서 다음과 같이 말합니다 .

빌더 패턴은 생성자 또는 정적 팩토리가 소수 이상의 매개 변수를 갖는 클래스를 설계 할 때 적합합니다.

우리는 어느 시점에서 각각의 추가가 새로운 옵션 매개 변수를 추가하는 생성자 목록이있는 클래스를 만났습니다.

Pizza(int size) { ... }
Pizza(int size, boolean cheese) { ... }
Pizza(int size, boolean cheese, boolean pepperoni) { ... }
Pizza(int size, boolean cheese, boolean pepperoni, boolean bacon) { ... }

이를 텔레 스코핑 생성자 패턴이라고합니다. 이 패턴의 문제점은 생성자가 4 또는 5 개의 매개 변수 길이이면 지정된 상황에서 원하는 특정 생성자와 매개 변수 의 필수 순서 를 기억하기어렵다는 것입니다.

Telescoping 생성자 패턴에 대한 한 가지 대안 은 필수 매개 변수를 사용하여 생성자를 호출 한 후 다음과 같은 선택적 세터를 호출하는 JavaBean 패턴입니다 .

Pizza pizza = new Pizza(12);
pizza.setCheese(true);
pizza.setPepperoni(true);
pizza.setBacon(true);

여기서 문제는 객체가 여러 호출을 통해 생성되기 때문에 구성 과정에서 일관성이없는 상태에있을 수 있다는 것입니다. 또한 스레드 안전을 보장하기 위해 많은 노력이 필요합니다.

더 나은 대안은 빌더 패턴을 사용하는 것입니다.

public class Pizza {
  private int size;
  private boolean cheese;
  private boolean pepperoni;
  private boolean bacon;

  public static class Builder {
    //required
    private final int size;

    //optional
    private boolean cheese = false;
    private boolean pepperoni = false;
    private boolean bacon = false;

    public Builder(int size) {
      this.size = size;
    }

    public Builder cheese(boolean value) {
      cheese = value;
      return this;
    }

    public Builder pepperoni(boolean value) {
      pepperoni = value;
      return this;
    }

    public Builder bacon(boolean value) {
      bacon = value;
      return this;
    }

    public Pizza build() {
      return new Pizza(this);
    }
  }

  private Pizza(Builder builder) {
    size = builder.size;
    cheese = builder.cheese;
    pepperoni = builder.pepperoni;
    bacon = builder.bacon;
  }
}

참고 피자는 불변이고, 그 파라미터 값이 하나의 위치에있는 . Builder의 setter 메소드는 Builder 오브젝트를 리턴 하므로 체인화 될 수 있습니다 .

Pizza pizza = new Pizza.Builder(12)
                       .cheese(true)
                       .pepperoni(true)
                       .bacon(true)
                       .build();

결과적으로 작성하기 쉽고 읽기 쉽고 이해하기 쉬운 코드가 만들어집니다. 이 예제에서, 빌드 메소드는 매개 변수가 빌더에서 Pizza 오브젝트로 복사 된 후 매개 변수를 점검 하고 올바르지 않은 매개 변수 값이 제공된 경우 IllegalStateException을 발생 시키도록 수정 될 수 있습니다 . 이 패턴은 융통성이 있으며 향후 더 많은 매개 변수를 쉽게 추가 할 수 있습니다. 생성자에 대해 4 개 또는 5 개 이상의 매개 변수가있는 경우에만 유용합니다. 즉 , 앞으로 더 많은 매개 변수를 추가 할 것으로 의심되면 처음에는 가치가있을 수 있습니다.

나는 Joshua Bloch의 Effective Java, 2nd Edition 책에서이 주제에 대해 많은 것을 빌렸다 . 이 패턴과 다른 효과적인 Java 관행에 대해 더 배우려면 강력히 권장합니다.


답변

식당을 생각해 보자. “오늘의 식사”를 만드는 것은 공장 패턴입니다. 부엌에 “오늘의 식사를주세요”라고 말하면 부엌 (공장)은 숨겨진 기준에 따라 어떤 객체를 생성할지 결정하기 때문입니다.

사용자 정의 피자를 주문하면 빌더가 나타납니다. 이 경우, 웨이터는 요리사 (빌더)에게 “피자, 치즈, 양파, 베이컨을 넣습니다!”라고 말합니다. 따라서 빌더는 생성 된 오브젝트가 가져야하는 속성을 노출하지만 설정 방법을 숨 깁니다.


답변

.NET StringBuilder 클래스는 빌더 패턴의 좋은 예입니다. 주로 일련의 단계에서 문자열을 만드는 데 사용됩니다. ToString ()을 수행하는 최종 결과는 항상 문자열이지만 해당 문자열의 생성은 사용 된 StringBuilder 클래스의 함수에 따라 다릅니다. 요약하자면, 기본 아이디어는 복잡한 객체를 구축하고 구축 방법에 대한 구현 세부 사항을 숨기는 것입니다.


답변

다중 스레드 문제의 경우 각 스레드마다 복잡한 객체를 구축해야했습니다. 오브젝트는 처리중인 데이터를 나타내며 사용자 입력에 따라 변경 될 수 있습니다.

대신 공장을 사용할 수 있습니까? 예

왜 안 했어? 빌더는 내가 생각하는 것이 더 이해가됩니다.

팩토리는 동일한 기본 유형 (같은 인터페이스 또는 기본 클래스 구현) 인 다른 유형의 오브젝트를 작성하는 데 사용됩니다.

빌더는 동일한 유형의 오브젝트를 반복해서 빌드하지만 구성은 동적이므로 런타임시 변경할 수 있습니다.


답변

처리 할 옵션이 많을 때 사용합니다. jmock과 같은 것을 생각해보십시오.

m.expects(once())
    .method("testMethod")
    .with(eq(1), eq(2))
    .returns("someResponse");

그것은 훨씬 더 자연스럽고 … 가능합니다.

xml 빌딩, 문자열 빌딩 및 기타 여러 가지가 있습니다. java.util.Map건축업자로 썼다 면 상상해보십시오 . 다음과 같은 작업을 수행 할 수 있습니다.

Map<String, Integer> m = new HashMap<String, Integer>()
    .put("a", 1)
    .put("b", 2)
    .put("c", 3);


답변

Microsoft MVC 프레임 워크를 거치면서 빌더 패턴에 대해 생각했습니다. ControllerBuilder 클래스에서 패턴을 발견했습니다. 이 클래스는 컨트롤러 팩토리 클래스를 반환하고 콘크리트 컨트롤러를 만드는 데 사용됩니다.

빌더 패턴을 사용할 때의 이점은 자신의 팩토리를 만들어 프레임 워크에 연결할 수 있다는 것입니다.

@Tetha에는 피자를 제공하는 이탈리아 사람이 운영하는 식당 (프레임 워크)이 있습니다. 피자를 준비하기 위해 이탈리아 사람 (오브젝트 빌더)은 피자베이스 (기본 클래스)와 함께 Owen (공장)을 사용합니다.

이제 인도 사람은 이탈리아 사람에서 식당을 인수합니다. 피자 대신 인도 식당 (프레임 워크) 서버 dosa. 인도 사람을 준비하기 위해 (인물 제작자) Maida (기본 클래스)와 함께 프라이팬 (공장)을 사용합니다.

시나리오를 보면 음식이 다르고 음식 준비가 다르지만 동일한 식당 (같은 프레임 워크)에서 다릅니다. 식당은 중식, 멕시칸 또는 모든 요리를 지원할 수있는 방식으로 지어 져야합니다. 프레임 워크 내부의 오브젝트 빌더를 사용하면 원하는 요리를 플러그인 할 수 있습니다. 예를 들어

class RestaurantObjectBuilder
{
   IFactory _factory = new DefaultFoodFactory();

   //This can be used when you want to plugin the 
   public void SetFoodFactory(IFactory customFactory)
   {
        _factory = customFactory;
   }

   public IFactory GetFoodFactory()
   {
      return _factory;
   }
}