주니어 기초 코딩공부/Spring 기초

[Spring] 제어의 역행 예제

jju_developer 2023. 2. 2. 21:08
728x90

안녕하세요 jju_developer입니다.

지난 시간에 이어 Spring에 대해서 좀 더 자세히 알아보겠습니다.

 

▼▼▼ 스프링 기초 ▼▼▼

 

 

[Spring] 스프링 시작하기- 기초 설명 및 스프링 프로젝트 파일 만들기

안녕하세요 jju_developer입니다. 오늘부터 2주간 스프링에 대해서 배운 부분을 공유드리려고 합니다. 첫 번째 주는 Spring Legacy 두 번째 주는 Spring 부트에 대해서 배울 예정입니다. 1. 스프링(Spring)이

jju240.tistory.com

지난시간에 스프링 프레임 워크의 특징에 대해서 알아봤는데요!

 

스프링 프레임워크는 줄여서 4가지 특징이 있습니다.

1. 경량

2, 제어의 역행

3. 관점지향

4. 컨테이너

 

이 특징 중, 제어의 역행에 대해 더욱 자세히 살펴보겠습니다.

 

<web.xml>

<HelloServlet.java>

 

 서블릿 컨테이너는 다음 순서에 따라 동작합니다.
• WEB-INF/web.xml 파일을 로딩하여 구동합니다.
• 브라우저로부터 /hello.do 요청 수신합니다.
• hello.HelloServlet 클래스를 찾아 객체를 생성하고 doGet() 메서드 호출합니다.
• doGet() 메소드 실행 결과를 클라이언트 브라우저로 전송합니다.

 이렇듯 컨테이너는 자신이 관리할 클래스들이 등록된 XML 설정 파일을 로딩하여 구동합니다.

그리고 클라이언트의 요청이 들어오는 순간 XML 설정 파일을 참조하여 객체를 생성하고, 객체의 생명주기를 관리합니다.


 스프링 컨테이너 역시 서블릿 컨테이너와 유사하게 동작하여 객체를 생성하고 객체들 사이의 의존관계를 처리하는 것에 대한 책임을 전적으로 개발자 소스코드에 의하지 않고 컨테이너로 처리하도록 하는데 이것을 제어의 역행이라 합니다.

 

 따라서 제어의 역행을 이용하면 소스에서 객체 생성과 의존성 관계에 대한 코드가 사라져 결과적으로 

낮은 결합도의 컴포넌트를 구현할 수 있게 한다. --> 유지보수가 쉬워짐!

 

 

 


두 번째 예제

(1) <결합도(Coupling)가 높은 프로그램>
 결합도란 하나의 클래스가 다른 클래스와 얼마나 많이 연결되어 있는지를 나타내는 표현이며, 결합도가 높은 프로그램은 유지보수가 어렵습니다.


 아래 코드에서 SamsungTVCoupling과 LgTVCoupling는 메서드 이름(signature)이 다르므로 

TVUserCoupling 코드 대부분을 수정해야 TV를 교체할 수 있습니다.

만약 TVUserCoupling과 같은 클라이언트 프로그램이 하나가 아니라 여러 개라면 유지보수는 더욱더 힘들 것이며,

TV 교체를 결정하기가 쉽지 않을 것입니다.

<TvUserCoupling.java>

두번째 예제

여기서 지금 보면 삼성티비를 쓰거나 엘지 티비의 기능을 쓰기 위해서는 각각의 변수를 선언한 뒤,

해당되는 메서드를 불러오는 방식입니다. (메서드 기능은 같지만 이름이 다릅니다.)

삼성티비는 tv로 선언하고 엘지티비는 tv1이라고 선언했습니다.

그럼 엘지 티비는 tv로 접근할 수 없고 tv1으로만 접근할 수 있습니다.

 

<삼성티비>

<엘지티비>

 

// 실행결과
SamsungTV---전원을 켠다.
SamsungTV---소리 올린다.
SamsungTV---소리 내린다.
SamsungTV---전원을 끈다.
LgTV---전원 켠다.
LgTV---소리 올린다.
LgTV---소리 내린다.
LgTV---전원 끈다.

 

이러한 해결 방법 중에는 추상클래스를 만들어 이름을 먼저 통일해 줄 수 있겠죠?

추상클래스를 통해서 변수 객체에 대한 다형성을 구현할 수 있습니다.

 

