객체 지향 프로그래밍
말 그대로 '객체'를 지향하는 프로그래밍.
코드를 단순한 명령어가 아닌 '객체'로서 바라봄
객체
- 한 묶음으로 상태 값과 기능을 가지는 현실 세계의 사물과 같은 개념
- 객체 간 데이터 교환과 관계를 통해 작업을 진행
다형성
필요한 기능을 정의하여 그 기능을 가진 객체들을 유연하게 바꿔가며 사용할 수 있음
객체 또는 사용자가 필요한 기능을 연결고리(인터페이스)로 정의하고 이를 사용
그럼 이 자리에는 연결고리를 갖고 있는(인터페이스를 구현한) 객체가 들어감으로써
서로 다른 객체여도 사용자가 필요로 하는 연결고리만 갖고 있으면 정상 동작을 보증
예시
노트북에 USB-C 단자라는 연결고리가 있다면 이 연결고리를 통해 64GB 용량을 가지는 메모리, 128GB 용량을
가지는 메모리와 같이 용량과 성능, 브랜드에 상관없이 관계를 가질 수 있다
더 나아가 usb 케이블을 통해 모니터, 키보드, 충전기 등과도 정해진 연결고리만 맞으면 관계를 가질 수 있다
이는 연결고리만 맞으면 된다는 극단적인 예시를 든 것이고 일반적인 개념은
- 연결고리 : 길찾기 기능
- 연결고리를 갖는 부품 : 내비게이션, 스마트폰
이와 같이 있고 사용자가 길찾기 기능을 사용한다고 하면 길찾기 기능이 있는 기기를 사용한다고만
선언하면 이에 대해서는 내비게이션이든 스마트폰이든 사용할 수가 있다
더불어 사용자는 사실 길찾기 기능만 있으면 된다고 할 때 둘 중 어떤 것을 쓴다해도 신경 쓸 필요 없고 몰라도 된다
자바
자바에서는 이 연결고리를 인터페이스로 하여 제공한다
public interface Navi {
public void navigate();
}
다음과 같이 길찾기 기능을 갖고 있는 인터페이스가 있고 이를 자동차라는 객채(클래스)에서 사용하게 하고 싶다면
public class Car {
private Navi navi;
public void setNavi(Navi navi) {
this.Navi = navi
}
public void navigate() {
navi.navigate();
}
}
이렇게 외부에서 Navi 인터페이스를 받아 Navi 인터페이스를 구현한 객체를 받으면 된다
자동차는 길찾기 기능을 가진 부품만 있으면 되기에 그 부품이 내비게이션이든 스마트폰이든 신경 쓰지 않아도 된다
외부에서는
Car car = new Car();
Navi navi = new Navigation();
// Navi navi = new SmartPhone();
car.setNavi(navi);
이처럼 Navi 인터페이스를 구현한 Navigation()이나 SmartPhone()을 같은 Navi 인터페이스에 담아 Car에 세
팅해주면 된다
한계
처음에는 이정도만 할 수 있어도 굉장히 유연하다고 생각이 들지만 결국 뒤에 나올 SOLID 원칙에서 보자면
Navigation 객체에서 SmartPhone 객체를 사용한다 하면
// Navi navi = new Navigation();
Navi navi = new SmartPhone();
으로 변경이 불가피하고(OCP 위배) 자동차 객체(클래스)에서는 담는 건 인터페이스에만 의존하지만 외부에서는
결국 구현체로 구현하며 구현체에 의존하고 있다 (DIP 위배)
이를 해결하기 위해
FileInputStream fis = new FileInputStream("설정파일 경로");
Scanner scan = new Scanner(fis);
String className = scan.nextLine();
Class clazz = Class.forName(className);
Car car = new Car();
Navi navi = (Navi)clazz.newInstance();
car.setNavi(navi);
이처럼 설정파일을 따로 두면 설정파일에서는 변경이 필요하겠지만
동작을 위한 코드에는 일체 변경 없이 Navigation과 SmartPhone 모두 자유롭게 사용할 수 있다
참고로 스프링에서는 이러한 작업들을 내부적으로 지원해주기 때문에
알게 모르게 좋은 객체 지향 설계를 강제하고 있다고 볼 수 있다
SOLID
좋은 객체 지향 설계의 5가지 원칙이라고 원칙들의 앞글자만 따와서 'SOLID'라고 한다
- SRP (Single responsibility principle)
단일 책임 원칙
하나의 책임이라는 말에 애매한 부분이 많지만 결국 뜻하는 바는
'변경에 있어 변경되는 클래스가 맡고 있는 하나의(최소의) 책임만 변경될 수 있도록 설계해야 한다'
라고 본다
- OCP (Open/Closed principle)
개방-폐쇄 원칙
앞서 말한 다형성에서 연결고리만 선언해서 사용한다 했을 때
이 연결고리를 갖는 부품들을 새로 만듦으로써 확장을 할 수 있고
그 밖에 연결고리를 사용하는 부분이나 다른 부분에는 일체 변경은 없다
- LSP (Liskov substitution principle)
리스코프 치환 원칙
연결고리를 갖는(인터페이스를 구현한) 객체는 연결고리(인터페이스)에서 의도한 대로 구현 되어야 한다
연결고리를 갖고 있지만 엉뚱한 기능을 한다면 프로그램 정확성이 깨지고
연결고리로서 의미를 상실하게 된다
- ISP (Interface segregation principle)
인터페이스 분리 원칙
여러 기능을 요구하는 연결고리를 갖기 보다 하나의 기능을 요구하는 연결고리를 여러 개 갖는 게 좋다
- DIP (Dependency inversion principle)
의존관계 역전 원칙
사용하는 객체에 직접 의존하지 말고 연결고리(인터페이스)에 의존해야 한다
대신 객체는 연결고리를 가져야(인터페이스를 구현해야) 하기 때문에 이에 의존관계가 역전되었다 한다
참고
'자바' 카테고리의 다른 글
익명 클래스, 함수형 인터페이스 그리고 람다 (0) | 2021.03.14 |
---|
댓글