이전 포스팅에서 Java의 동작 순서에 포스팅을 하면서 Java의 대표적인 특징인 객체 지향 언어라는 점을 생각해보게 되었다.
과연 나는 누군가가 '객체 지향 언어가 뭐죠?'라는 묻는 질문에 어떻게 대답을 해야 할지 고민해봤다.
명확하게 이런 것이라고 말은 못 해도 대충 두리뭉실하게 설명은 할 수 있을 것 같다. 하지만 면접장에서는 다르다.
면접관의 질문에 명확하게 대답을 해야 한다라고 생각하는 바 포스팅하게 되었다. 서론이 너무 길었으니 바로 본론으로 들어가자!
객체 지향 프로그래밍(OOP : Object Oriented Programming)
객체 지향 프로그래밍이라는 숲을 보기 전에 객체라는 나무를 먼저 보도록 하자.
객체는 클래스(class)가 실제로 구현된 인스턴스(instance)를 말한다. 즉, 객체란 클래스를 인스턴스화 한 것이다.
흔히 클래스를 말할 때 붕어빵을 만드는 틀이라고 하고 인스턴스를 붕어빵이라고 설명을 한다.
그럼 클래스와 인스턴스가 무엇이냐?
클래스는 새로운 객체를 만들기 위한 템플릿을 말한다. 변수와 메서드를 자신의 멤버로 가지고 있다.
인스턴스는 클래스에 소속된 개별적인 객체를 말한다. 즉, 템플릿이 실제 구현된 것이다.
이것을 가지고 객체 지향 프로그래밍에 대해 다음과 같이 설명할 수 있을 것 같다.
여러 프로그램(기능)들을 '객체'라는 기본 단위로 쪼개서 구현하고, 이러한 객체들의 상호작용으로 프로그래밍하는 방식
어느 정도 객체 지향 프로그래밍이 무엇인지 틀이 잡힌 것 같다. 그러면 객체 지향 프로그래밍의 장점과 단점, 특징을 알아보자.
장점
- 코드 재사용이 쉽다. → 남이 만든 클래스를 가져다가 이용할 수 있고, 상속을 통해 확장해서 사용할 수 있다.
- 유지보수가 쉽다. → 보통 객체를 클래스 단위로 생성하기 때문에 클래스 내부 변수 또는 함수를 수정하면 기능 변경이 가능하다.
- 프로젝트가 클수록 개발에 용이하다. → 객체 단위로 모듈화 시켜서 개발하기 때문에 여러 명이 각자의 기능을 개발한 뒤 하나로 합쳐서 사용하기 편하기 때문이다.
모듈화 : 거대한 문제를 작은 조각의 문제로 나누어 다루기 쉽도록 하는 과정이다.
(https://appleceo.github.io/2019/06/09/ModuleAndModularization/)
단점
- 처리 속도가 절차적 프로그래밍보다 느리다.
- 객체가 많으면 용량이 커질 수 있다.
- 설계 시 많은 시간과 노력이 필요하다.
객체 지향 프로그래밍의 특징
- 캡슐화
- 상속
- 다형성
- 추상화
캡슐화(Encapsulation)
- 데이터와 코드의 형태를 외부로부터 알 수 없게 하고, 데이터의 구조와 기능, 역할을 하나의 캡슐 형태로 만드는 방법이다.
- 캡슐화의 주요 목적은 변수를 private로 선언하여 데이터를 보호하고, 그 변수를 수정자를 통해서만 접근할 수 있도록 하는 것이다.
- 외부에서 오용으로 인해 객체가 손상되거나 변형되는 것을 막기 위해 사용한다.
상속(Inheritance)
- 상위 클래스에서 기능을 가져와 재사용할 수 있으며 동시에 하위 클래스에서 새로운 기능을 추가할 수 있다.
- 부모의 유전자를 자식이 물려받는 것으로 이해하면 상속에 대해 쉽게 이해할 수 있다.
- 코드의 중복을 없애기 위해 사용하며, Java에서는 다중 상속을 허용하지 않는다.
다형성(Polymorphism)
- 다형성은 상속과 연관 있는 개념으로 볼 수 있다.
- 같은 부모님 밑에서 태어나도 형제, 자매들끼리 서로 다른 성격을 지니는 것으로 이해하면 조금은 다가가기 쉽다.
- 다형성의 예로 Overloading과 Overriding이 있다. ( Overloading과 Overriding 자세한 설명 보기 )
추상화(Abstraction)
- 추상화는 객체의 공통적인 속성과 기능을 추출하여 정의하는 것이다.
- 객체들은 실제 그 모습이지만, 클래스는 객체들이 어떤 특징을 가지고 있어야 한다고 정의하는 추상화된 개념이다.
- 그러므로 추상화는 객체들의 공통된 특징을 파악해 정의해놓은 설계 기법이라고 할 수 있다.
SOLID 원칙 ( 객체 지향 프로그래밍의 원칙)
- SRP
- OCP
- LSP
- ISP
- DIP
SRP(단일 책임 원칙, Single Responsibility)
- 하나의 모듈은 하나의 책임만 가져야 하며, 모듈이 변경되는 이유도 한 가지 여야 한다.
- 단일 책임 원칙이 지켜지면 변경해야 할 때, 수정할 대상이 명확해진다.
OCP(개방 폐쇄 원칙, Open Closed)
- 확장에 대해서는 열려있어야 하지만, 변경에 대해서는 닫혀있어야 한다.
- 이 원칙을 무시하면 객체 지향 프로그래밍의 장점을 잃게 된다. 그러므로 반드시 지켜야 하는 원칙이다.
- 보통 인터페이스를 의미하는데, 인터페이스를 만들어 이를 클래스가 구현하고, 객체를 통해 함수를 호출한다.
LSP(리스코프 치환 원칙, Liskov Substitution)
- 상위 타입이 하위 타입으로 변경되어도 상위 타입을 통해 서브 클래스를 사용할 수 있어야 한다.
- 즉, 이 원칙을 준수한다는 것은 자식 클래스가 부모 클래스를 대신해서 사용될 수 있다는 것이다.
ISP(인터페이스 분리 원칙, Interface Segregation)
- 각 역할에 맞게 인터페이스로 분리하는 것이다.
- 결론적으로 단일 책임 원칙과 인터페이스 분리 원칙은 같은 문제에 대한 다른 해결법으로 볼 수 있다. 하지만 특별한 경우를 제외하면 단일 책임 원칙이 더 좋은 해결법이다.
DIP(의존 역전 원칙, Dependency Inversion)
- 구체화에 의존하지 않고 추상화에 의존한다.
- 자신보다 변하기 쉬운 것에 의존하던 것을 변하기 어려운 것에 의존하게 해야 한다.
SOLID 원칙을 보고 알 수 있듯이 핵심은 추상화라는 것이다. 구체화가 아닌 추상화에 의존하면서 우리는 유연하고 확장 가능한 애플리케이션을 만들도록 하자 !
※ 도움을 주신 분들
https://maivve.tistory.com/211
https://jeong-pro.tistory.com/95
https://steady-coding.tistory.com/446
'Language > Java' 카테고리의 다른 글
[Java]스트림(stream)(2/3) (0) | 2022.06.07 |
---|---|
[Java]스트림(stream)(1/3) (0) | 2022.06.07 |
[Java] 람다식 (0) | 2022.06.06 |
예외처리(Exception Handling) (0) | 2022.05.27 |
Java는 어떻게 동작하지?( + 메모리 영역) (0) | 2022.05.23 |