Dependency Injection 소개

6,917 views

Published on

Dependency Injection 개요 및 장점 등

Published in: Technology, Business

Dependency Injection 소개

  1. 1. Dependency Injection 소개<br />최범균(madvirus@madvirus.net)<br />
  2. 2. TOC<br />DI<br />의존<br />의존 처리<br />DI<br />장점<br />
  3. 3. 기능 구현을 위한 코드 구성<br />게시글 쓰기<br />게시판 정보조회<br />게시글 쓰기 폼<br />게시글 쓰기 요청 처리<br />게시글 ID/정렬값생성<br />데이터 검증<br />게시글 데이터 삽입<br />
  4. 4. Monolithic 코드의 문제<br />
  5. 5. 단일 -> 분리<br />유지/보수 측면에서 단일 클래스보다 역할 별 분리된 클래스가 유리<br />(코드 가독성, 기능 추가, 변경, 확장 등)<br />게시글 쓰기<br />게시판 정보조회<br />게시글 쓰기 폼<br />게시글 쓰기 요청 처리<br />게시글 ID/정렬값생성<br />데이터 검증<br />게시글 데이터 삽입<br />
  6. 6. 객체 간 의존(dependency) 발생<br />게시판 정보조회<br />데이터 검증<br />게시글 쓰기 폼<br />게시글 쓰기 요청 처리<br />게시글 ID/정렬값생성<br />게시글 데이터 삽입<br />* 의존의 가장 단순한 정의: 다른 객체의 메서드를 호출하면 의존<br />
  7. 7. 의존 객체를 구하는 방식<br />직접 의존 객체 구함<br />중앙 저장소에서 객체 구함<br />DI 사용<br />
  8. 8. 의존 상황<br />
  9. 9. 의존 처리 1: 직접 의존 객체 구함<br />코드에서 직접 의존 클래스의 객체 생성<br />public class WriteArticleService {<br /> public WriteResult write(Article article) {<br /> BoardService boardService = new DefaultBoardService();<br /> Board board = boardService.getBoard(article.getBoardId());<br /> if (board == null) {<br /> throw new BoardNotFoundException(article.getBoardId());<br /> }<br /> IdGenerator idGenerator = new MemoryIdGenerator();<br /> Integer nextId = idGenerator.nextId();<br /> article.setId(nextId);<br /> ArticleDao articleDao = new MySQLArticleDao();<br /> articleDao.insert(article);<br /> return WriteResult(aritcle);<br /> }<br />}<br />의존 클래스를 바꾸면<br />코드 수정 필요<br />의존 클래스가 구현되기<br />전이면, 실행 불가<br />
  10. 10. 의존 처리 2: 중앙에서 가져옴<br />객체 Locator (또는 디렉터리 서버)로부터 의존 객체 구함<br />public class WriteArticleService {<br /> public WriteResult write(Article article) {<br /> BoardService boardService = Locator.getBoardService();<br /> Board board = boardService.getBoard(article.getBoardId());<br /> if (board == null) {<br /> throw new BoardNotFoundException(article.getBoardId());<br /> }<br /> IdGenerator idGenerator = Locator.getIdGenerator();<br /> Integer nextId = idGenerator.nextId();<br /> article.setId(nextId);<br /> ArticleDao articleDao = Locator.getArticleDao();<br /> articleDao.insert(article);<br /> return WriteResult(aritcle);<br /> }<br />}<br />로직과 상관없는<br />클래스에 대한 의존 발생<br />
  11. 11. 의존 처리 3: Dependency Injection<br />의존 객체를 외부로부터 전달받음<br />public class WriteArticleService {<br /> private BoardService boardService;<br /> private IdGenerator idGenerator;<br /> private ArticleDao articleDao;<br /> public void setBoardService(BoardService boardService) {<br /> this.boardService = boardService;<br /> }<br /> …<br /> public WriteResult write(Article article) {<br /> Board board = boardService.getBoard(article.getBoardId());<br /> if (board == null) {<br /> throw new BoardNotFoundException(article.getBoardId());<br /> }<br /> Integer nextId = idGenerator.nextId();<br /> article.setId(nextId);<br /> articleDao.insert(article);<br /> return WriteResult(aritcle);<br /> }<br />}<br />
  12. 12. 조립기<br />DI는 조립기를 통해 구현<br />public class Assembler {<br /> public void init() {<br /> DefaultBoardServiceboardService = new DefaultBoardService();<br /> MemoryIdGenerator idGenerator = new MemoryIdGenerator();<br /> MySQLArticleDao articleDao = new MySQLArticleDao();<br /> WriteArticleService articleService = new WriteArticleService();<br /> articleService.setBoardService(boardService);<br /> articleService.setIdGenerator(idGenerator);<br /> articleService.setArticleDao(articleDao);<br /> …<br /> }<br /> public WriteArticleService getWriteArticleService() {<br /> return articleService;<br /> }<br />}<br />Assembler assembler = new Assembler();<br />assembler.init();<br />WriteArticleService service = assember.getWriteArticleService();<br />service.write(…);<br />
  13. 13. DI 기법 두 가지<br />생성자를 통한 의존 객체 전달받음<br />Setter 메서드를 통해 의존 객체 전달받음<br />기타: Method Injection<br />public class WriteArticleService {<br /> private ArticleDao articleDao;<br /> public WriteArticleService(ArticleDao articleDao) {<br /> this.articleDao = articleDao;<br /> }<br />}<br />public class WriteArticleService {<br /> private ArticleDao articleDao;<br /> public setArticleDao(ArticleDao articleDao) {<br /> this.articleDao = articleDao;<br /> }<br />}<br />
  14. 14. 조립기의 구현<br />조립기는 객체를 담는 컨테이너 형태로 구현 됨<br />주요 컨테이너: Spring, Google Guice, …<br />컨테이너<br />어플리케이션<br />
  15. 15. Spring DI 설정 예<br />XML 이용 객체간 의존 설정<br /><bean id="agent" class="com.wemade.am.agent.Agent"<br /> p:functionConfigLoader-ref="functionConfigLoader"<br /> p:functionConfigRepository-ref="functionTestLineRepository"<br /> p:scheduler-ref="scheduler" /><br /><bean id="functionConfigLoader"<br /> class="com.wemade.am.agent.loader.HttpClientFunctionConfigLoader"<br /> p:configLoadingUrl="${console.configLoadingUrl}"<br /> p:testConfigUnmarshaller-ref="testConfigUnmarshaller" /><br /><bean id="testConfigUnmarshaller" <br /> class="com.wemade.am.agent.loader.StaxTestConfigUnmarshaller" /><br /><bean id="functionTestLineRepository" <br /> class="com.wemade.am.agent.repo.FunctionTestLineRepositoryImpl" /><br /><bean id="scheduler" class="com.wemade.am.agent.scheduler.TimerScheduler"<br /> p:period="60000" p:testProcessor-ref="testProcessor" /><br />
  16. 16. DI 장점<br />의존 객체의 변경이 용이<br />단위 테스트가 쉬워짐<br />기타 장점<br />코드 가독성 향상<br />재사용성 향상<br />
  17. 17. 장점1 : 의존 객체 변경 용이<br />설정 파일 변경 만으로 의존 객체 변경<br /><bean id="agent" class="com.wemade.am.agent.Agent"<br /> p:functionConfigLoader-ref="functionConfigLoader"<br /> p:functionConfigRepository-ref="functionTestLineRepository"<br /> p:scheduler-ref="scheduler" /><br /><bean id="functionConfigLoader"<br /> class="com.wemade.am.agent.loader.HttpClientFunctionConfigLoader” /><br /><bean id="agent" class="com.wemade.am.agent.Agent"<br /> p:functionConfigLoader-ref="functionConfigLoader"<br /> p:functionConfigRepository-ref="functionTestLineRepository"<br /> p:scheduler-ref="scheduler" /><br /><bean id="functionConfigLoader"<br /> class="com.wemade.am.agent.loader.SoapFunctionConfigLoader” /><br />
  18. 18. 장점2 : 단위 테스트 용이<br />Mock 객체를 이용한 단위 테스트 가능<br />실제 구현 없이 (또는 사용하지 않고) 테스트 가능<br />의존 클래스를 코드에서 직접 사용할 경우,<br />전체가 완성되기 전까지 테스트 과정이 수월하지 않음<br />WriteArticleService service = new WriteArticleService();<br />ArticleDao articleDao = mock(ArticleDao.class);<br />…<br />service.setArticleDao(articleDao);<br />WriteResult result = service.write(…);<br />assertNotNull(result.getArticle());<br />Mockito, easyMock 등 이용해서<br />실 구현없이 가짜 객체 생성<br />class WriteArticleService {<br /> public WriteResult write(Article article) {<br /> ArticleDao articleDao = new MySQLArticleDao();<br /> articleDao.insert(article);<br /> …<br /> } <br />}<br />의존 클래스 구현 없이<br />테스트 어려움<br />
  19. 19. DI의 장점을 살리려면,,,<br />인터페이스에 의존할 것!<br />자바 인터페이스 or 추상 클래스의 추상 메서드<br />최대한 역할별로 클래스를 분리할 것<br />좋은 기준: 클래스 LoC(Line of Code) < 100~200<br />
  20. 20. 질문?<br />

×