kenzi

오늘 수업에서 질문한 것(DI와 인터페이스 구현) 본문

Spring

오늘 수업에서 질문한 것(DI와 인터페이스 구현)

kenzi 2022. 4. 4. 18:10

1. 

상황 설명 

1) OracleArticleDao는 ArticleDao 인터페이스를 구현하고 있다 

interface ArticleDao   <----------implements-------------- class OracleArticleDao

              조상                                                              자손

2) interface ArticleDao(조상)에는 추상메서드 insert()(=선언부만 있는 메서드) 가 있고 

class OracleArticleDao(자손)는 조상의 메서드를 모두 구현해야하므로 override된 insert() 메서드가 있다 

다만 추상메서드의 구현부(몸통)을 작성해야하므로 insert()메서드의 구체적인 내용이 있다 

package ch05_obj;

public interface ArticleDao {

	void insert();

} //end interface
package ch05_obj;

public class OracleArticleDao implements ArticleDao{

	@Override
	public void insert() {
		System.out.println("OracleArticleDao.insert() 메서드 호출");
	}
 
} //end class

 

 

질문은 여기서 시작된다 

1. write() 실행=> articleDao.insert() 실행=> OracleArticleDao의 insert()로 연결이 되는가?

우리는

private ArticleDao articleDao;

타입 ArticleDao 변수명 articleDao인 참조형 변수를 선언했으므로

articleDao.insert()를 실행=> interface ArticleDao의 추상메서드 insert()가 실행

이렇게 되어야 하는 것 아닌가? 

 

package ch05_obj;

public class WriteImpl {

	private ArticleDao articleDao; 

	public WriteImpl(ArticleDao articleDao) {
		
		this.articleDao = articleDao;
	}
	
	public void write() {
		System.out.println("WriteImpl.write() 메서드 호출됨");
		articleDao.insert();
		
	}
} //end class

 

답변 

포인트는 container에 있다 

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns = "http://www.springframework.org/schema/beans"
	xmlns:context = "http://www.springframework.org/schema/context"
	xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance"
	xmlns:aop = "http://www.springframework.org/schema/aop"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
	http://www.springframework.org/schema/beans/spring-beans.xsd
	http://www.springframework.org/schema/aop
	http://www.springframework.org/schema/aop/spring-aop.xsd
	http://www.springframework.org/schema/context
	http://www.springframework.org/schema/context/spring-context.xsd">

//1
<bean id = "write" class = "ch05_obj.WriteImpl">
	<constructor-arg  ref = "articleDao" />
</bean>

//2
<bean id = "articleDao" class = "ch05_obj.OracleArticleDao"/>
</beans>

1) id가 write 인 빈 객체의 주소는 WriteImpl이다 & id가 articleDao인 빈 객체가 생성자 방식으로 주입되고 있다(의존성 주입)

2) id가 articleDao인 빈 객체의 주소는 OracleArticleDao이다 

 

따라서 private ArticleDao articleDao 참조변수의 주소는 OracleArticleDao이다 

다시 말해

OracleArticleDao 인스턴스를 조상타입 ArticleDao으로 형변환이 된 것이다 

 

만약 xml에서 의존성 주입을 저렇게 해주지 않았다면

우리는 ArticleDao(조상타입) articleDao = new OracleArticleDao()로 참조형 변수를 만들고 객체를 넣어줬을것이다 

그리고 articleDao.insert()를 하면 똑같이 OracleArticleDao(자손)의 insert()가 실행되는 것이다 

 

즉 xml에서 의존성 주입을 해준 저 한 줄로 참조형 변수의 주소가 OracleArticleDao임을 알 수 있다 

 

그렇다면 왜 이렇게 할까? 

앞서 말했듯이 

xml에서 의존성 주입을 해주지 않고 참조형 변수를 직접 만들어서 객체 넣어서 사용하는 방법이 있는데!

 

DI의 의의를 묻는 질문이다 

만약 OracleArticleDao말고 MyBatisArticleDao를 넣어야 하는 상황이라면 클래스를 찾아다니면서 new OracleArticleDao()를 new MyBatisArticleDao로 바꾸고 ~~ 해야하는 번거로운 상황이 온다 

 

그러지 말고 xml컨테이너에서 빈을 추가해주고 MyBatisArticleDao클래스도 interface ArticleDao를 구현하면 된다 

(인터페이스의 자손이 되면 된다)

그러면 WriteImpl을 수정할 필요없이 MyBatisArticleDao에 있을(오버라이딩해야하므로) insert()메서드가 실행될 것이다 

 

<bean id = "articleDao" class = "ch05_obj.MyBatisArticleDao"/>

 

 

정리 

package ch05_obj;

public class WriteImpl {

	private ArticleDao articleDao; 
	// 2
	public WriteImpl(ArticleDao articleDao) {
		// 4
		this.articleDao = articleDao;
	}
	
	public void write() {
		System.out.println("WriteImpl.write() 메서드 호출됨");
		articleDao.insert();// 3
		//1
	}
} //end class

1) xml에서 <bean id = "articleDao" class = "ch05_obj.OracleArticleDao"/> 이렇게 만들어서 여기에 생성자로 injection 했기 때문에 

2) 여기에서 이 ArticleDao는 타입은 ArticleDao(조상)이지만 실 주소는  class = "ch05_obj.OracleArticleDao" 에 의해 OracleArticleDao를 가리킨다 

3) 그래서 실 주소의 OracleArticleDao의 insert()가 실행된다 

4) 만약 xml이 없었으면 ArticleDao articleDao = new OracleArticleDao()로 객체 생성해서 했을것 

 

 

참고로 인터페이스는 추상메서드의 집합이다 

추상클래스와 동일하게 미완성 설계도의 역할을 한다  

미완성 설계도가 필요한 이유는 

공통적인 형태와 기능을 참고하기 위해서다 

인터페이스에는 추상클래스와 동일하게 추상메서드의 구체적인 몸통(구현부)는 없고 선언부만 있어야한다 

구현하는 자손 클래스는 인터페이스에 있는 추상메서드의 선언부를 작성하여 구현해야 한다 

 

추상클래스 역시 상속받는 자손 클래스는 추상클래스에 있는 모든 메서드를 오버라이딩(중복하여 서술)하여 구현부를 작성해야한다 모든 메서드를 구현하지 않으면 구현하는 자손클래스에 abstract을 붙여줘야 한다

자손 클래스에서 오버라이딩된 메서드의 구현부는 각기 다를 수 있다 

 

예를 들어 전국의 모든 신세계 백화점 건물 내부의 전체적인 구조와 모양, 층별로 어떤 물품이 있는지(1층은 명품관, 지하는 푸드코트 등 )는 대체로 공통적이지만 지역에 따라서 층별에 입점되어있는 브랜드는 각기 다를수 있다 

 

 

 

 

 

 


남궁성님의 자바 6,7 장 강의 주말에 듣기 잘한거 같다 

물론 7장 아직 듣고 있지만 

자바와 스프링 둘다 이해가고 있는 중 .. 

 

 

'Spring' 카테고리의 다른 글

오늘의 질문 정리(advice는 어려워..&ComponentScan과 Component)  (0) 2022.04.05
AOP  (0) 2022.04.05
pom.xml이 무엇인지 정리해보자 ..  (0) 2022.04.04
AOP  (0) 2022.04.04
스프링 5일차 (Autowired, interface, scope)  (0) 2022.04.01
Comments