Study with book/토비의 스프링 3.1

1장. 오브젝트 의존관계1


토비 스프링을 공부하면서 실습했던 내용과 모르는 내용만 기록을 위해서 포스팅한다.

 

객체지향 프로그래밍이 제공하는 폭넓은 혜택을 누릴 수 있도록 기본으로 돌아가자는 것이 스프링 핵심 철학이다. 스프링이 가장 관심을 많이 두는 대상은 오브젝트이다. 스프링이 관심을 갖는 대상인 오브젝트의 설계와 구현, 동작원리에 더 집중하길 바란다.

1.1 초난감 DAO

1.1.1 User

실습 코드 링크: https://github.com/vvshinevv/toby-spring/tree/feature/1.1.1

 자바빈디폴트 생성자프로퍼티 관례에 따라서 만들어진 오브젝트를 가리킨다.

 - 디폴트 생성자: 자바빈은 파라미터가 없는 디폴트 생성자를 갖고 있어야 한다. 툴이나 프레임워크에서 리플렉션을 이용해 오브젝트를 생성하기 때문이다.

 - 프로퍼티: 자바빈이 노출하는 이름을 가진 속성을 프로퍼티라고 한다. 프로퍼티는 수정자 메소드와 접근자 메소드를 이용해 수정 및 조회할 수 있다.

 

1.1.2 UserDao

실습 코드 링크: https://github.com/vvshinevv/toby-spring/tree/feature/1.1.2

 스터디에서 나온 내용으로 Class.forName() 메소드로 클래스 로더를 통해서 Driver를 등록해주는데, 이 것은 자바 1.6 부터 DriverManager.getConnection() 메소드를 호출하면 자동으로 등록해준다고 한다. Class.forName을 통해서 jdbc driver가 등록되는 과정은 나중에 한번 공부해봐야겠다. 

 

1.1.3 main()을 이용한 DAO 테스트 코드

실습 코드 링크: https://github.com/vvshinevv/toby-spring/tree/feature/1.1.3

 mysql-connector-java-5.1.7-bin.jar 파일을 클래스패스에 넣어줘야 한다. 여기서 클래스패스란 클래스를 찾기 위한 경로이다. JVM이 프로그램을 실행할 때, 클래스 파일을 찾는데 기준이 되는 파일 경로이다. 스터디 내용에서 클래스패스의 티폴트 경로와 JVM이 클래스패스를 어떻게 찾아가는지도 공부하면 좋을 것 같다는 이야기 나왔다. (해당 내용은 https://vvshinevv.tistory.com/70에 정리해 두었다.)

 

다음 아래 나열하는 질문들은 실제로 우리가 스프링을 공부하는 목적이고, 개발자로 성장하면서 항상 질문해야할 마음가짐 같아서 길지만 내용을 적는다.

왜 정상적으로 돌아가는 코드에 문제가 많다고 하는 것일까? 잘 동작하는 코드는 굳이 수정하고 개선해야 하는 이유는 뭘까? 그렇게 DAO 코드를 개선했을 때의 장점은 무엇일까? 그런 장점들이 당장에, 또는 미래에 주는 유익은 무엇인가?객체지향 설계의 원칙과는 무슨 상관이 있을까? 이 DAO를 개선하는 경우와 그대로 사용하는 경우, 스프링을 사용하는 개발에서 무슨 차이가 있을까?

 

1.2 DAO의 분리

1.2.1 관심사의 분리

 객체지향 프로그래밍이 이전의 절차적 프로그래밍 패러다임에 비해 초기에 좀 더 많은, 번거로운 작업을 요구하는 이유는 객체지향 기술 자체가 지니는, 변화에 효과적으로 대처할 수 있다는 기술적인 특징 때문이다. 이 문장에서 객체지향 프로그래밍과 절차적 프로그래밍이란 것은 무엇을 의미할까? 공부해보면 좋을 듯하다.

 

1.2.2 커넥션 만들기의 추출

실습 코드 링크: https://github.com/vvshinevv/toby-spring/tree/feature/1.2.2

 기능이 추가되거나 바뀐 것은 없지만 UserDao는 이전보다 훨씬 깔끔해졌고 미래의 변화에 좀 더 손쉽게 대응할 수 있는 코드가 됐다. 이런 작업을 리팩토링이라고 한다. 또한 위에서 사용한 getConnection()이라고 하는 공통의 기능을 담당하는 메소드로 중복된 코드를 뽑아내는 것을 메소드 추출기법이라고 한다.

 

1.2.3 DB 커넥션 만들기의 독립

실습 코드 링크: https://github.com/vvshinevv/toby-spring/tree/feature/1.2.3

 슈퍼클래스에 기본적인 로직의 흐름을 만들고, 그 기능의 일부를 추상 메소드나 오버라이딩이 가능한 protected 메소드 등으로 만든 뒤 서브클래스에서 이런 메소드를 필요에 맞게 구현해서 사용하도록 하는 방법을 템플릿 메소드 패턴이라고 한다.

 UserDao의 서브클래스의 getConnection() 메소드는 어떤 Connection 클래스의 오브젝트를 어떻게 생성할 것인지를 결정하는 방법이라고 볼 수 있다. 이렇게 서브클래스에서 구체적인 오브젝트를 생성 방법을 결정하게 하는 것을 팩토리 메소드 패턴이라고 부른다. 이때 말하는 1) 팩토리 메소드2)팩토리 메소드 패턴의 팩토리 메소드는 의미가 다르다. 상속의 개념이 들어가면 2)번 이라고 이해하고 없으면 1)번이라고 이해하자. 기본적을 1)번의 의미의 경우 뒤에서 나오는 DaoFactory와 같이 특정 인터페이스를 구현한 객체를 단순히 리턴하는 것이고 2)번의 경우 상속의 개념을 포함하여 로직적인 흐름 속에서 변화가 일어날 수 있는 특정 객체를 선택하여 그 흐름이 이어지는 것이라고 보면 된다.

 

