스프링은 자바를 기반으로 한 기술이다.
따라서 스프링이 가장 중요하게 가치를 두는 것은 객체지향 프로그래밍이 가능한 언어라는 점이다.
🧐 객체지향 프로그래밍(OOP, Object Oriented Programming)란?
객체(클래스) = 속성(변수) + 기능(메소드)
'실제 세계는 사물(객체)로 이루어져 있으며, 발생하는 모든 사건들은 사물간의 상호작용이다.'라는 개념으로 시작된다.
따라서 객체들의 집합으로 프로그램의 상호 작용을 표현하며 데이터를 객체로 취급하여 객체 내부에 선언된 메소드를 활용하는 방식이라 볼 수 있다.
특징으로는 추상화, 캡슐화, 상속성, 다형성이 있다.
스프링이 가장 관심을 많이 두는 대상은 오브젝트(객체)이다.
오브젝트 생성, 관계, 사용, 소멸까지의 전 과정 및 어떻게 설계할지, 어떤 단위로 만들어야할지도 생각해야한다.
이런 관심은 오브젝트의 특징과 사용방법을 넘어서 오브젝트의 설계로 발전하게 된다.
이 때는 객체지향 설계(Object Oriented Design)의 기초와 원칙, 디자인 패턴, 리팩토링, 단위 테스트 등에 대한 기술과 지식이 요구된다.
DAO(Data Access Object)란?
DB를 사용해 데이터를 조회 및 조작하는 기능을 전담하도록 만든 오브젝트
자바빈(JavaBean)이란?
- 원래는 비주얼 툴에서 조작 가능한 컴포넌트를 의미했음
- 자바의 주력 개발 플랫폼이 웹 기반 엔터프라이즈 방식으로 바뀌면서 사라졌음
- 하지만 몇 가지 코딩 관례가 이어지고 있음
- 자바빈 또는 빈이라고 말하면 다음 두 가지 관례를 따라 만들어진 오브젝트를 가리킴
- 디폴트 생성자
- 자바빈은 파라미터가 없는 디폴트 생성자를 갖고 있어야함
- 툴이나 프레임워크에서 리플렉션을 이용해 오브젝트를 생성하기 때문에 필요함
- 프로퍼티
- 자바빈이 노출하는 이름을 가진 속성을 프로퍼티라고 함
- 프로퍼티는 set으로 시작하는 수정자 메소드(setter)와 get으로 시작하는 접근자 메소드 (getter)를 이용해 수정 또는 조회할 수 있음
- 디폴트 생성자
// 자바빈 규약을 따르는 오브젝트 예시
public class User {
String id;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
}
개발자가 객체를 설계할 때 가장 염두에 둬야 할 사항
- 미래의 변화를 어떻게 대비할 것인가?
- 변화는 며칠, 몇 시간 후에 발생 가능
- 가장 좋은 대책은 변화의 폭을 최소한으로 줄이는 것
변경 발생 시 필요한 작업을 최소화하고, 그 변경이 다른 곳에 문제를 일으키지 않게 하려면 분리와 확장을 고려한 설계 필요함.
- 모든 변경과 발전은 한 번에 한 가지 관심사항에 집중해서 발생
- 문제점
- 변화는 집중된 한 가지 관심에서 발생하지만, 작업은 한 곳에 집중되지 않는 경우가 많음
- 1가지를 바꾸려면 연관된 100가지를 수정해야할 수 있음
- 해결 방법
- 한 가지 관심이 한 군데 집중되게 하는 것
- 관심이 같은 것끼리 모으고, 관심이 다른 것은 따로 떨어져 있게 하는 것
- 관심사의 분리(Separation Of Concerns)를 객체지향에 적용
- 관심이 같은 것 끼리는 하나의 객체 안 또는 친한 객체로 모이게 하고, 관심이 다른 것은 가능한 따로 떨어져서 서로 영향을 주지 않도록 분리하는 것
- 문제점
// 관심사의 분리 예시
public void add(User user) throws ClassNotFoundException, SQLException {
Connection c = getConnection();
...
}
public void get(String id) throws ClassNotFoundException, SQLException {
Connection c = getConnection();
...
}
// DB 연결 기능이 필요하면 getConnection() 이용
private Connection getConnection() throws ClassNotFoundException, SQLException {
Class.forName("com.mysql.jdbc.Driver");
Connection c = DriverManager.getConnection("jdbc:mysql://localhost/springbook", "spring", "book");
return c;
}
DB 연결이 필요한 메소드인 add()와 get() 이 있다고 가정했을 때, 각 메소드에서 DB를 연결하는 코드를 작성했을 수 있다.
그런 중복되는 DB 연결 코드를 getConnection() 이라는 독립적인 메소드로 만든다.
- 메소드가 100개이고, DB 연결과 관련된 부분에 변경이 일어났을 경우
- getConnection() 만 수정하면 된다
- 관심의 종류에 따라 코드를 구분했기에, 한 가지 관심에 대한 변경이 일어날 경우 그 관심이 집중되는 부분의 코드만 수정하면 됨
- 관심이 다른 코드가 있는 메소드(add, get)에는 영향을 주지 않고, 관심 내용이 독립적으로 존재하므로 수정도 간단해짐
이렇게 똑같은 기능이지만 여러 메소드에 중복돼서 등장하는 특정 관심사항이 담긴 코드를 별도의 메소드로 분리해낸 것을 리팩토링이라 함
- 기능에는 영향 X, 코드 구조만 변경 O
- 이전보다 깔끔해지고, 미래의 변화에 좀 더 손쉽게 대응할 수 있는 코드 O
- 코드 가독성, 생산성, 품질 증가 및 유지보수 용이
공통의 기능을 담당하는 메소드로 중복된 코드를 뽑아내는 것을 리팩토링에서는 메소드 추출(Extract Method) 기법이라 부름
상속을 통한 확장
UserDao 클래스로는 사용자마다 다른 getConnection()을 만들기 힘들다.
따라서 오른쪽 구조처럼 상속을 통한 확장으로 방법을 제공하고 있다.
getConnection()을 추상메소드로 만들고 사용자가 상속해서 원하는 방식대로 구현하는 방법이다.
- 클래스 계층 구조를 통해 두 개의 관심이 독립적으로 분리되어 변경 작업 용이
- "어떻게 데이터를 등록하고 가져올 것인가" 라는 관심을 담당하는 UserDao
- "DB 연결 방법은 어떻게 할 것인가?" 라는 관심을 담고있는 NUserDao와 DUserDao
- 이제는 새로운 DB 연결 방법을 적용해야 할 때는 상속을 통해 확장하면 됨
디자인 패턴(Design Patterns)
디자인 패턴은 소프트웨어 설계 시 특정 상황에서 자주 만나는 문제를 해결하기 위해 사용할 수 있는 재사용 가능한 솔루션을 말함.
- 모든 패턴에는 간결한 이름이 있어서 잘 알려진 패턴을 적용하고자 할 때 간단히 패턴 이름을 언급하는 것만으로도 설계의 의도와 해결책을 함께 설명할 수 있음
- 디자인 패턴은 주로 객체지향 설계에 관한 것이고, 대부분 객체지향적 설계 원칙을 이용해 문제를 해결함
- 패턴에서 가장 중요한 것은 각 패턴의 핵심이 담긴 목적 또는 의도이다
- 패턴을 적용할 상황, 해결해야할 문제, 솔루션의 구조와 각 요소의 역할과 함께 핵심 의도가 무엇인지를 기억해야함
템플릿 메소드 패턴(Template Method Pattern)
- 상속을 통해 슈퍼클래스의 기능을 확장할 때 사용하는 가장 대표적인 방법
- 변하지 않는 기능은 슈퍼클래스에 만들어두고 자주 변경되며 확장할 기능은 서브클래스에서 만듦
- 슈퍼클래스에서는 미리 추상메소드 또는 오버라이드 가능한 메소드를 정의해둬서 이를 활용해 코드의 기본 알고리즘을 담고 있는 템플릿 메소드를 만듦
- 슈퍼클래스에서 디폴트 기능을 정의 또는 비워뒀다가 서브클래스에서 선택적으로 오버라이드 할 수 있도록 만들어둔 메소드를 훅(hook)메소드라고 함
- 서브클래스에서는 추상 메소드를 구현하거나, 훅 메소드를 오버라이드하는 방법을 이용해 기능 일부를 확장함
public abstract class Super {
// 기본 알고리즘 골격을 담은 메소드인 템플릿 메소드
// 템플릿 메소드는 서브클래스에서 오버라이드하거나 구현할 메소드 사용
public void templateMethod() {
// 기본 알고리즘 코드
hookMethod();
abstractMethod();
...
}
// 선택적으로 오버라이드 가능한 훅 메소드
protected void hookMethod();
// 서브클래스에서 반드시 구현해야 하는 추상 메소드
public abstract void abstractMethod();
}
// 슈퍼클래스의 메소드를 오버라이드하거나 구현해서 기능 확장
// 다양한 확장 클래스 생성 가능
public class Sub1 extends Super {
protected void hookMethod() {
...
}
public void abstractMethod() {
...
}
}
팩토리 메소드 패턴(Factory Method Pattern)
- 템플릿 메소드 패턴과 마찬가지로 상속을 통해 기능을 확장하는 패턴 (구조가 비슷함)
- 슈퍼클래스의 코드에서는 서브클래스에서 구현할 메소드를 호출해서 필요한 타입의 오브젝트를 가져와 사용함
- 이 메소드는 주로 인터페이스 타입으로 오브젝트를 리턴하므로, 서브클래스에서 어떤 클래스의 오브젝트를 만들어 리턴할지는 슈퍼클래스에서는 알지 못함
- 서브클래스는 다양한 방법으로 오브젝트를 생성하는 메소드를 재정의할 수 있음
- 이렇게 서브클래스에서 오브젝트 생성 방법과 클래스를 결정할 수 있도록 미리 정의해둔 메소드를 팩토리 메소드라 함
- 팩토리 메소드를 통해 오브젝트 생성 방법을 나머지 로직, 즉 슈퍼클래스의 기본 코드에서 독립시키는 방법을 팩토리 메소드 패턴이라 함
- 자바에서는 종종 오브젝트를 생성하는 기능을 가진 메소드를 일반적으로 팩토리 메소드라고 부르기도 함
- 이 때 말하는 팩토리 메소드와 팩토리 메소드 패턴의 팩토리 메소드는 의미가 다름
UserDao의 서브클래스의 getConnection() 메소드는 어떤 Connection 클래스의 오브젝트를 어떻게 생성할 것인지를 결정하는 방법이라고 볼 수 있다. 이렇게 서브클래스에서 구체적인 오브젝트 생성 방법을 결정하게 하는 것을 팩토리 메소드 패턴이라고 부른다.
'도서' 카테고리의 다른 글
[Clean Code] 3장 함수 (0) | 2023.04.27 |
---|---|
[Clean Code] 2장 의미 있는 이름 (0) | 2022.02.13 |
[Clean Code] 1장 깨끗한 코드 (0) | 2022.02.13 |
[Clean Code] 시작 (0) | 2022.02.12 |