본문 바로가기
Spring

2022-11-25 IoC(제어의 역전), DI(의존관계 주입) - 생성자를 이용해 객체 생성하기 리뷰

by HTT 2022. 11. 25.
생성자를 이용해 객체 생성하기

 

package di.constructor02;

public class Test01 {
	public static void main(String[] args) {
		ApplicationContext factory = new GenericXmlApplicationContext("/config/constructor.xml");
		AbstractPlayer p = factory.getBean("player", AbstractPlayer.class);
		p.play();
		System.out.println("세번 굴린 주사위의 합:"+p.getTotalValue());
	}

}
package di.constructor02;

public class Player implements AbstractPlayer{
	AbstractDice d;  //상위 인터페이스로 정의하기
	int totalValue=0;
	
	public Player() {
		
	}
	public Player(AbstractDice d) {
		super();
		this.d = d;
	}
	public void play(){
		totalValue=0;
		for (int i = 0; i < 3; i++) {
			totalValue+=d.getDiceValue();
		}
	}
	public int getTotalValue(){
		return totalValue;
	}
}

 

1. 메인 메소드에서 IoC컨테이너 생성하기

IoC컨테이너 = new("xml파일경로")

 

 

2. Player클래스에서 생성자 이용해서 AbstractDice객체 생성할 수 있도록 준비하기(DI방식)

=> 멤버변수와 기본생성자, 매개변수가 있는 생성자가 필요하면 매개변수를 포함한 생성자로 만들어준다.

스프링은 아무것도 지정하지 않으면 객체를 생성하면서 기본생성자를 호출하기 때문에 기본생성자는 쓰지 않아도 무조건!! 만들어둬야 한다. AbstractDice타입을 매개변수로 가지는 생성자를 만들고 xml파일에서 빈을 만들어준다.

constructor.xml
<!-- dice객체를 생성 -->
<bean id="dice" class="di.constructor02.Dice"/>
<bean id="player" class="di.constructor02.Player">
	<constructor-arg ref="dice"/>
</bean>

=> player빈에 dice빈을 주입시킴(Constructor Injection). 이미 만들어진 빈들 중에서 dice를 참조하겠다는 뜻

작성하는 순서가 바뀌어도 됨. 왜냐하면 모든 빈을 만든 후에 어떤 빈을 참조할지 정하기 때문.

 

<constructor-arg> 태그를 사용해 상위 인터페이스를 구현한 하위 객체의 주소를 지정해주기

<bean id="사용할 아이디명" class="폴더명.하위객체 클래스명">

 

 

3. 객체를 불러올 준비를 마쳤으니 이제 new객체가 필요한 클래스에서 객체를 만들어보자!

 

3-1. 우선 Player클래스에서 생성자를 통해 객체를 생성했다. 선언부에서 생성자를 통해 생성한 AbstractDice타입 객체주소를 매개변수d에 담고 있고, 생성자 구현부에서 AbstractDice타입 매개변수d를 멤버변수 d에 대입하고 있으니 두 변수는 같은 주소를 공유하게 된다.

* 객체생성은 oop의 특징 다형성을 이용해서 조상타입의 참조변수로 자식타입 객체를 참조하는 형태로 생성해줘야 하는데 그 이유는 객체를 자유롭게 바꾸기 위해서이다.

 

3-2. 메인 메소드에서 만들어뒀던 IoC컨테이너의 gegBean메소드를 이용해 필요한 객체를 불러온다.

IoC컨테이너 변수명.getBean("자신이 불러올 객체의 baen-id명");

 

 

객체를 불러오는 방법

 

① 캐스팅

IWriteArticleMgr writemgr = (IWriteArticleMgr)factory.getBean("write");

② class타입 명시

AbstractPlayer p = factory.getBean("player", AbstractPlayer.class);

③ class타입만 명시

AbstractPlayer p = factory.getBean(AbstractPlayer.class);

=> AbstractPlayer타입의 빈이 모두 찾아지므로 두 개 이상인 경우 오류가 발생한다. 지금은 하나 밖에 없으므로 괜찮음

 

 

 

끝!

 

 

 

..인데 처음 코드바꿀 때 실수한 것!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

객체생성코드 짤 때 다형성을 이용해야 한다는 것을 까먹고 자식타입으로 객체를 생성했다.

 

public class Player implements AbstractPlayer{ };

 

 AbstractPlayer p = new Player();

 Player p = new Player();

 

1번 방법으로 해야 하는데 2번 방법으로 했던 것이다.... 결과가 똑같이 나와서 나는 맞게 한 줄 알았지~~!~!

하지만 한 번 틀렸기 때문에 다른 예제 풀 때는 실수하지 않았다. Good!

 

*그리고!!!! 메인메소드에서 객체를 불러올 때 기본생성자를 쓸지 매개변수가 있는 생성자를 쓸지 잘 확인해야 함. 분명 다 작성해놓고 왜... 매개변수가 이상하지? 하면 생성자와 동일하게 작성하지 않은 것이다 ㄱ-;;

<comstructor-arg>는  <bean>태그 내부에 있어야 하고, bean의 <constructor-arg>갯수가 생성자의 매개변수 갯수와 동일해야 한다!

댓글