스프링을 공부하기 앞서 스프링의 기반이 되는 JAVA에 대해서 알아볼 필요가 있다.
JAVA는 C++와 함께 대표적인 객체 지향 프로그래밍 언어로 잘 알려져 있다.
그렇다면 객체 지향 프로그래밍이라는건 어떤 것을 의미하는 것일까?
객체 지향 프로그래밍은 하나의 프로그래밍 스타일 혹은 패러다임을 의미하고 프로그램을 구성하는 요소들을 각각 독립적인 "객체"로 나누고, 객체들과의 상호작용을 통해 프로그램이 작동하게 된다.
여기서 객체란 데이터(혹은 필드)와 기능(메서드 혹은 함수)를 하나로 묶어 캡슐화된 단위를 의미한다.
이 객체 지향 프로그래밍에는 크게 4가지 아주아주 중요한 특징을 가지고 있는데 이 특징들에 대해서 간단하게 알아보고자 한다.
객체 지향 프로그래밍이란 "객체"들과의 상호작용을 통해 프로그램을 동작하게 하는 하나의 스타일이다.
객체 지향 프로그래밍의 4가지 특징으로는
캡슐화(Encapsulation),
추상화(Abstraction),
다형성(Polymorphism),
상속(Inheritance)
가 있고 각 특성의 특징에 대해 간단한 코드와 함께 알아보자
앞서 객체를 데이터와 기능을 하나로 묶은 캡슐화된 단위라고 설명했다.
즉, 캡슐화는 연관된 데이터와 기능을 하나로 묶는것이다.
캡슐화의 가장 중요한 특징이자 목표로 "정보은닉"이 있다.
정보 은닉이란 객체 내부의 구성을 숨김으로써 객체 내부 요소에 대한 불필요한 직접적 접근을 막고 제한된 방법으로만 객체에 접근하도록 하므로써 응집도를 높이고 결합도를 낮춘다.
자바의 경우 접근제한자를 통해 정보은닉을 구현하며
public
protected
default
private
4종류가 있고, 이를 통해 접근을 제한한다.
public | protected | default | private | |
---|---|---|---|---|
클래스 내부 | O | O | O | O |
동일한 패키지 | O | O | O | X |
하위(자식)클래스 | O | O | X | X |
그 외 | O | X | X | X |
public class Pnp{
//필드
private int studentId;
private String name;
private int score;
//메서드
public string getPassStatus(){
if(score >= 70){
return "P"
}else{
return "NP"
}
}
// studentId setter
public void setStudentId(int studentId) {
this.studentId = studentId;
}
// studentId getter
public int getStudentId() {
return studentId;
}
// name setter
public void setName(String name) {
this.name = name;
}
// name getter
public String getName() {
return name;
}
// score setter
public void setScore(int score) {
this.score = score;
}
// score getter
public int getScore() {
return score;
}
}
추상화란 객체들의 공통적인 데이터와 기능을 한데 묶어 핵심적인 특징이나 기능을 간추리는것을 의미한다.
즉, 중요한 부분을 간결하게 표현하고 불필요한 부분은 숨기는 것이다.
추상화를 통해 코드의 복잡성을 감소시키고, 불필요한 중복을 제거하여 재사용성을 늘릴 수 있다.
JAVA에서는 보통 인터페이스, 추상 클래스를 통해 구현할 수 있다.
public interface Playable{
void play();
void pause();
void stop();
void next();
void last();
}
public class VideoPlayer implements Playable{
@override
public void play(){
//재생 기능 구현
}
@override
public void pause(){
//일시정지 기능 구현
}
@override
public void stop(){
//중지 기능 구현
}
@override
public void next(){
//다음 영상 실행 기능 구현
}
@override
public void last(){
//이전 영상 실행 기능 구현
}
}
public abstract class Bird{
private String name;
public abstract void chirping();
public void setName(String name){
this.name = name
}
public String getName(){
return name;
}
public class seagull extends Bird{
//생성자
public seagull(String name){
this.setName(name)
}
@override
public void chirping(){
System.out.println("KKack KKack")
}
다형성이란 각 요소들이 상황에 맞는 형태를 가질 수 있는 특성이다.
이 특성으로 인해 하나의 메서드 이름으로 여러 버전의 메서드를 정의할 수 있고(overloading)
상위 클래스 혹은 인터페이스의 요소들을 하위클래스에 맞게 변경하거나 확장할 수 있다.(overriding)
이 특성으로 인해 상위 클래스 혹은 인터페이스는 하위 클래스의 동작방식을 몰라도 된다.
오버라이딩의 경우 위의 Bird 추상 클래스 예시와 같이 chirping()이라는 상위 클래스의 매서드를 하위 클래스인 seagull()에 맞게 구현 한 것과 같다.
public class MathUtils {
// int 타입 두 개의 숫자 합을 계산하는 메서드
public int add(int a, int b) {
return a + b;
}
// double 타입 두 개의 숫자 합을 계산하는 메서드
public double add(double a, double b) {
return a + b;
}
// int 타입 세 개의 숫자 합을 계산하는 메서드
public int add(int a, int b, int c) {
return a + b + c;
}
}
오버로딩은 같은 메서드의 이름을 가지고 파라미터의 개수 또는 타입(이것을 메소드 시그니처라고 함),반환값을 변경하여 여러 버전의 메서드를 정의하는 것이다.
위의 예시와 같이 같은 이름의 메서드이지만 메서드 시그니처를 가각 다르게 정의하여 호출 시점에 전잘하는 파라미터에 따라 자동으로 선택되어 실행된다.
상속은 앞서 추상화 및 다형성의 예시에서 처럼 상위 클래스(인터페이스)의 요소들을 하위클래스가 재활용하여 사용할 수 있고 이로인해 코드의 불필요한 중복을 줄이고 객체를 세분화 할 수 있다.
클래스를 상속할때는 extends(다중 상속 불가)
인터페이스를 상속할때는 implements(다중 상속 가능)를 사용한다.
객체 지향 프로그래밍의 4가지 특성인 캡슐화, 추상화, 다형성, 상속에 대해서 알아봤는데
객체 지향 프로그래밍을 공부할 때 마다 느끼는 것이지만 이 4가지 특성을 따로 따로 설명하는것이 상당히 어렵다고 생각한다.
특성들이 서로 얽히고 설켜 있기 때문에 하나하나 따로 이해하려하기 보다 유기적으로 생각하며 공부하는것이 훨씬 효과적일 것이라고 생각한다.
이런 객체 지향을 더 잘 설계하기위한 원칙인 S.O.L.I.D라는것도 있는데 이 개념은 다음에 알아보도록 하자.