- Dependency(의존) Injection(주입)
--> DI
* 의존? (Dependency)
: A객체랑 B객체가 있는데 A객체가 B객체의 어떤 메소드를 호출하고 값을 리턴한다치면
( A ----> B )
===> A에서 B에 있는걸 불러 ===> A는 B가 필요해... B한테 의존할거야... 너 없으면 안돼...
===> A는 B에 의존한다.
* 주입? (Injection)
: 의존이랑 비슷한데 의존이랑 반대야
===> A에서 B에 있는걸 불러 ===> B가 A에 들어가... B를 A에 주입할거야...
===> B를 A에 주입한다.
===> A는 주입 받는다.
★ A는 B에 의존 = B를 A에 주입
★ 불려지는게 B 의존 객체 (의존할 객체) -----> 지존
★ 불러서 쓰는게 A 의존하는 객체
* 객체 외부에 존재하는 assembler(container) (= spring)가 런타임시에 객체들 사이의 의존 관계를 파악하고 의존 객체를 객체에 주입
* 컨테이너가 해줌
* 근데 객체 정의, 의존 관계 설정은 개발자가
* 객체들 간의 의존 관계는 XML 파일이나 annotation을 통해 설정 됨
* 객체들 간의 결합도(coupling)를 낮춤 ---> 테스트 및 수정 용이, 재사용성 증가
* 응집도(cohesion) ↑ 결합도(coupling) ↓ ---> 응고
★ 인터페이스 https://mdown.blog.me/221316632143
- 인터페이스는 객체가 될 수 없어! 클래스가 아니니까! 객체가 가져야하는 특징, 특성 같은거야! 인터페이스를 지키는 객체!
: ArticleDao는 인터페이스지 객체가 아니야
: ArticleDao를 상속 받아서 구현한게 객체
: MysqlArticleDao / OracleArticleDao
: 상속 받았으니까 ArticleDao에 있는 메소드 insert() / selectById()가 결국 MysqlArticleDao / OracleArticleDao 클래스에 있는거야
< 의존 객체 생성 방법 >
① 의존하는 객체를 직접 생성
public class WriteArticleService {
private ArticleDao articleDao = new MysqlArticleDao();
...
}
* private 인터페이스타입 변수 = new 인터페이스구현객체();
단점)
- 결합(coupling)이 너무 타이트 (결합도는 낮아야함)
- 의존 클래스(의존 객체=불려지는거=MysqlArticleDao)를 다른 클래스로 변경하려면? 힘든 수정이 필요
- MysqlArticleDao() ---> OracleArticleDao()
- 여러 클래스들도 의존하고 있으면 다 하나하나 수정해야 함
- 클래스마다 개발자가 다르면? 진도가 다르면?
- 단위 테스트를 위해서 코드 수정이 필요해짐
② Factory 클래스 이용 (==> 간접적 생성)
public class WriteArticleService {private ArticleDaoFactory factory = ArticleDaoFactory.newInstance();private ArticleDao articleDao = factory.newArticleDao();...}* Factory클래스를 따로 만들고 거기에 있는 DAO(newInstance)를 호출해서 사용 * ArticleDaoFactory 클래스 안에 newInstance() 메소드, 그 안에 newArticleDao() 메소드장점) - 수정 필요 시 Factory 클래스만 수정하면 됨 단점) - 객체마다 Factory 클래스를 구현해야 함 - Factory 객체에 대한 타이트한 의존 관계 형성③ Dependency Injection 이용 (Assembler(Spring)가 의존 객체 생성 후 의존하는 객체에게 전달)★ 생성자 : 내가 만약 객체를 생성할 때 마다 그 객체에 어떠한 기능을 주고 싶거나, 변수를 초기화하고 싶다면 생성자 이용 ★ this : 멤버변수, 나를 부른 놈, 자신을 호출한 객체, 생성자를 부른 객체의 변수 ★ super : 부모 클래스의 생성자를 쓰겠다, 그냥 상속받은 클래스에서 초기화하면 되지 왜? 왜냐면 내 변수는 내가 책임질게 네 변수는 네가 책임져! 이런 의미란다 코드가 꼬일 수 있기에 ★ 오버라이딩 : 부모 클래스의 메소드를 자식 클래스에서 재정의 하는 것, 클래스이름 및 매개변수 다 같아야 함 ★ 오버로딩 : 생성자가 대표적 오버로딩인데 같은 클래스에서 같은 이름의 메소드들 정의, 클래스이름은 같아야하고 매개변수는 달라도 됨 ★ 다형성 : 왼쪽 변이 같거나 더 커야 함. Employee(상위클래스) m = new Manager(하위클래스)(); 이면 왼쪽변이 크니까 가능한데 대신 Employee 클래스에 있는 변수만 사용 가능. Manager() 객체라고 해서 Manager()에 있는 변수를 사용할 수 있는게 아니야.public class WriteArticleService { //의존하는 객체private ArticleDao articleDao; //필드(참조변수) 선언public WriteArticleService(ArticleDao articleDao) {//생성자를 통해 의존 객체(MysqlArticleDao 등)를 전달받도록 구현this.articleDao = articleDao; //의존 객체 주입(DI)}public void writeArticle(Article article) {articleDao.insert(article); //의존 객체 호출//이 articleDao는 바뀐 값. 주입된 값. 주입된 객체의 insert메소드 호출// 즉 MysqlArticleDao의 내용들이 담긴 것이 여기로 와서 주입된거야(이건 밑 코드가 먼저 실행)// insert해라~ 처리는 이 클래스에서 하는 것}...}
* 위 코드는 생성자 사용 방법임. 생성자를 정의 해야함
--> 생성자로 의존 객체를 주입하는 것
* 다른 방법으로는 setter 메소드를 정의 하는 방법이 있음
--> setter 메소드로 의존 객체 주입하는 것
장점)
- 의존 객체를 직접 생성하거나 찾기 위한 코드가 불필요
- new 안씀
- 의존 객체 주입
- 독립적 구현
- 그래서 loose coupling임
단점)
- 의존 객체가 위 코드에는 안나와있어서 구체적으로 Mysql..인지 Oracle..인지는 알 수 없음
public class MysqlArticleDao implements ArticleDao { //인터페이스인 ArticleDao를 구체적으로 구현한 클래스private Map<Integer, Article> mysqlDB = new HashMap<>();//Map 타입의 mysqlDB는 HashMap 객체이다. 메모리에 저장한다.@Overridepublic void insert(Article article) {System.out.println("MysqlArticleDao.insert() 실행");mysqlDB.put(article.getId(), article);//Map 타입에 따라서 Article 객체를 Map에 저장//--> Article 타입의 article이 저장되는거니까Article 객체가 저장되는거지.System.out.println(" --> Article " + article.getId() + " was inserted into Mysql.");}// 결과// MysqlArticleDao.insert() 실행// --> Article 23 was inserted into Mysql.@Overridepublic Article selectById(int id) {System.out.println("MysqlArticleDao.selectById() 실행");System.out.println(" --> Article " + id + " was selected from Mysql.");return mysqlDB.get(id); //Map에서 Article 객체를 검색}}public class Assembler { // 스프링에선 구현 필요는 없다.private ArticleDao articleDao;private WriteArticleService writeService;private ReadArticleService readService;public Assembler() {articleDao = new MysqlArticleDao();// ArticleDao를 구현한 객체 생성// 즉 articleDao에는 MysqlArticleDao의 내용들이 담긴거야writeService = new WriteArticleService(articleDao);// WriteArticleService 객체 생성// ArticleDao를 구현한 객체를 전달(생성자 만들었으니까 거기로)// 즉 이 writeService에는 MysqlArticleDao 내용이랑 WrtieArticleService의 insert 해라~ 까지 담겨있는거야readService = new ReadArticleService(articleDao);}public WriteArticleService getWriteArticleService() { return writeService; --> WriteArticleService 객체임 }public ReadArticleService getReadArticleService() { return readService; }}public class MainForAssembler { // 메인 테스트 프로그램public static void main(String[] args) {Assembler assembler = new Assembler();// Assembler 객체 생성WriteArticleService writeService = assembler.getWriteArticleService();// Assembler로부터 WriteArticleService 타입의 객체를 가져옴// 그러면 즉 이 writeService에는 MysqlArticleDao 내용이랑 WrtieArticleService의 insert 해라~ 까지 담겨있는거야// 근데 아직 insert안함 insert가 있는 메소드는 WriteArticleService의 writeArticle(Article article) 메소드 이니까// 이 .writeArticle() 가 호출 되어야 그 안에 있는 insert가 실행되는 것!Article article = new Article(101, "This is a new article ...");// Article 객체 생성System.out.println(article + " was created.");writeService.writeArticle(article);// WrtieArticleService 클래스를 호출하게 되는거니까 이제 여기서 insert() 실행 됨System.out.println();ReadArticleService readService = assembler.getReadArticleService();Article result = readService.readArticle(101);// 얘는 객체 안만들고 값만 가져오는거니까...System.out.println(result + " was read.");}}
'SPRING' 카테고리의 다른 글
DI / 의존 관계 설정 방법 2 (Annotation 이용 방법) (0) | 2019.03.18 |
---|---|
DI / 의존 관계 설정 방법 1 (XML 이용 방법) (0) | 2019.03.18 |
Spring Web MVC framework (0) | 2019.03.16 |
spring Components (0) | 2019.03.15 |
what is Spring framework? (0) | 2019.03.15 |