From dcf92126e8f3eb614159f8d76a5da84eb2fe82ea Mon Sep 17 00:00:00 2001 From: SONG22 Date: Sun, 9 May 2021 21:43:09 +0900 Subject: [PATCH 1/3] item 5 --- ...5\225\230\353\235\274_\354\225\210\354\206\241\354\235\264.md" | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 "2\354\236\245/5_\354\236\220\354\233\220\354\235\204_\354\247\201\354\240\221_\353\252\205\354\213\234\355\225\230\354\247\200_\353\247\220\352\263\240_\354\235\230\354\241\264 \352\260\235\354\262\264_\354\243\274\354\236\205\354\235\204_\354\202\254\354\232\251\355\225\230\353\235\274_\354\225\210\354\206\241\354\235\264.md" diff --git "a/2\354\236\245/5_\354\236\220\354\233\220\354\235\204_\354\247\201\354\240\221_\353\252\205\354\213\234\355\225\230\354\247\200_\353\247\220\352\263\240_\354\235\230\354\241\264 \352\260\235\354\262\264_\354\243\274\354\236\205\354\235\204_\354\202\254\354\232\251\355\225\230\353\235\274_\354\225\210\354\206\241\354\235\264.md" "b/2\354\236\245/5_\354\236\220\354\233\220\354\235\204_\354\247\201\354\240\221_\353\252\205\354\213\234\355\225\230\354\247\200_\353\247\220\352\263\240_\354\235\230\354\241\264 \352\260\235\354\262\264_\354\243\274\354\236\205\354\235\204_\354\202\254\354\232\251\355\225\230\353\235\274_\354\225\210\354\206\241\354\235\264.md" new file mode 100644 index 0000000..e69de29 From e40107a301f67e5b7793447485aeea2bbcbc1787 Mon Sep 17 00:00:00 2001 From: SSONG22 <35327776+SSONG22@users.noreply.github.com> Date: Sun, 9 May 2021 21:53:57 +0900 Subject: [PATCH 2/3] item 5 --- ...4_\354\225\210\354\206\241\354\235\264.md" | 257 ++++++++++++++++++ 1 file changed, 257 insertions(+) diff --git "a/2\354\236\245/5_\354\236\220\354\233\220\354\235\204_\354\247\201\354\240\221_\353\252\205\354\213\234\355\225\230\354\247\200_\353\247\220\352\263\240_\354\235\230\354\241\264 \352\260\235\354\262\264_\354\243\274\354\236\205\354\235\204_\354\202\254\354\232\251\355\225\230\353\235\274_\354\225\210\354\206\241\354\235\264.md" "b/2\354\236\245/5_\354\236\220\354\233\220\354\235\204_\354\247\201\354\240\221_\353\252\205\354\213\234\355\225\230\354\247\200_\353\247\220\352\263\240_\354\235\230\354\241\264 \352\260\235\354\262\264_\354\243\274\354\236\205\354\235\204_\354\202\254\354\232\251\355\225\230\353\235\274_\354\225\210\354\206\241\354\235\264.md" index e69de29..d347800 100644 --- "a/2\354\236\245/5_\354\236\220\354\233\220\354\235\204_\354\247\201\354\240\221_\353\252\205\354\213\234\355\225\230\354\247\200_\353\247\220\352\263\240_\354\235\230\354\241\264 \352\260\235\354\262\264_\354\243\274\354\236\205\354\235\204_\354\202\254\354\232\251\355\225\230\353\235\274_\354\225\210\354\206\241\354\235\264.md" +++ "b/2\354\236\245/5_\354\236\220\354\233\220\354\235\204_\354\247\201\354\240\221_\353\252\205\354\213\234\355\225\230\354\247\200_\353\247\220\352\263\240_\354\235\230\354\241\264 \352\260\235\354\262\264_\354\243\274\354\236\205\354\235\204_\354\202\254\354\232\251\355\225\230\353\235\274_\354\225\210\354\206\241\354\235\264.md" @@ -0,0 +1,257 @@ +# 아이템 5 자원을 직접 명시하지 말고 의존 객체 주입을 사용하라 + +--- + +> 클래스가 내부적으로 하나 이상의 **자원**에 의존하고, +그 자원이 클래스 동작에 영향을 준다면 +싱글턴(Singleton) 과, 정적 유틸리티(static util class)는 사용하지 않는 것이 좋다. + +*즉, 사용하는 자원에 따라 동작이 달라지는 클래스에는 정적 유틸리티 클래스나 싱글턴 방식이 적합하지 않다.* + +- 정적 유틸리티를 잘못 사용한 예 - 유연하지 않고 테스트하기 어렵다 + + ```java + // 정적 유틸리티를 잘못 사용한 예 - 유연하지 않고 테스트하기 어렵다 + public class SpellChecker{ + private static final Lexicon dictionary = ...; // 사전에 의존 + private SpellChecker() {} // 객체 생성 방지 + public static boolean isValid(String word){...} + public static List suggestions(String typo){...} + } + ``` + +- 싱글턴을 잘못 사용한 예 - 유연하지 않고 테스트하기 어렵다 + + ```java + // 싱글턴을 잘못 사용한 예 - 유연하지 않고 테스트하기 어렵다 + public class SpellChecker{ + private static final Lexicon dictionary = ...; // 사전에 의존 + private SpellChecker(...) {} + public static SpellChecker INSTANCE = new SpellChecker(...); + + public static boolean isValid(String word){...} + public static List suggestions(String typo){...} + + } + ``` + +- SpellChecker 클래스는 dictionary(자원)에 의존하고 있다 +- 그런데, 언어별 사전, 특수 어휘용 사전이 필요하게 되면 클래스 내부 메서드 동작이 달라져야 한다. +- 정적 유틸리티 클래스나 싱글턴 방식은 적합하지 않다. + +> 왜냐하면, 유연하지 않고, 테스트 하기 어렵기 때문이다. + +- SpellChecker가 여러 사전을 사용할 수 있도록 만들기 위해 dictionary 필드에서 final 한정자를 제거하고 다른 사전으로 교체하는 메서드를 추가할 수는 있다. +- 그러나 이 방법은 어색하며, 오류를 내기 쉽다. 또한 멀티스레드 환경에서는 쓸 수 없다. + +> 클래스가 여러 자원 인스턴스를 지원해야하고, 클라이언트가 원하는 자원을 사용하게 하는 방법을 사용해야 한다. +인스턴스를 생성할 때 생성자에 필요한 자원을 넘겨주자. + +- **의존 객체 주입 방식** 이라고한다. + + ```java + // 의존 객체 주입은 유연성과 테스트 용이성을 높여준다 + public class SpellChecker{ + private final Lexicon dictionary; + public SpellChecker(Lexicon dictionary){ + this.dictionay = Objects.requiredNonNull(dictionay); + } + public boolean isValid(String word){...} + public List suggestions(String typo){...} + } + ``` + +- 클래스의 유연성, 재사용성, 테스트 용이성을 개선 해준다. +- 불변을 보장해 해당 자원을 사용하려는 여러 클라이언트가 의존 객체들을 안심하고 공유할 수 있다. +- 생성자, 정적 팩터리, 빌더 아이템에 응용할 수 있다. + +```java +public class 배달서비스{ + private final 배달 치킨배달; + // 정적 유틸리티 + private 배달서비스(){}; //객체 생성 방지 + public static void 배달시작(){} +} +public class 배달서비스{ + private final 배달 치킨배달; + private 배달서비스(..){..}; + public static 배달서비스 Instance = new 배달음식서비스(..); // 싱글턴 패턴 + public static void 배달시작(){} +} +// 치킨배달만 가능하다 ... +``` + +```java +public class 배달서비스{ + private final 배달 음식배달; + public 배달서비스(배달 음식이름){ + this.음식배달 = 음식이름; + } + public static void 배달시작(){} +} +// 어떤 음식도 배달할 수 있는 서비스가 되었다 ! +``` + +> 의존 객체 주입 응용 : 생성자에 자원 팩터리(Factory) 를 넘겨 주는 방식 + +- 팩터리(Factory) : 호출할 때마다 특정 타입의 인스턴스를 반복해서 만들어주는 객체 +- 팩터리 메서드 패턴 (Factory Method pattern) : 생성자에 자원 팩터리를 넘겨주는 방식 + +
+ 팩터리 메서드 패턴 +
+ +- 팩터리 메서드 패턴 + - 객체 생성을 캡슐화 하는 패턴이다 + - 객체를 생성하기 위한 인터페이스를 정의하지만, 어떤 클래스의 인스턴스를 생성할지에 대한 결정은 서브 클래스가 내린다. + - Creator의 서브 클래스에 팩토리 메서드를 정의 하며, 팩터리 메서드 호출로 ConcreteProduct 인스턴스를 반환하게 한다. + - 예제코드 + + ```java + // Product 역할 + public interface Shopping { + // 쇼핑을 할 때 공통 과정 + void find(); + void cart(); + void order(); + } + + // Creator (Factory) + public abstract class Shop { + public Shopping shopping(String category){ + Shopping shopping = selectCategory(category); + shopping.find(); + shopping.cart(); + shopping.order(); + return shopping; + } + + // factory method + abstract Shopping selectCategory(String category); + } + ``` + + ```java + public class MarketOne extends Shop { + @Override + Shopping selectCategory(String category) { + System.out.println("THIS IS MARKET ONE."); + if (category.equals("FOOD")) return new MarketOneFoodCategory(); + if (category.equals("HEALTH")) return new MarketOneHealthCategory(); + return null; + } + } + public class MarketOneFoodCategory implements Shopping { + @Override + public void find() { + System.out.println("market-one: food 검색 "); + } + + @Override + public void cart() { + System.out.println("market-one: food 담기 "); + } + + @Override + public void order() { + System.out.println("market-one: food 주문 "); + } + } + ``` +
+
+ +--- + +- 의존성이 수천개가 되는 큰 프로젝트에서는 의존 객체 주입이 코드를 어지럽게 만들기도 한다. +- 대거, 주스, 스프링 같은 의존 객체 주입 프레임워크를 사용하면 이런 어질러짐을 해소할 수 있다. + +
+스프링 의존성 주입 +
+ +- 스프링 의존성 주입 + + ```java + @Service + public class ShopService{ + public void findAllShop(){ + ShopRepository shopRepository = new FoodShop(); + shopRepository.findAll(); + } + } + ``` + + - 스프링 핵심 기능 DI (Dependency Injection) + + **외부**(IOC컨테이너) 에서 객체를 생성한 후 의존성을 주입시킨다 + + ```java + @Service + public class ShopService{ + private ShopRepository shopRepository; + public ShopService(ShopRepository shopRepository){ + this.shopRepository = shopRepository; + } + public void findAllShop(){ + shopRepository.findAll(); + } + } + + @Test + public class testFindAll(){ + ShopRepository foodShop = new FoodShop(); + ShopService shopService = new ShopService(foodShop); + shopService.findAll(); + } + ``` + + 의존성 주입방법 + + 1. 생성자 이용 + + ```java + @Service + public class ShopService{ + private ShopRepository shopRepository; + public ShopService(ShopRepository shopRepository){ + this.shopRepository = shopRepository; + } + } + ``` + + 2. Field 변수 이용 + + ```java + @Service + public class ShopService{ + @Autowired + private ShopRepository shopRepository; + } + ``` + + 3. setter 이용 + + ```java + @Service + public class ShopService{ + private ShopRepository shopRepository; + @Autowired + public ShopService(ShopRepository shopRepository){ + this.shopRepository = shopRepository; + } + } + ``` + + +
+
+ +--- + + +### 핵심 정리 + +- 클래스가 내부적으로 하나 이상의 자원에 의존하고, 그 자원이 클래스 동작에 영향을 준다면 싱글턴과 정적 유틸리티 클래스는 사용하지 말자. +- 이 자원들을 클래스가 직접 만들게 해서도 안된다. +- 필요한 자원을 (혹은 그 자원을 만들어주는 팩터리를) 생성자에 (혹은 정적 팩터리나 빌더에) 넘겨주자. 의존 객체 주입이라 하는 이 기법은 클래스의 유연성, 재사용성, 테스트 용이성을 기막히게 개선해준다. From 1a4f7a4e11ba235d45e98f119fadff88c4cec4e5 Mon Sep 17 00:00:00 2001 From: SSONG22 <35327776+SSONG22@users.noreply.github.com> Date: Tue, 11 May 2021 20:01:11 +0900 Subject: [PATCH 3/3] update item 5 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 내용 추가 --- ...235\274_\354\225\210\354\206\241\354\235\264.md" | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git "a/2\354\236\245/5_\354\236\220\354\233\220\354\235\204_\354\247\201\354\240\221_\353\252\205\354\213\234\355\225\230\354\247\200_\353\247\220\352\263\240_\354\235\230\354\241\264 \352\260\235\354\262\264_\354\243\274\354\236\205\354\235\204_\354\202\254\354\232\251\355\225\230\353\235\274_\354\225\210\354\206\241\354\235\264.md" "b/2\354\236\245/5_\354\236\220\354\233\220\354\235\204_\354\247\201\354\240\221_\353\252\205\354\213\234\355\225\230\354\247\200_\353\247\220\352\263\240_\354\235\230\354\241\264 \352\260\235\354\262\264_\354\243\274\354\236\205\354\235\204_\354\202\254\354\232\251\355\225\230\353\235\274_\354\225\210\354\206\241\354\235\264.md" index d347800..3918372 100644 --- "a/2\354\236\245/5_\354\236\220\354\233\220\354\235\204_\354\247\201\354\240\221_\353\252\205\354\213\234\355\225\230\354\247\200_\353\247\220\352\263\240_\354\235\230\354\241\264 \352\260\235\354\262\264_\354\243\274\354\236\205\354\235\204_\354\202\254\354\232\251\355\225\230\353\235\274_\354\225\210\354\206\241\354\235\264.md" +++ "b/2\354\236\245/5_\354\236\220\354\233\220\354\235\204_\354\247\201\354\240\221_\353\252\205\354\213\234\355\225\230\354\247\200_\353\247\220\352\263\240_\354\235\230\354\241\264 \352\260\235\354\262\264_\354\243\274\354\236\205\354\235\204_\354\202\254\354\232\251\355\225\230\353\235\274_\354\225\210\354\206\241\354\235\264.md" @@ -161,6 +161,12 @@ public class 배달서비스{ +- 자바 8의 Supplier 인터페이스가 리소스의 생성자에 전달하는 팩터리로 쓰기에 적합하다. + + ```java + Mosaic create(Supplier tileFactory){..} + ``` + --- - 의존성이 수천개가 되는 큰 프로젝트에서는 의존 객체 주입이 코드를 어지럽게 만들기도 한다. @@ -171,6 +177,9 @@ public class 배달서비스{
- 스프링 의존성 주입 + - 스프링 핵심 기능 DI (Dependency Injection) + + **외부**(IOC컨테이너) 에서 객체를 생성한 후 의존성을 주입시킨다 ```java @Service @@ -182,10 +191,6 @@ public class 배달서비스{ } ``` - - 스프링 핵심 기능 DI (Dependency Injection) - - **외부**(IOC컨테이너) 에서 객체를 생성한 후 의존성을 주입시킨다 - ```java @Service public class ShopService{