먼저 "테스트 주도 개발로 배우는 객체 지향 설계와 실천" 책의 22장에 나오는 예제 코드임을 밝힙니다.
책을 읽던 중 평소에 테스트케이스를 작성하면서 가장 귀찮았고 보기 안 좋았던 부분에 대한 해결방법이 나와서
gist에 정리 후 블로그를 이용하여 포스트해봅니다.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//테스트를 위한 객체 생성이 복잡할때 (성가실때) | |
//AS-IS | |
@Test | |
public void chargesCustomerForTotalCostOfAllOrderedItems() { | |
Order order = new Order( | |
new Customer("Jang Yong Seok", new Address("Sanggyedong","Seoul",new PostCode("131","000")))); | |
order.addLine(new OrderLine("Cap", 1)); | |
order.addLine(new OrderLine("Shoes", 1)); | |
} | |
//TO-BE | |
new OrderBuilder().fromCustomer(new CutomerBuilder() | |
.withAddress(new AddressBuilder().withNoPostCode().build()) | |
.build()) | |
.build(); | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//비슷한 객체를 다수 생성해야할때 | |
//AS-IS | |
Order orderWithSmallDiscount = new OrderBuilder() | |
.withLine("cap", 1) | |
.withLine("shoes", 1) | |
.withDiscount(0.10) | |
.build(); | |
Order orderWithLargeDiscount = new OrderBuilder() | |
.withLine("cap", 1) | |
.withLine("shoes", 1) | |
.withDiscount(0.50) | |
.build(); | |
//TO-BE | |
OrderBuilder capAndShoes = new OrderBuilder() | |
.withLine("cap", 1) | |
.withLine("shoes", 1); | |
Order orderWithSmallDiscount = capAndShoes.withDiscount(0.10).build(); | |
Order orderWithLargeDiscount = capAndShoes.withDiscount(0.25).build(); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//상태의 Add 문제 | |
//AS-IS | |
OrderBuilder capAndShoes = new OrderBuilder() | |
.withLine("cap", 1) | |
.withLine("shoes", 1); | |
Order orderWithDiscount = capAndShoes.withDiscount(0.10).build(); | |
Order orderWithGiftVoucher = capAndShoes.withGiftVoucher("abc").build(); | |
//TO-BE | |
Order orderWithDiscount = new OrderBuilder(capAndShoes).withDiscount(0.10).build(); | |
Order orderWithGiftVoucher = new OrderBuilder(capAndShoes).withGiftVoucher("abc").build(); | |
//or return copy of builder | |
Order orderWithDiscount = capAndShoes.but().withDiscount(0.10).build(); | |
Order orderWithGiftVoucher = capAndShoes.but().withGiftVoucher("abc").build(); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//Builder 조합 | |
//AS-IS | |
Order orderWithNoPostCode = new OrderBuilder() | |
.fromCustomer( | |
new CustomerBuilder() | |
.withAddress(new AddressBuilder().withNoPostCode().build()) | |
.build()) | |
.build(); | |
//TO-BE | |
Order order = new OrderBuilder() | |
.fromCustomer(new CustomerBuilder() | |
.withAddress(new AddressBuilder().withNoPostCode()))) | |
.build(); | |
//빌더 생성 부분을 팩터리 메서드로.. | |
Order order = anOrder().fromCustomer(aCustomer().withAddress(anAddress().withNoPostCode())).build(); | |
//위 메서드에서 with, builder 메서드에 포함된 타입의 이름을 모두 제거 | |
Order order = anOrder().from(aCustomer().with(anAddress().withNoPostCode())).build(); |
1. Sample1.java
테스트를 위한 객체가 필요한데 이 객체를 생성하기위해 위와 같이 다수의 객체 혹은 String등을 입력해줘야 할때 사용 할 수 있는 방법입니다. Builder 클래스를 작성하는 것..
2. Sample2.java
비슷한 객체를 다수 생성해야 할때가 있습니다. 특정 필드의 값만 다른... 그럴때 사용하는 방법입니다.
3. Sample3.java
2의 예를 사용해서 테스트 데이터를 생성하다보면, 비슷한 이름의 필드에 대해서 값을 설정할때 문제가 발생 할 수 있습니다. 위 코드에서는 orderWithGiftVoucher의 discount 필드가 0.10으로 셋팅이 된 상태이죠. 하지만 코드상으로 이 부분이 명확하게 드러나지 않습니다. 그럴 때 Builder를 넘겨주거나 혹은 현재 상태를 지닌 Builder의 사본을 반환하는 팩터리 메서드(but())를 추가하는등의 방법입니다.
4.Sample4.java
Builder의 조합의 경우 build() 메서드의 다수 출현으로 코드가 산만해집니다. 이럴때 사용하는 방법이며, 팩터리 메서드를 이용해서 도메인 모델을 강조하는 방법도 나와있습니다.
gist가 파일마다 링크가 생성되면 좋은데.. 그렇게는 안되네요... :)