1.3 DAO의 확장

1.3.1 클래스의 분리

실습 코드 링크: https://github.com/vvshinevv/toby-spring/tree/feature/1.3.1

 

1.3.2 인터페이스의 도입

실습 코드 링크: https://github.com/vvshinevv/toby-spring/tree/feature/1.3.2

 추상화란 어떠 것들의 공통적인 성격을 뽑아내어 이를 따로 분리해내는 작업이다. 추상화와 관련해서 스터디를 하면서 정보 은닉캡슐화의 개념에 대해서 이야기해보는 시간을 가졌다. 정보 은닉과 캡슐화 내용은 추후에 다시 정리하도록 하겠다.

 

1.3.3 관계설정 책임 분리

실습 코드 링크: https://github.com/vvshinevv/toby-spring/tree/feature/1.3.3

 클래스 사이에 관계가 만들어진다는 것은 한 클래스가 인터페이스 없이 다른 클래스를 직접 사용한다는 뜻이다. 따라서 클래스가 아니라 오브젝트와 오브젝트 사이의 관계를 설정해줘야 한다. 클래스 사이의 관계는 코드에 다른 클래스 이름이 나타나기 때문에 만들어지는 것이다. 오브젝트 사이의 관계는 특정 클래스를 전혀 알지 못하더라도 해당 클래스가 구현한 인터페이스를 사용했다면, 그 클래스의 오브젝트를 인터페이스 타입으로 받아서 사용할 수 있다. 다형성의 특징인 것이다.

 

1.3.4 원칙과 패턴

