-src/main/java 폴더에
-1. 실행할 MainClass
-2. Battery 인터페이스 / Battery 인터페이스를 구현할 클래스 ChargeBattery, NormalBattery 2개 생성
-3. ElectronicCar, ElectronucRadio 클래스 생성
- Battery 인터페이스
package com.ezen.battery;
public interface Battery {
public int getBatteryValue();
}
- NormalBattery.java
package com.ezen.battery;
public class NormalBattery implements Battery{
@Override
public int getBatteryValue() {
return 0;
}
}
-> Battery 인터페이스의 getBatteryValue 메소드 오버라이딩
-ChargeBattery.java
package com.ezen.battery;
public class ChargeBattery implements Battery {
@Override
public int getBatteryValue() {
return 0;
}
public void charge(int value) {
}
}
-> Battery 인터페이스의 getBatteryValue 메소드 오버라이딩
-ElectronicCar.java
package com.ezen.toy;
import com.ezen.battery.Battery;
import com.ezen.battery.NormalBattery;
public class ElectronicCar {
private Battery bat; //인터페이스 레퍼런스 변수, - NormalBattery 또는 ChargeBattery 인스턴스가 저장될 변수
public ElectronicCar() {
//생성자에서 노멀배터리를 멤버변수의 초기값으로 대입하고 시작합니다.
bat = new NormalBattery();
//인터페이스멤버 변수에 battery를 임플리먼트한 클래스를 대입합니다.
}
}
//이 장난감은 배터리가 출시당시 탑재(내장)되어서 교체가 불가능한 상태로 판매되는 형태입니다.
-> 멤버변수 Battery 생성
-> ElectronicCar 객체 생성시 Battery 멤버변수에 NormalBattery 인스턴스를 대입한다.
-ElectronicRadio.java
package com.ezen.toy;
import com.ezen.battery.Battery;
public class ElectronicRadio {
private Battery bat;
//생성자에서 배터리가 초기화되는데, 그 초기값이 생성자의 전달인수로 전달되어야 하는 형태입니다,
public ElectronicRadio(Battery bat) {
this.bat = bat;
}
public void setBattery(Battery battery) {
this.bat = battery;
}//추후 배터리를 새로 교체할 수 있는 기능이 있습니다.
}
//구매와 동시에 동봉 또는 별도 구입한 새 배터리를 장착할 수 있는 기능이 있습니다.
-> 위 ElectronicCar 클래와 달리 ElectronicRadio 클래스는 생성시에 Battery 객체를 필요로한다.
-> 위 ElectronicCar 클래스와 달리 setBattery(Battery battery) 메소드를 통해 Battery 멤버 변수에 새로운 값을 대입할 수 있다.
-> 즉, 구입(객체 생성)시 배터리가 장착 / 추후에 교체할 수 있다.
-가장 중요한 MainClass.java
package com.ezen;
import org.springframework.context.support.GenericXmlApplicationContext;
import com.ezen.battery.ChargeBattery;
import com.ezen.battery.NormalBattery;
import com.ezen.toy.ElectronicCar;
import com.ezen.toy.ElectronicRadio;
public class MainClass {
public static void main(String[] args) {
//일반적인 사용예
//배터리가 장착된 상태로 판매되는 일체형. 객체생성 하나만으로 사용이 가능합니다.
ElectronicCar carToy1 = new ElectronicCar();
//ElectronicRadio radioToy = new ElectronicRadio(); //에러
//생성자에 배터리 객체가 전달되어야, 매개변수가 있는 생성자가 실행되므로 위는 에러입니다.
NormalBattery nbatt1 = new NormalBattery();
ChargeBattery cbatt1 = new ChargeBattery();
ElectronicRadio radioToy1 = new ElectronicRadio(nbatt1);
//생성자에 배터리 객체를 전달해주면 정상 생성, 이렇게 객체 생성시에 다른 객체의 존재 및 생성자로의 전달이 필수인 상태!
//객체생성이 다른 객체에 의존하고 있는 상태! 이를 객체 의존이라고 부릅니다.
//그리고 필요 객체를 생성자의 전달인수로 넣어주는 것을 의존주입(Dependency Injection)이라고 부릅니다.
GenericXmlApplicationContext ctx
= new GenericXmlApplicationContext("classpath:applicationContext.xml");
ElectronicCar carToy2 = ctx.getBean("car", ElectronicCar.class);
ElectronicRadio radioToy2 = ctx.getBean("radio",ElectronicRadio.class);
radioToy2.setBattery(nbatt1);
//스프링 프레임워크에서의 클래스 사용이 약간 업그레이드되어 조금 간편해졌습니다.
}
}
-> 첫째줄부터 코드를 하나하나 뜯어보면,
1) ElectronicCar carToy1 = new ElectronicCar(); --> ok
ElectronicCar 클래스는 생성자에 매개변수를 필요로 하지 않으니 이대로 객체 생성이 가능하지만,
ElectronicRadio radioToy = new ElectronicRadio(); --> x
ElectronicRadio 클래스는 생성자에 매개변수(Battery 인터페이스를 구현하는 클래스)를 필요로 하므로, 에러이다.
NormalBattery nbatt1 = new NormalBattery();
ChargeBattery cbatt1 = new ChargeBattery();
ElectronicRadio radioToy1 = new ElectronicRadio(nbatt1);
-->위와 같이 Battery 인터페이스를 구현하는 클래스의 객체 생성을 하고, ElectronicRadio의 생성자 매개변수에 넣어주면 ok이다.
nbatt1을 보내줘도 되고, cbatt1을 보내줘도 Ok이다.
Dependency Injection(DI) 의존주입
-위와 같이 필요 객체를 생성자의 전달인수로 넣어주는 것을 의존 주입이라고 한다.
-만약 중간에 Battery 인터페이스를 두지 않고 직접 ElectronicRadio 생성자의 매개변수로 NormalBattery 객체를 전달하게 되면 어떻게 될까? (NormalBattery와 ChargeBattery 클래스는 Battery 인터페이스를 구현하지 않는 독립적인 클래스라고 가정)
package com.ezen.toy;
public class ElectronicRadio {
private NomalBattery nbatt1;
public ElectronicRadio(NormalBattery nbatt1) {
this.nbatt1 = nbatt1;
}
public void setBattery(ChargeBattery nbatt2) {
this.nbatt1 = nbatt2;
}//추후 배터리를 새로 교체할 수 있는 기능이 있습니다.
}
---> 위와 같이 (NormalBattery, ChargeBattery) 클래스와 ElectronicRadio 클래스 객체간의 의존도가 훨씬 높아진다.
---> 만약 나중에 장착될 혹은 교체될 배터리가 달라진다면 코드 수정이 불가피하다.
---> 따라서 객체간의 결합도를 약하게 하기 위해 중간에 Battery 인터페이스를 둔다.
GenericXmlApplicationContext
- XML 파일로부터 정보를 읽어와 객체를 생성하고 초기화
- 스프링은 각각의 객체를 연결하고 조립하는 역할을 한다.
- 스프링 컨테이너가 생성해서 보관하는 객체를 빈(Bean)객체라고 하며 자바의 객체와 동일하다.
-getBean() 메서드를 이용하여 빈(Bean) 객체를 return 받는다.
-Bean 객체를 미리 생성해놓고 필요시 꺼내쓴다는것은, 싱글톤 방식과 같다.
-만약 다른 인스턴스를 생성하고 싶다면, id만 달리해서 Bean객체를 생성하면 된다.
-ApplicationContext는 빈 객체의 생성, 초기화, 보관, 제거 등을 관리하는데 이런 이유로 '컨테이너'라고 부른다.
->src/main/resources 폴더 아래 xml 파일에 Bean 객체를 관리한다.
->자바 객체 생성 처럼 NormalBattery bt = new NormalBattery(); -> new 를 사용하여 객체를 생성하지 않고
getBean() 메서드를 사용한다.
-applicationContext.xml 파일
<beans xmlns = "http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean class="com.ezen.battery.NormalBattery" id="nBattery"></bean>
<bean class="com.ezen.battery.ChargeBattery" id="cBattery"></bean>
<bean id="car" class="com.ezen.toy.ElectronicCar"></bean>
<bean id="radio" class="com.ezen.toy.ElectronicRadio">
<constructor-arg ref="cBattery"></constructor-arg><!-- 의존 주입 - 객체 조립 -->
</bean>
<!-- 클래스의 생성자가 다른 클래스를 매개변수로 갖고, 해당 객체가 전달되어야 생성자 실행이 가능하면,
이는 클래스가 다른 클래스에 의존하고 있다. 라고 얘기합니다. 그리고 의존에 해당하는 객체를 위와 같이 Constructor-arg를
이용해서 채워주는 것을 의존 주입이라고 말합니다. 통틀어 객체 조립이라고 표현합니다. -->
</beans>
-> getBean 메소드를 이용하여 객체 생성
GenericXmlApplicationContext ctx
= new GenericXmlApplicationContext("classpath:applicationContext.xml");
ElectronicCar carToy2 = ctx.getBean("car", ElectronicCar.class);
ElectronicRadio radioToy2 = ctx.getBean("radio",ElectronicRadio.class);
'Spring' 카테고리의 다른 글
빌드 자동화 도구 Maven vs. Gradle (0) | 2022.09.14 |
---|---|
Spring MVC 와 Spring Boot (0) | 2022.09.14 |
DI 의존객체 주입 -> @Autowired (0) | 2022.09.14 |
DI 의존주입 & Bean 생성과 사용 (0) | 2022.09.14 |