Spring, DI, IoC란? (1)

infoqoch·2021년 4월 26일
0

스프링

목록 보기
2/5

들어가며

  • DI, IoC, 객체지향 프로그래밍을 배우며 항상 듣는 것 중 하나가 있다. "객체 간 의존성을 줄인다." 객체 간 의존성을 줄인다는 도대체 무슨 말일까?

DI가 없는 코드

  • 시나리오 : 학생(Student)가 책(Book)을 공부(study)한다.
public class Student {
    public void study() {
        Book book = new Book();
        System.out.println(book.getName()+"을/를 공부한다.");
    }
}

public class Book {
    private String name= "영어";
    public String getName() {
        return this.name;
    }
}

public class Test {
    public static void main(String[] args) {
        Student student = new Student();
        student.study(); 
    }
}
---
결과 : 영어을/를 공부한다.
  • 만약 내가 여기서 내가 공부하고 싶은 것이 "영어"가 아니라 "수학"이 되려면 어떻게 해야 할까?
public class Book {
    // private String name= "영어";
    private String name= "수학";
    public String getName() {
        return this.name;
    }
}
결과 : 수학을/를 공부한다.
  • 만약 내가 여기서 책이 아니라 인강으로 공부하고 싶으면 어떻게 할까?
public class Student {
    public void study() {
    	//Book book = new Book();
		//System.out.println(book.getName()+"을/를 공부한다.");
        Youtube youtube = new Youtube();
        System.out.println(youtube.getName()+"을/를 공부한다.");
    }
}

public class Youtube {
    private String name= "꽃꽂이";
    public String getName() {
        return this.name;
    }
}
결과 : 꽃꽂이을/를 공부한다.
  • 이처럼 우리는 해당 값을 수정하기 위하여 class 내부를 수정해야 한다.

DI를 적용한 코드

  • 위의 코드를 아래와 같이 변경하면 어떨까?
public class Student {
    private Resources resources;
    public Student(Resources resources){
        this.resources = resources;
    }
    public void study() {
        System.out.println(resources.getThings()+"을/를 공부했다");
    }
}

public interface Resources {
    String getThings();
    void setThings(String things);
}

public class Book implements Resources {
    private String things;

    @Override
    public String getThings() {
        return this.things;
    }

    @Override
    public void setThings(String things) {
        this.things = things;
    }
}

public class Test {
    public static void main(String[] args) {
        Resources resources = new Book();
        resources.setThings("국어");
        Student student = new Student(resources);
        student.study();
    }
}
결과 : 국어을/를 공부했다
  • 만약 여기서 국어가 아닌 과학을 공부하려면 어떻게 해야할까?
public class Test {
    public static void main(String[] args) {
        Resources resources = new Book();
        //resources.setThings("국어");
        resources.setThings("과학");
        Student student = new Student(resources);
        student.study();
    }
}
결과 : 과학을/를 공부했다
  • 만약 유튜브로 공부하면 어떻게 될까?
public class Youtube implements Resources{
    private String things;

    @Override
    public String getThings() {
        return this.things;
    }

    @Override
    public void setThings(String things) {
        this.things = things;
    }
}

public class Test {
    public static void main(String[] args) {
//        Resources resources = new Book();
//        resources.setThings("국어");
        Resources resources = new Youtube();
        resources.setThings("요리");
        Student student = new Student(resources);
        student.study();
    }
}
결과 : 요리을/를 공부했다
  • Student와 Resource, Book 객체 어떤 것도 건들지 않았다. 새로운 부품(Youtube)를 만들고 메인스레드에 원하는 값을 넣었다.

DI와 IoC란?

1) 클래스가 다른 클래스에 영향을 받는 것과 매개변수를 통해 값을 변경하는 것.

  • DI를 적용한 코드와 그렇지 않은 코드의 가장 큰 차이 중 하나는 매개변수의 활용이다.
  • 매개변수를 사용하는 것만으로도 매우 편해진다. 클래스를 수정할 필요가 없이 메인스레드에만 집중하면 된다.

