diff --git a/ria/gof/src/main/kotlin/com/gof/pattern/builder/after/App.kt b/ria/gof/src/main/kotlin/com/gof/pattern/builder/after/App.kt new file mode 100644 index 0000000..9b4495d --- /dev/null +++ b/ria/gof/src/main/kotlin/com/gof/pattern/builder/after/App.kt @@ -0,0 +1,9 @@ +package com.gof.pattern.builder.after + +class App + +fun main() { + var director = TourDirector(DefaultTourBuilder()) + val cancunTrip = director.cancunTrip() + val longBeachTrip = director.longBeachTrip() +} diff --git a/ria/gof/src/main/kotlin/com/gof/pattern/builder/after/DefaultTourBuilder.kt b/ria/gof/src/main/kotlin/com/gof/pattern/builder/after/DefaultTourBuilder.kt new file mode 100644 index 0000000..41c316d --- /dev/null +++ b/ria/gof/src/main/kotlin/com/gof/pattern/builder/after/DefaultTourBuilder.kt @@ -0,0 +1,48 @@ +package com.gof.pattern.builder.after + +import com.gof.pattern.builder.before.DetailPlan +import com.gof.pattern.builder.before.TourPlan +import java.time.LocalDate + +class DefaultTourBuilder : TourPlanBuilder { + + var title: String? = null + var nights: Int = 0 + var days: Int = 0 + var startDate: LocalDate? = null + var whereToStay: String? = null + var plans: MutableList = mutableListOf() + + override fun title(title: String): TourPlanBuilder { + this.title = title + return this + } + + override fun nightsAndDays(nights: Int, days: Int): TourPlanBuilder { + this.nights = nights + this.days = days + return this + } + + override fun startDate(localDate: LocalDate): TourPlanBuilder { + this.startDate = startDate + return this + } + + override fun whereToStay(whereToStay: String): TourPlanBuilder { + this.whereToStay = whereToStay + return this + } + + override fun addPlan(day: Int, plan: String): TourPlanBuilder { + if (this.plans == null) { + this.plans = mutableListOf() + } + plans.add(DetailPlan(day, plan)) + return this + } + + override fun getPlan(): TourPlan { + return TourPlan(title, nights, days, startDate, whereToStay, plans) + } +} diff --git a/ria/gof/src/main/kotlin/com/gof/pattern/builder/after/TourDirector.kt b/ria/gof/src/main/kotlin/com/gof/pattern/builder/after/TourDirector.kt new file mode 100644 index 0000000..578fc41 --- /dev/null +++ b/ria/gof/src/main/kotlin/com/gof/pattern/builder/after/TourDirector.kt @@ -0,0 +1,22 @@ +package com.gof.pattern.builder.after + +import com.gof.pattern.builder.before.TourPlan +import java.time.LocalDate + +class TourDirector(private val tourPlanBuilder: TourPlanBuilder) { + fun cancunTrip(): TourPlan { + return tourPlanBuilder.title("칸쿤 여행") + .nightsAndDays(2, 3) + .startDate(LocalDate.of(2024, 1, 3)) + .whereToStay("리조트") + .addPlan(0, "체크인하고 짐 풀기") + .addPlan(0, "저녁 식사") + .getPlan() + } + + fun longBeachTrip(): TourPlan { + return tourPlanBuilder.title("롱비치") + .startDate(LocalDate.of(2024, 3, 4)) + .getPlan() + } +} diff --git a/ria/gof/src/main/kotlin/com/gof/pattern/builder/after/TourPlanBuilder.kt b/ria/gof/src/main/kotlin/com/gof/pattern/builder/after/TourPlanBuilder.kt new file mode 100644 index 0000000..386b4e6 --- /dev/null +++ b/ria/gof/src/main/kotlin/com/gof/pattern/builder/after/TourPlanBuilder.kt @@ -0,0 +1,14 @@ +package com.gof.pattern.builder.after + +import com.gof.pattern.builder.before.TourPlan +import java.time.LocalDate + +interface TourPlanBuilder { + + fun title(title: String): TourPlanBuilder + fun nightsAndDays(nights: Int, days: Int): TourPlanBuilder + fun startDate(localDate: LocalDate): TourPlanBuilder + fun whereToStay(whereToStay: String): TourPlanBuilder + fun addPlan(day: Int, plan: String): TourPlanBuilder + fun getPlan(): TourPlan +} diff --git a/ria/gof/src/main/kotlin/com/gof/pattern/builder/before/App.kt b/ria/gof/src/main/kotlin/com/gof/pattern/builder/before/App.kt new file mode 100644 index 0000000..c3b385a --- /dev/null +++ b/ria/gof/src/main/kotlin/com/gof/pattern/builder/before/App.kt @@ -0,0 +1,22 @@ +package com.gof.pattern.builder.before + +import java.time.LocalDate + +class App + +fun main() { + var shortTrip = TourPlan() + shortTrip.title = "세노떼 여행" + shortTrip.startDate = LocalDate.of(2023, 10, 11) + + var tourPlan = TourPlan() + tourPlan.title = "칸쿤 여행" + tourPlan.nights = 2 + tourPlan.days = 3 + tourPlan.startDate = LocalDate.of(2024, 3, 2) + tourPlan.whereToStay = "리조트" + tourPlan.addPlan(0, "체크인 이후 짐풀기") + tourPlan.addPlan(1, "조식 뷔페에서 식사") + tourPlan.addPlan(1, "수영하기") + tourPlan.addPlan(2, "체크아웃") +} diff --git a/ria/gof/src/main/kotlin/com/gof/pattern/builder/before/DetailPlan.kt b/ria/gof/src/main/kotlin/com/gof/pattern/builder/before/DetailPlan.kt new file mode 100644 index 0000000..8841e88 --- /dev/null +++ b/ria/gof/src/main/kotlin/com/gof/pattern/builder/before/DetailPlan.kt @@ -0,0 +1,3 @@ +package com.gof.pattern.builder.before + +class DetailPlan(var day: Int, var plan: String) diff --git a/ria/gof/src/main/kotlin/com/gof/pattern/builder/before/TourPlan.kt b/ria/gof/src/main/kotlin/com/gof/pattern/builder/before/TourPlan.kt new file mode 100644 index 0000000..250c45c --- /dev/null +++ b/ria/gof/src/main/kotlin/com/gof/pattern/builder/before/TourPlan.kt @@ -0,0 +1,38 @@ +package com.gof.pattern.builder.before + +import java.time.LocalDate + +class TourPlan { + + var title: String? = null + var nights: Int = 0 + var days: Int = 0 + var startDate: LocalDate? = null + var whereToStay: String? = null + var plans: MutableList = mutableListOf() + + constructor() + + constructor( + title: String?, + nights: Int, + days: Int, + startDate: LocalDate?, + whereToStay: String?, + plans: MutableList + ) { + this.title = title + this.nights = nights + this.days = days + this.startDate = startDate + this.whereToStay = whereToStay + this.plans = plans + } + + fun addPlan(day: Int, plan: String) { + if (this.plans == null) { + this.plans = mutableListOf() + } + this.plans.add(DetailPlan(day, plan)) + } +} diff --git a/ria/gof/src/test/kotlin/com/gof/pattern/builder/after/AppKtTest.kt b/ria/gof/src/test/kotlin/com/gof/pattern/builder/after/AppKtTest.kt new file mode 100644 index 0000000..5f816f9 --- /dev/null +++ b/ria/gof/src/test/kotlin/com/gof/pattern/builder/after/AppKtTest.kt @@ -0,0 +1,19 @@ +package com.gof.pattern.builder.after + +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Test + +class AppKtTest { + + @Test + fun `빌더패턴 적용 후 성공 테스트`() { + // given + var director = TourDirector(DefaultTourBuilder()) + // when + val cancunTrip = director.cancunTrip() + // then + assertThat(cancunTrip.title).isEqualTo("칸쿤 여행") + assertThat(cancunTrip.whereToStay).isEqualTo("리조트") + assertThat(cancunTrip.plans.map { it.plan }).contains("저녁 식사") + } +} diff --git a/ria/gof/src/test/kotlin/com/gof/pattern/builder/before/AppKtTest.kt b/ria/gof/src/test/kotlin/com/gof/pattern/builder/before/AppKtTest.kt new file mode 100644 index 0000000..0c4c6c7 --- /dev/null +++ b/ria/gof/src/test/kotlin/com/gof/pattern/builder/before/AppKtTest.kt @@ -0,0 +1,40 @@ +package com.gof.pattern.builder.before + +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.DisplayName +import org.junit.jupiter.api.Test +import java.time.LocalDate + +class AppKtTest { + + @Test + @DisplayName("빌더 패턴 적용 전 성공 테스트") + fun beforeBuilderSuccessTest() { + // given + val plan = TourPlan() + // when + plan.title = "세노떼 여행" + plan.startDate = LocalDate.of(2023, 11, 4) + plan.whereToStay = "리조트" + // then + assertThat(plan.title).isEqualTo("세노떼 여행") + assertThat(plan.whereToStay).isEqualTo("리조트") + } + + @Test + @DisplayName("빌더 패턴 적용 전 실패 테스트") + fun beforeBuilderFailTest() { + // given + var title: String = "세노떼 여행" + var nights: Int = 2 + var days: Int = 3 + var startDate: LocalDate = LocalDate.of(2024, 7, 2) + var whereToStay: String = "리조트" + var plans: MutableList = mutableListOf() + // then + var plan = TourPlan(whereToStay, days, nights, startDate, title, plans) + // then + assertThat(plan.title).isEqualTo("세노떼 여행") + assertThat(plan.whereToStay).isEqualTo("리조트") + } +} diff --git a/ria/java/gof/src/main/java/com/gof/pattern/builder/after/App.java b/ria/java/gof/src/main/java/com/gof/pattern/builder/after/App.java new file mode 100644 index 0000000..c8fabef --- /dev/null +++ b/ria/java/gof/src/main/java/com/gof/pattern/builder/after/App.java @@ -0,0 +1,29 @@ +package com.gof.pattern.builder.after; + +import com.gof.pattern.builder.before.TourPlan; + +/** + * 빌더패턴 + * 장점) 구체 로직 은닉, 다양한 빌더를 통해 다양한 로직 구현 가능 + * 단점) 구조가 복잡해짐, 빌더 사용을 위한 인스턴스 생성 + */ +public class App { + public static void main(String[] args) { +// DefaultTourBuilder builder = new DefaultTourBuilder(); +// TourPlan plan = builder.title("칸쿤 여행") +// .nightsAndDays(2, 3) +// .startDate(LocalDate.of(2023, 8, 29)) +// .whereToStay("리조트") +// .addPlan(0, "체크인하고 짐 풀기") +// .addPlan(0, "저녁 식사") +// .getPlan(); +// +// TourPlan longBeachTrip = builder.title("롱비치") +// .startDate(LocalDate.of(2023, 10, 5)) +// .getPlan(); + + TourDirector director = new TourDirector(new DefaultTourBuilder()); + TourPlan cancunTrip = director.cancunTrip(); + TourPlan longBeachTrip = director.longBeachTrip(); + } +} diff --git a/ria/java/gof/src/main/java/com/gof/pattern/builder/after/DefaultTourBuilder.java b/ria/java/gof/src/main/java/com/gof/pattern/builder/after/DefaultTourBuilder.java new file mode 100644 index 0000000..3410f75 --- /dev/null +++ b/ria/java/gof/src/main/java/com/gof/pattern/builder/after/DefaultTourBuilder.java @@ -0,0 +1,57 @@ +package com.gof.pattern.builder.after; + +import com.gof.pattern.builder.before.DetailPlan; +import com.gof.pattern.builder.before.TourPlan; + +import java.time.LocalDate; +import java.util.ArrayList; +import java.util.List; + +public class DefaultTourBuilder implements TourPlanBuilder { + + private String title; + private int nights; + private int days; + private LocalDate startDate; + private String whereToStay; + private List plans; + + @Override + public TourPlanBuilder title(String title) { + this.title = title; + return this; + } + + @Override + public TourPlanBuilder nightsAndDays(int nights, int days) { + this.nights = nights; + this.days = days; + return this; + } + + @Override + public TourPlanBuilder startDate(LocalDate startDate) { + this.startDate = startDate; + return this; + } + + @Override + public TourPlanBuilder whereToStay(String whereToStay) { + this.whereToStay = whereToStay; + return this; + } + + @Override + public TourPlanBuilder addPlan(int day, String plan) { + if (this.plans == null) { + this.plans = new ArrayList<>(); + } + this.plans.add(new DetailPlan(day, plan)); + return this; + } + + @Override + public TourPlan getPlan() { + return new TourPlan(title, nights, days, startDate, whereToStay, plans); + } +} diff --git a/ria/java/gof/src/main/java/com/gof/pattern/builder/after/TourDirector.java b/ria/java/gof/src/main/java/com/gof/pattern/builder/after/TourDirector.java new file mode 100644 index 0000000..eac9bf1 --- /dev/null +++ b/ria/java/gof/src/main/java/com/gof/pattern/builder/after/TourDirector.java @@ -0,0 +1,30 @@ +package com.gof.pattern.builder.after; + +import com.gof.pattern.builder.before.TourPlan; + +import java.time.LocalDate; + +public class TourDirector { + + private TourPlanBuilder tourPlanBuilder; + + public TourDirector(TourPlanBuilder tourPlanBuilder) { + this.tourPlanBuilder = tourPlanBuilder; + } + + public TourPlan cancunTrip() { + return tourPlanBuilder.title("칸쿤 여행") + .nightsAndDays(2, 3) + .startDate(LocalDate.of(2023, 8, 29)) + .whereToStay("리조트") + .addPlan(0, "체크인하고 짐 풀기") + .addPlan(0, "저녁 식사") + .getPlan(); + } + + public TourPlan longBeachTrip() { + return tourPlanBuilder.title("롱비치") + .startDate(LocalDate.of(2023, 10, 5)) + .getPlan(); + } +} diff --git a/ria/java/gof/src/main/java/com/gof/pattern/builder/after/TourPlanBuilder.java b/ria/java/gof/src/main/java/com/gof/pattern/builder/after/TourPlanBuilder.java new file mode 100644 index 0000000..74f1ee4 --- /dev/null +++ b/ria/java/gof/src/main/java/com/gof/pattern/builder/after/TourPlanBuilder.java @@ -0,0 +1,20 @@ +package com.gof.pattern.builder.after; + +import com.gof.pattern.builder.before.TourPlan; + +import java.time.LocalDate; + +public interface TourPlanBuilder { + + TourPlanBuilder title(String title); + + TourPlanBuilder nightsAndDays(int nights, int days); + + TourPlanBuilder startDate(LocalDate localDate); + + TourPlanBuilder whereToStay(String whereToStay); + + TourPlanBuilder addPlan(int day, String plan); + + TourPlan getPlan(); +} diff --git a/ria/java/gof/src/main/java/com/gof/pattern/builder/before/App.java b/ria/java/gof/src/main/java/com/gof/pattern/builder/before/App.java new file mode 100644 index 0000000..dc67bd1 --- /dev/null +++ b/ria/java/gof/src/main/java/com/gof/pattern/builder/before/App.java @@ -0,0 +1,24 @@ +package com.gof.pattern.builder.before; + +import java.time.LocalDate; + +public class App { + + public static void main(String[] args) { + TourPlan shortTrip = new TourPlan(); + shortTrip.setTitle("세노떼 여행"); + shortTrip.setStartDate(LocalDate.of(2023, 11, 12)); + + TourPlan tourPlan = new TourPlan(); + tourPlan.setTitle("칸쿤 여행"); + tourPlan.setNights(2); + tourPlan.setDays(3); + tourPlan.setStartDate(LocalDate.of(2023, 11, 29)); + tourPlan.setWhereToStay("리조트"); + tourPlan.addPlan(0, "체크인 이후 짐풀기"); + tourPlan.addPlan(0, "저녁 식사"); + tourPlan.addPlan(1, "조식 뷔페에서 식사"); + tourPlan.addPlan(1, "해변가 산책"); + tourPlan.addPlan(2, "체크아웃"); + } +} diff --git a/ria/java/gof/src/main/java/com/gof/pattern/builder/before/DetailPlan.java b/ria/java/gof/src/main/java/com/gof/pattern/builder/before/DetailPlan.java new file mode 100644 index 0000000..7911ddd --- /dev/null +++ b/ria/java/gof/src/main/java/com/gof/pattern/builder/before/DetailPlan.java @@ -0,0 +1,11 @@ +package com.gof.pattern.builder.before; + +public class DetailPlan { + private int day; + private String plan; + + public DetailPlan(int day, String plan) { + this.day = day; + this.plan = plan; + } +} diff --git a/ria/java/gof/src/main/java/com/gof/pattern/builder/before/TourPlan.java b/ria/java/gof/src/main/java/com/gof/pattern/builder/before/TourPlan.java new file mode 100644 index 0000000..58ff393 --- /dev/null +++ b/ria/java/gof/src/main/java/com/gof/pattern/builder/before/TourPlan.java @@ -0,0 +1,82 @@ +package com.gof.pattern.builder.before; + +import java.time.LocalDate; +import java.util.ArrayList; +import java.util.List; + +public class TourPlan { + + private String title; + private int nights; + private int days; + private LocalDate startDate; + private String whereToStay; + private List plans; + + public TourPlan() { + } + + public TourPlan(String title, int nights, int days, LocalDate startDate, String whereToStay, List plans) { + this.title = title; + this.nights = nights; + this.days = days; + this.startDate = startDate; + this.whereToStay = whereToStay; + this.plans = plans; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public int getNights() { + return nights; + } + + public void setNights(int nights) { + this.nights = nights; + } + + public int getDays() { + return days; + } + + public void setDays(int days) { + this.days = days; + } + + public LocalDate getStartDate() { + return startDate; + } + + public void setStartDate(LocalDate startDate) { + this.startDate = startDate; + } + + public String getWhereToStay() { + return whereToStay; + } + + public void setWhereToStay(String whereToStay) { + this.whereToStay = whereToStay; + } + + public List getPlans() { + return plans; + } + + public void setPlans(List plans) { + this.plans = plans; + } + + public void addPlan(int day, String plan) { + if (this.plans == null) { + this.plans = new ArrayList<>(); + } + this.plans.add(new DetailPlan(day, plan)); + } +} diff --git a/ria/java/gof/src/main/java/com/gof/pattern/builder/java/LombokExample.java b/ria/java/gof/src/main/java/com/gof/pattern/builder/java/LombokExample.java new file mode 100644 index 0000000..eb5362f --- /dev/null +++ b/ria/java/gof/src/main/java/com/gof/pattern/builder/java/LombokExample.java @@ -0,0 +1,19 @@ +package com.gof.pattern.builder.java; + +import lombok.Builder; + +@Builder +public class LombokExample { + + private String title; + private int nights; + private int days; + + public static void main(String[] args) { + LombokExample trip = LombokExample.builder() + .title("여행") + .nights(2) + .days(3) + .build(); + } +} diff --git a/ria/java/gof/src/main/java/com/gof/pattern/builder/java/SpringExample.java b/ria/java/gof/src/main/java/com/gof/pattern/builder/java/SpringExample.java new file mode 100644 index 0000000..3c83623 --- /dev/null +++ b/ria/java/gof/src/main/java/com/gof/pattern/builder/java/SpringExample.java @@ -0,0 +1,18 @@ +package com.gof.pattern.builder.java; + +import org.springframework.web.util.UriComponents; +import org.springframework.web.util.UriComponentsBuilder; + +/** + * uri를 문자열로 만들 때보다 안전하게 만들 수 있음 + */ +public class SpringExample { + public static void main(String[] args) { + UriComponents howToStudyJava = UriComponentsBuilder.newInstance() + .scheme("http") + .host("www.whiteship.me") + .path("java-playList-ep1") + .build().encode(); + System.out.println("howToStudyJava = " + howToStudyJava); + } +} diff --git a/ria/java/gof/src/main/java/com/gof/pattern/builder/java/StreamExample.java b/ria/java/gof/src/main/java/com/gof/pattern/builder/java/StreamExample.java new file mode 100644 index 0000000..e026c2c --- /dev/null +++ b/ria/java/gof/src/main/java/com/gof/pattern/builder/java/StreamExample.java @@ -0,0 +1,10 @@ +package com.gof.pattern.builder.java; + +import java.util.stream.Stream; + +public class StreamExample { + public static void main(String[] args) { + Stream names = Stream.builder().add("keesun").add("whiteship").build(); + names.forEach(System.out::println); + } +} diff --git a/ria/java/gof/src/main/java/com/gof/pattern/builder/java/StringBuilderExample.java b/ria/java/gof/src/main/java/com/gof/pattern/builder/java/StringBuilderExample.java new file mode 100644 index 0000000..525155a --- /dev/null +++ b/ria/java/gof/src/main/java/com/gof/pattern/builder/java/StringBuilderExample.java @@ -0,0 +1,12 @@ +package com.gof.pattern.builder.java; + +public class StringBuilderExample { + public static void main(String[] args) { + // synchronized 사용x + StringBuilder stringBuilder = new StringBuilder(); + String result = stringBuilder.append("whiteship") + .append("keesun") + .toString(); + System.out.println("result = " + result); + } +} diff --git a/ria/java/gof/src/test/java/com/gof/pattern/builder/after/AppTest.java b/ria/java/gof/src/test/java/com/gof/pattern/builder/after/AppTest.java new file mode 100644 index 0000000..93932c3 --- /dev/null +++ b/ria/java/gof/src/test/java/com/gof/pattern/builder/after/AppTest.java @@ -0,0 +1,23 @@ +package com.gof.pattern.builder.after; + +import com.gof.pattern.builder.before.TourPlan; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +class AppTest { + + @Test + @DisplayName("빌더 패턴 적용 후 성공 테스트") + void afterBuilderSuccessTest() { + // given + TourDirector director = new TourDirector(new DefaultTourBuilder()); + // when + TourPlan cancunTrip = director.cancunTrip(); + // then + assertThat(cancunTrip.getTitle()).isEqualTo("칸쿤 여행"); + assertThat(cancunTrip.getWhereToStay()).isEqualTo("리조트"); + assertThat(cancunTrip.getPlans().contains("저녁 식사")); + } +} \ No newline at end of file diff --git a/ria/java/gof/src/test/java/com/gof/pattern/builder/before/AppTest.java b/ria/java/gof/src/test/java/com/gof/pattern/builder/before/AppTest.java new file mode 100644 index 0000000..e047359 --- /dev/null +++ b/ria/java/gof/src/test/java/com/gof/pattern/builder/before/AppTest.java @@ -0,0 +1,47 @@ +package com.gof.pattern.builder.before; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import java.time.LocalDate; +import java.util.ArrayList; +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; + +class AppTest { + + @Test + @DisplayName("빌더 패턴 적용 전 성공 테스트") + void beforeBuilderSuccessTest() { + // given + TourPlan plan = new TourPlan(); + // when + plan.setTitle("세노떼 여행"); + plan.setStartDate(LocalDate.of(2023, 11, 23)); + plan.setWhereToStay("리조트"); + // then + assertThat(plan.getTitle()).isEqualTo("세노떼 여행"); + assertThat(plan.getWhereToStay()).isEqualTo("리조트"); + } + + /** + * 생성자 호출 시 순서 보장x + */ + @Test + @DisplayName("빌더 패턴 적용 전 실패 테스트") + void beforeBuilderFailTest() { + // given + String title = "세노떼 여행"; + int nights = 2; + int days = 3; + LocalDate startDate = LocalDate.of(2023, 11, 11); + String whereToStay = "리조트"; + List plans = new ArrayList<>(); + // when + TourPlan plan = new TourPlan(whereToStay, days, nights, startDate, title, plans); + // then + assertThat(plan.getTitle()).isEqualTo("세노떼 여행"); + assertThat(plan.getDays()).isEqualTo(3); + } +} \ No newline at end of file