객체 이니셜 라이저와 빌더 및 유체 인터페이스를 사용할 때 요점이 있습니까?


10

Java 및 C #에서는 매개 변수를 사용하여 생성자를 정의하거나, 오브젝트를 구성한 후 각 특성을 정의하거나, 빌더 / 유체 인터페이스 패턴을 사용하여 초기화시 설정할 수있는 특성으로 오브젝트를 작성할 수 있습니다. 그러나 C # 3에는 객체 및 컬렉션 이니셜 라이저가 도입되어 빌더 패턴이 크게 쓸모가 없었습니다. 이니셜 라이저가없는 언어에서는 빌더를 구현 한 후 다음과 같이 사용할 수 있습니다.

Vehicle v = new Vehicle.Builder()
                    .manufacturer("Toyota")
                    .model("Camry")
                    .year(1997)
                    .colour(CarColours.Red)
                    .addSpecialFeature(new Feature.CDPlayer())
                    .addSpecialFeature(new Feature.SeatWarmer(4))
                    .build();

반대로 C #에서는 다음과 같이 작성할 수 있습니다.

var vehicle = new Vehicle {
                Manufacturer = "Toyota",
                Model = "Camry",
                Year = 1997,
                Colour = CarColours.Red,
                SpecialFeatures = new List<SpecialFeature> {
                    new Feature.CDPlayer(),
                    new Feature.SeatWarmer { Seats = 4 }
                }
              }

... 이전 예제에서 볼 수 있듯이 빌더가 필요하지 않습니다.

이 예제를 기반으로 빌더는 C #에서 여전히 유용합니까, 아니면 초 기자에 의해 대체 되었습니까?


are builders useful왜 이런 종류의 질문을 계속 볼 수 있습니까? 빌더는 디자인 패턴입니다. 언어 기능으로 노출 될 수 있지만 하루가 끝나면 디자인 패턴 일뿐입니다. 디자인 패턴 "잘못"될 수 없습니다 . 유스 케이스를 충족시킬 수도 아닐 수도 있지만 패턴 전체를 잘못 적용하지는 않습니다. 하루가 끝나면 디자인 패턴이 특정 문제를 해결한다는 것을 기억하십시오. 문제에 직면하지 않으면 왜 문제를 해결하려고 시도합니까?
VLAZ

@vlaz 빌더가 잘못되었다는 말은 아닙니다. 사실 초기 질문은 빌더를 사용하는 가장 일반적인 경우의 구현이 주어진 빌더에 대한 유스 케이스가 있는지 묻는 질문이었습니다. 분명히 사람들은 빌더가 개인 필드를 설정하는 데 여전히 유용하다고 대답했으며, 그 결과 내 질문에 대답했습니다.
svbnet

3
@vlaz 명확히하기 위해 : 초기자는 내부 빌더 클래스를 작성하는 "전통적인"빌더 / 유체 인터페이스 패턴을 대체 한 다음 해당 클래스 내에 체인 클래스 설정 메소드를 작성하여 해당 상위 클래스의 새 인스턴스를 작성한다고 말합니다. 나는 이니셜 라이저가 특정 빌더 패턴을 대체한다고 말하는 것이 아니다 . 초기 자는 개발자가 특정 빌더 패턴을 구현해야 하고 답변에 언급 된 사용 사례를 저장 하지 않아도 되므로 빌더 패턴을 쓸모 없게 만들지 않습니다 .
svbnet

5
@vlaz 나는 당신의 관심사를 이해하지 못합니다. "디자인 패턴이 유용하지 않다고 말하고 있습니다."아닙니다. Joe는 디자인 패턴이 유용한 지 묻고 있었습니다 . 그게 어떻게 나쁘거나 틀리거나 틀린 질문입니까? 답이 분명하다고 생각하십니까? 나는 그 대답이 명백하다고 생각하지 않습니다. 이것은 나에게 좋은 질문처럼 보인다.
Tanner Swett

2
@vlaz, 싱글 톤 및 서비스 로케이터 패턴이 잘못되었습니다. Ergo 디자인 패턴이 잘못되었을 수 있습니다.
David Arno

답변:


12