객체지향 설계의 원칙(SOLID)은 검색하면 많이 나오는 용어이기 때문에 간단하게 한 문장으로만 알고 넘어가도록 한다.

 1. SRP(The Single Responsibility Principle) : 단일 책임 원칙 (https://siyoon210.tistory.com/155)

 - 함수 혹은 클래스는 하나의 기능만 수행해야 한다.

 - 특정 기능에 수정이 발생하는 경우 하나의 함수 혹은 클래스에서 수정이 일어나야 한다.

 2. OCP(The Open Closed Principle) : 개방 폐쇄 원칙 (http://wonwoo.ml/index.php/post/1726)
 - 기존 코드를 수정하지 않으면서, 기능을 추가할 수 있도록 되어야 한다.

 - UserDao는 DB연결 방법이라는 기능에는 열려 있고, UserDao 핵심 기능에는 닫혀 있다.

 3. LSP(The Liskov Subsititution Priciple) : 리스코프 치환 원칙 (http://wonwoo.ml/index.php/post/1780)

 - 상위 타입의 객체를 하위 타입의 객체로 치환해도 상위 타입을 사용하는 프로그램은 정상적으로 작동해야 한다.

 - 상속과 관련된 이야기로, Animal animal = new Cat();Cat animal = new Cat();으로 치환해도 정상적으로 작동해야 한다.

 - Collections.unmodifiableList와 같은 시리즈는 리스코프 치환 원칙을 무시하는 행위이다.

 4. ISP(The Interface Segregation Principle) : 인터페이스 분리 원칙 (http://wonwoo.ml/index.php/post/1675)

 - 자신이 사용하지 않는 인터페이스는 구현하지 않아야 한다.

 - 자동차 인터페이스에 자동 주행 기능이 있는데, 아반떼의 경우 자동 주행 기능이 없다면 구현하면 안 된다. 다른 인터페이스로 분리해야 한다.

 5. DIP(The Dependency Inversion Principle) : 의존관계 역전 원칙 (https://vandbt.tistory.com/42)

 - 추상화된 것은 구체화된 것에 의존하면 안된다. 구체화된 것이 추상화된 것에 의존되어야 한다.

 - ConnectionMaker conn = new DConnectionMaker();로 선언하면 안된다.

 

전략 패턴변화가 필요한 것은 인터페이스를 통해 통째로 외부로 분리시키고, 이를 구현한 구체적인 알고리즘 클래스를 필요에 따라 바꿔서 사용할 수 있는 패턴이다.

 

1.4 제어의 역전(IoC)

1.4.1 오브젝트 팩토리

실습 코드 링크: https://github.com/vvshinevv/toby-spring/tree/feature/1.4.1

DaoFactory 클래스는 객체의 생성 방법을 결정하고 그렇게 만들어진 오브젝트를 돌려준다. 이런 역할을 하는 오브젝트를 팩토리라고 말하는데, 추상 팩토리 패턴팩토리 메소드 패턴과는 다르다. 스터디에서 추상 팩토리 패턴과 팩토리 메소드 패턴은 조사해서 돌아가면서 발표하기로 했는데 다른 포스팅으로 남기도록 하겠다.

UserDao와 ConnectionMaker는 각각 애플리케이션의 핵심적인 데이터 로직과 기술 로직을 담당(컴포넌트)하고 있고, DaoFactory는 이런 애플리케이션의 오브젝트들을 구성하고 그 관계를 정의하는 책임(설계도)을 맡고 있다. 

 

1.4.2 오브젝트 팩토리의 활용

실습 코드 링크: https://github.com/vvshinevv/toby-spring/tree/feature/1.4.2

 

1.4.3 제어권의 이전을 통한 제어관계 역전

제어의 역전이란 건, 간단히 프로그램 제어 흐름 구조가 뒤바뀌는 것이라고 설명할 수 있다. 제어의 역전에서는 오브젝트가 자신이 사용할 오브젝트를 스스로 선택하지 않으며, 생성도 하지 않는다. 라이브러리와 프레임워크의 차이점제어의 역전이 들어가 있는지 없는지에 있다. 라이브러리는 동작하는 중에 필요한 기능이 있을 때 능동적으로 라이브러리를 사용할 뿐이다. 반면에 프레임워크는 거꾸려 어플리케이션 코드가 프레임워크에 의해 사용된다. 프레임워크에는 분명한 제어의 역전 개념이 적용되어 있어야 한다.


[참고자료]

토비 스프링 vol.1 - 이일민

https://pjh3749.tistory.com/250

https://kyun2.tistory.com/23

https://www.slipp.net/questions/276

'Study with book > 토비의 스프링 3.1' 카테고리의 다른 글

4장. 예외  (0) 2020.03.29
3장. 템플릿2  (0) 2020.03.22
3장. 템플릿1  (0) 2020.03.22
2장. 테스트  (0) 2020.03.15
1장. 오브젝트 의존관계2  (0) 2020.03.15