2) DI란?

  • 그런데, 단순하게 String이나 int를 통해 해소되지 않을 수 있다. 하나의 클래스를 생성하는데 있어서 다수의 클래스가 필요한 경우가 많으니까. 웹 개발시 Controller는 여러 개의 Service 객체가 필요할 수 있으니까.
  • 그 객체도 마찬가지로 매개변수를 통해 주입한다. 이를 DI라 한다.
  • DI란 Dependency Injection의 준말이다. 의존성 주입이다. 너무 어렵다. 내가 자주 보는 유튜브 뉴렉처(https://www.youtube.com/channel/UC5-ixpj8DioZqmrasj6Ihpw/playlists)에서는 이것을 간단하게 설명한다. 바로 부품!
  • 실제로 부품이라 이해하면 더 쉽게 다가온다. 학생이 공부를 할 때 책은 일종의 부품이다. 하나의 컨트롤러가 다수의 Service 객체를 사용해서 클라이언트에 데이타를 넘긴다. 그러므로 컨트롤러의 입장에서 service 객체 역시 부품이다.
  • 부품을 전달하는 방식을 매개변수로 할 경우, 부품을 사용하는 클래스를 수정하지 않고 사용할 부품만 매개변수로 교환하면 된다. 훨씬 편해졌다.
  • 그럼 부품은 어떻게 교환하는가?

3) 인터페이스의 장점

  • 이전의 코드는 Student에 Book이나 Youtube 객체를 바로 주입했다. 그러나 DI를 적용한 코드는 interface를 사용했다. interface란 일종의 틀거리다. 공부를 항상 책으로 할 필요가 없다. 공부는 책, 유튜브, 선생님, 라디오 등 다양한 것을 가지고 할 수 있다. 우리는 이것을 대략 "수업자료"라 칭할 수 있다. 마찬가지로 Student가 study할 대상 역시 확실하게 정의되지 않았지만 "수업자료" 같이 애매하게 정의할 수 있다. 이를 interface라 한다.
  • "수업자료"에 합당한 것은 일단 배울만한 가치가 있어야 하고, 이해할 수 있어야 한다. interface도 마찬가지다. getThings()와 setThings()를 인터페이스에 정의하면, 그것의 객체도 그것을 정의(@Override) 해야 한다. 이것에 걸맞는 것을 정의하여 Book 객체와 Youtube 객체를 만들 수 있다.

4) IoC란?

  • 그럼 우리는 study를 하기 위해서 어떤 과정을 거쳤던가?
public class Test {
    public static void main(String[] args) {
        Resources resources = new Youtube();
        resources.setThings("요리");
        Student student = new Student(resources);
        student.study();
    }
}
  • 학생이 공부를 한다고 가정하면 보통 학생->공부->책 이란 순서로 생각한다. DI가 없는 코드는 마찬가지로 Student 객체를 생성한 후, Book 객체가 study() 매서드에서 호출 된다.
  • 하지만 메인스레드를 보면 정의하는 과정이 다르다. 책->학생->공부. Resource -> Student
  • 이처럼 정의하는 과정이 역전되어 있다. 이를 제어의 역전 Inversion of Control 이라 한다.

나아가며

  • DI와 IoC를 통해 결합도를 낮추고, 객체의 수정을 최소화 하는 과정을 정리해봤다. 그런데 만약 메인스레드 자체를 수정하고 싶지 않으면 어떻게 해야할까? 그러니까 어플리케이션의 코드가 너무 완벽해서 그 누구도 수정하지 않기를 바랄 경우, 메인 스레드조차 수정하지 않기를 원하는 경우 우리는 어떻게 할 수 있을까?
  • 그때 활용하는 것이 XML이다. XML을 활용하면 우리는 어플리케이션 코드 자체를 일절 건드리지 않고 책으로 영어공부하는 것에서 유튜브로 꽃꽂이를 공부할 수 있게 된다. 이 부분은 다음에 정리하고자 한다.
profile
JAVA web developer

0개의 댓글