2014-02-26 2 views
3

나는 조회 테이블 용 빌더를 작성하고 아래 표시된대로 사용합니다. 시험에서이 빌더를 사용Java의 일반 빌더

public class RaceCodeDataBuilder { 

    private RaceCode raceCode; 

    public RaceCodeDataBuilder() { 
     raceCode = new RaceCode(); 
    } 

    public RaceCodeDataBuilder code(String code) { 
     raceCode.setCode(code);  
     return this; 
    } 

    public RaceCodeDataBuilder displayName(String displayName) { 
     raceCode.setDisplayName(displayName); 
     return this; 
    } 

    public RaceCode build() { 
     return raceCode; 
    } 

} 

: 나는 그런 StateCodeBuilder, GenderCodeBuilder 그들 모두 그냥 "코드"가와 같은 다른 조회 테이블에 대해 더 많은 유사한 빌더를 기대하고

RaceCode mockRaceCode = new RaceCodeDataBuilder() 
         .code("2054-5") 
         .displayName("Black or African American") 
         .build(); 

"displayName", 위의 빌더와 비슷합니다.

일반 빌더를 만들고 다른 이름으로 동일한 작업을 수행하는 여러 빌더 클래스를 작성하지 않으려합니다.

public class CodeDataBuilder<T>{ 

    private T t;  

    public CodeDataBuilder(T t) { 
     this.t = t; 
    } 

    public CodeDataBuilder code(String code) { 
     raceCode.setCode(code);  // Cant write T.setCode here for obvious resons 
     return this; 
    } 

    public CodeDataBuilder displayName(String displayName) { 
     raceCode.setDisplayName(displayName); // Cant write T.setDisplayNamehere for obvious resons 
     return this; 
    } 

    public T build() { 
     return t; 
    } 

} 

누군가가 나를 도울 수 ..

나는 제네릭 뭔가를 시도하지만 해제 방법입니까?

감사합니다.

+0

해당 인터페이스를 구현하는 모든 클래스가'.setCode()'와 같은 특정 메소드를 가질 수 있도록 인터페이스를 생성하십시오. 그'Interface'에'T'를 던져서 그 메소드에 접근 할 수 있습니다. – Rainbolt

답변

3

필요한 방법으로 인터페이스 BuildableCodeData을 만들고 RaceData과 같은 클래스로 구현하십시오. 당신은 몇 가지 표준 기능과 인터페이스가있는 경우

public interface BuildableCodeData { 

    public void setCode(String code); 

    public void setDisplayName(String name); 
} 

public class Builder<T extends BuildableCodeData> { 
    private T codeData; 

    public Builder(T codeData) { 
    this.codeData = codeData; 
    } 

    public Builder<T> setCode(String code) { 
    codeData.setCode(code); 
    return this; 
    } 

    public Builder<T> setDisplayName(String displayName) { 
    codeData.setDisplayName(displayName); 
    return this; 
    } 

    public T build() { 
    return codeData; 
    } 
} 
+0

감사합니다. 귀하의 솔루션은 깨끗하고 명확합니다. 내가 그것에 대해 좋아하지 않는 유일한 점은 내 인터페이스를 구현하기 위해 RaceData를 "수정"해야한다는 것입니다. 변경하지 못했던 Legacy/ThirdParty 클래스가 있다면 어떨까요? –

+0

인터페이스를 구현하는 다른 클래스로 둘러 쌉니다. – abraabra

1

당신이 필요한 방법과 인터페이스를 만드는 경우 :

interface CodeModel { 
    public void setCode(String s); 
    public void setDisplayName(String s); 
} 

을 당신은 다음과 같이 만 T extends CodeModel을 허용하도록 제네릭 클래스를 요청할 수 있습니다 :이 도움이

class CodeDataBuilder<T extends CodeModel> { 
    // T has setCode method now! 
} 

희망!

+2

그리고 인터페이스는 generic 매개 변수를 어떻게 사용합니까? –

+0

죄송합니다. 오타였습니다. 오류를 제거했습니다. – gdiazc

2

인터페이스를 사용해야하는 것처럼 보이며 빌드 메소드가 해당 인터페이스를 반환하도록 만듭니다. 예를 들면 다음과 같습니다.