(2) 다형성 이용하기
 결합도를 낮추기 위해서 다양한 방법을 사용할 수 있겠지만, 가장 쉽게 생각할 수 있는 것이 객체지향 언어의 핵심 개념인 다형성(Polymorphism)을 이용하는 것입니다.
 이 방법 역시 TV를 변경하고자 할 때, TV 클래스 객체를 생성하는 소스를 수정해야만 합니다.

 

위의 예제를 다형성을 이용하여 수정해 보겠습니다~!!

 

<TVUserPolymorphism.java>

<TV인터페이스>

티비는 인터페이스기 때문에 사용하고자 하는 곳에서 재정의를 해야 합니다.

 

<삼성티비- TV 인터페이스를 구현한 구현클래스>

package polymorphism;

public class SamsungTV implements TV {
	private Speaker speaker;
	private int price;

	public SamsungTV() {
		System.out.println("===> SamsungTV(1) 객체 생성");
	}
	
	public SamsungTV(Speaker speaker) {
		System.out.println("===> SamsungTV(2) 객체 생성");
		this.speaker = speaker;
	}

	public SamsungTV(Speaker speaker, int price) {
		System.out.println("===> SamsungTV(3) 객체 생성");
		this.speaker = speaker;
		this.price = price;
	}

	public void initMethod() {
		System.out.println("객체 초기화 작업 처리...");
	}
	
	public void destoryMethod() {
		System.out.println("객체 삭제 전에 처리할 로직 처리...");
	}

	public void setSpeaker(Speaker speaker) {
		System.out.println("===> setSpeaker() 호출");
		this.speaker = speaker;
	}

	public void setPrice(int price) {
		System.out.println("===> setPrice() 호출");
		this.price = price;
	}

	public void powerOn() {
		System.out.println("SamsungTV---전원을 켠다. (가격 : " + price + ")");
	}

	public void powerOff() {
		System.out.println("SamsungTV---전원을 끈다.");
	}

	public void volumeUp() {
		speaker.volumeUp();
		//System.out.println("SamsungTV---소리 올린다.");
	}

	public void volumeDown() {
		speaker.volumeDown();
		//System.out.println("SamsungTV---소리 내린다.");
	}
}

 

<엘지티비- TV 인터페이스를 구현한 구현클래스>

이제 실행을 해볼까요?

실행 결과를 보면 하나의 tv라는 변수에 담아서 삼성과 엘지 티비가 각각 출현이 되죠?

 

이처럼 아까보다는 결합성이 느슨해졌지만 여전히 코드를 반복하여 메서드를 넣어주어야 합니다.

 

더욱더 코드를 느슨하게 해 볼까요?

 


(3) 디자인 패턴 이용하기
 결합도를 낮추기 위한 또 다른 방법으로 디자인 패턴을 이용하는 방법이 있습니다.
 TV를 교체할 때, 클라이언트 소스를 수정하지 않고 명령행 매개변수만 수정하여 TV를 교체할 수 있어 유지보수가 더욱 편리합니다..

 

빈 팩토리 메서드 만들기!

[BeanFactory.java]

[TVUserDesignPattern.java]

원래는 object 타입인데 (TV)로 강제 형변환 하여 factory에 원하는 객체를 만들어 하나씩 아래 코드에 

집어넣게 됩니다. 이 방법이 바로 컨테이너를 이용하는 방법입니다.

TVUser라는 클래스에서 빈팩토리로 객체를 찾으러 갑니다.

argument로 만약에 lg를 주면 빈팩토리에서 LgTV를 찾아서 return 해주게 됩니다.

 

이렇게 하게 된다면 아까 전에 한 추상클래스 구현보다 더 느슨하게 됩니다.

이게 바로 IOC 방법입니다. IoC(Inversion of Control) 제어의 역행이며 

이 방법이 바로 스프링에서 객체를 주입시키는 방법입니다.

 

변수만 딱 선언하고 설정만 준다면 알아서 컨테이너에서 객체를 꺼내와 줍니다.

이렇게 하면 개발자는 바꿀 것이 아무것도 없겠죠?

 

여기까지 변수가 타이트하게 묶여있는 경우부터 변수가 느슨해지는 경우까지 예제를 보았습니다.

 

 

다음시간에는 스프링 컨테이너 예제를 보겠습니다.

 

오늘도 수고하셨습니다😀

728x90