@ user248215에서 언급했듯이 실제 문제는 불변성입니다. C #에서 빌더를 사용하는 이유는 설정 가능한 특성을 노출하지 않고 초기화 프로그램의 명시 성을 유지하기 위해서입니다. 캡슐화의 문제가 아니기 때문에 내가 직접 답을 작성했습니다. 캡슐화는 setter를 호출한다고해서 setter가 실제로하는 일을 암시하거나 구현에 연결하지 않기 때문에 상당히 직교합니다.

C # 8.0의 다음 버전에서는 with빌더를 작성할 필요없이 불변 개체를 명확하고 간결하게 초기화 할 수 있는 키워드 를 소개 할 것입니다.

이니셜 라이저와 달리 빌더로 할 수있는 또 다른 흥미로운 일은 호출 된 메소드의 순서에 따라 다양한 유형의 객체를 생성 할 수 있다는 것입니다.

예를 들어

value.Match()
    .Case((DateTime d) => Console.WriteLine($"{d: yyyy-mm-dd}"))
    .Case((double d) => Console.WriteLine(Math.Round(d, 4));
    // void

var str = value.Match()
    .Case((DateTime d) => $"{d: yyyy-mm-dd}")
    .Case((double d) => Math.Round(d, 4).ToString())
    .ResultOrDefault(string.Empty);
    // string

위의 예를 명확히하기 위해, 빌더 패턴을 사용하여 케이스를 지정하여 "일치"를 작성하는 패턴 일치 라이브러리입니다. 케이스는 Case함수를 전달 하는 메소드를 호출하여 추가됩니다 . value함수의 매개 변수 유형에 지정 가능한 경우 호출됩니다. GitHub 에서 전체 소스 코드를 찾을 수 있으며 XML 주석은 일반 텍스트로 읽기 어렵 기 때문에 SandCastle 빌드 문서에 대한 링크입니다 ( 비고 섹션 참조).


IEnumerable<Func<T, TResult>>멤버를 사용하여 어떻게 객체 초기화를 수행 할 수 없었는지 알 수 없습니다 .
Caleth

@Caleth 실제로 실험 한 것이었지만 그 접근법에는 몇 가지 문제가 있습니다. 조건부 절 (링크 문서에서 표시되지 않고 사용 및 설명)을 허용하지 않으며의 유형 유추를 허용하지 않습니다 TResult. 궁극적으로 형식 유추와 관련이 있습니다. 또한 제어 구조처럼 보이기를 원했습니다. 또한 돌연변이를 허용하기 때문에 이니셜 라이저를 사용하고 싶지 않았습니다.
Aluan Haddad

12

객체 이니셜 라이저는 호출 코드로 속성에 액세스 할 수 있어야합니다. 중첩 된 빌더는 클래스의 개인 멤버에 액세스 할 수 있습니다.

Vehicle모든 세터를 개인용으로 변경 하여 불변 으로 만들 려면 중첩 된 빌더를 사용하여 개인용 변수를 설정할 수 있습니다.


0

그들은 모두 다른 목적으로 사용됩니다 !!!

생성자readonly개인 및 보호 된 구성원뿐만 아니라 표시된 필드를 초기화 할 수 있습니다 . 그러나 생성자 내에서 수행 할 수있는 작업에는 다소 제한이 있습니다. this예를 들어 외부 메서드에 전달 하지 말아야하고 가상 멤버를 호출하지 않아야합니다. 가상 멤버는 아직 자체 생성되지 않은 파생 클래스의 컨텍스트에서 실행될 수 있기 때문입니다. 또한 생성자가 실행되도록 보장합니다 (호출자가 매우 특이한 작업을 수행하지 않는 한) 생성자에서 필드를 설정하면 나머지 클래스의 코드는 해당 필드가 null이 아니라고 가정 할 수 있습니다.

초기화 는 시공 후 실행됩니다. 그들은 단지 당신이 공공 재산을 부를 수있게합니다. 개인 및 / 또는 읽기 전용 필드는 설정할 수 없습니다. 일반적으로 속성 설정 작업은 상당히 제한적이어야합니다. 예를 들어 속성은, 등원이어야하고 부작용은 제한적입니다.

빌더 메소드는 실제 메소드이므로 둘 이상의 인수를 허용하므로 규칙에 따라 오브젝트 작성을 포함한 부작용이있을 수 있습니다. 읽기 전용 필드를 설정할 수는 없지만 다른 작업을 거의 수행 할 수 있습니다. 또한 메소드는 확장 메소드로 구현 될 수 있습니다 (예 : 거의 모든 LINQ 기능).

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.