public interface Buildable{ 
    void setDisplayName(String name); 
    void setCode(String code); 
} 

public class CodeDataBuilder { 

    private Buildable mObj;  

    public CodeDataBuilder(Buildable mObj) { 
     this.mObj = mObj; 
    } 

    public CodeDataBuilder code(String code) { 
     mObj.setCode(code);  // Cant write T.setCode here for obvious resons 
     return this; 
    } 

    public CodeDataBuilder displayName(String displayName) { 
     mObj.setDisplayName(displayName); // Cant write T.setDisplayNamehere for obvious resons 
     return this; 
    } 

    public Buildable build() { 
     return mObj; 
    } 

} 
} 

그런 다음 작성하려는 모든 객체를 Buildable 인터페이스로 구현하십시오.

+0

매번 빌더의 출력을 특정 클래스로 전송해야합니다. – abraabra

+1

사실, 캐스트는 실제로 명시된 문제가 아니며 여러 빌더를 구현하지 않아도됩니다. 다른 답변에서 볼 수 있듯이 제네릭을 사용하도록 확장하는 것은 상대적으로 쉽습니다. – Submersed

+0

감사합니다. Submersed, 당신의 접근 방식은 올바른데, Abra의 답변을 받아들입니다. 제 요구 사항에 맞는 generics로 보여 주었고 명시 적 캐스팅은 피했습니다. –

0

, 당신은 그것에 대한 일반적인 빌더를 만들 수 있습니다

코드는 다음과 같이 표시됩니다. 기본 빌더는 추상적 일 것이며 각각의 구체적인 구현에 대해 구체적인 빌더가있을 것입니다.

인터페이스 :

public interface CodeNameable { 
    String getCode(); 
    String getName(); 
} 

콘크리트 구현 :

public class CodeNamedCar implements CodeNameable { 
    private String code; 
    private String name; 
    public CodeNamedCar(String code, String name) { 
     this.code = code; 
     this.name = name; 
    } 
} 

추상 빌더 :

public abstract class CodeNameBuilder<C extends CodeNameable> { 
    public String code; 
    public String name; 
    public CodeNameBuilder() { 
    } 
} 

콘크리트 빌더 :

public abstract class CarBuilder extends CodeNameBuilder<CodeNamedCar> { 
    public CarBuilder() { 
    } 
    public CarBuilder code(String co_de) { 
     this.code = code; 
     return this; 
    } 
    public CarBuilder name(String name) { 
     this.name = name; 
     return this; 
    } 
    public CodeNameCar build() { 
     return (new CodeNameCar(code, name)); 
    } 
} 
당신이 희망으로

그리고 당신이 그것을 사용할 수 있습니다

CodeNamedCar car = new CarBuilder().code("thecode").name("Mazda").build(); 

이 디자인을 사용하면 CodeNameCar 생성자의 정확성 (예를 들어, null이 아닌 비 비어)에 대한 각 필드를 확인해야합니다. 그것을 디자인하는 다른 방법들도 있습니다.

0

빌더 패턴은 클래스의 새 인스턴스를 크레이트하고 필요한만큼 초기화합니다.

가는 길에 일부 속성의 부분적인 설정자로 끝내고 두 개체의 속성이 동일하기 때문에 가능한 가짜 관계를 만드는 경향이 있습니다.

이 예에서 모든 것을 지원하려면 이름 속성이 있지만 Nameable이라는 수퍼 인터페이스를 만들지 말고 모든 가능한 위치에 구현하십시오.

이러한 특성이 클래스간에 공유되는 경우 해당 특성을 클래스로 생성해야한다고 생각해야합니다.

class Code { 
    int number; 
    String name; 
} 

class Race { 
    Code code; 
    //other attributes; 
} 

코드 작성자와 경주 용 빌더가 있습니다.

좋은 디자인은 균형의 균형이라는 점에 유의하십시오. 두 개의 필드가 5 개의 클래스에 공통적 인 경우 코드를 복잡하게 만들고 초기화를 압축하고 생산성을 높이 지 않는 전용 기계를 만드는 것이 목적입니다.