1. 객체지향 프로그래밍이란?
1) 정의
프로그램을 단순히 데이터와 처리방법으로 나누는 것이 아니라, 수많은 객체라는 기본 단위들로 나누고 이들의 상호작용으로 서술하는 것을 지향하는 방식입니다.(즉, 프로그래밍의 방향성을 단순 데이터와 처리방식의 집합이 아닌, 객체들의 상호작용에 두는 관점입니다.) 여기서 객체란 하나의 역할을 수행하는 속성과 메소드의 묶음입니다. 물리적인 사물 혹은 추상적인 개념도 객체가 될 수 있습니다.
*왜 지향인가?
프로그래밍을 모두 객체로 바라보는 것이 좋을 수도 있지만 나쁠 수도 있습니다. 왜냐하면 프로그래밍은 실제 세계와 완벽히 같지 않아서 객체로 표현이 안될 수도 있기 때문이입니다. 이에 '지향'이라는 단어를 사용합니다.
2) 장단점?
장점
- 코드 유지 보수 및 확장이 쉽다.
- 코드 재사용이 용이하다.
- 사람이 많은 대형 프로젝트에 적합하다.
단점
- 설계 시 많은 노력이 요구됩니다. 현실세계와 컴퓨터 세계는 완전히 닮아 있지 않아 객체와 그들의 상호작용을 정의하기 어렵기 떄문입니다.
- 절차지향에 비해 실행속도가 느리며, 필요한 메모리 양이 많습니다. 이는 모든 것을 객체로 생각하기 때문에 추가적인 포인터 메모리가 들어가고 자바의 경우에는 클래스 내용 자체가 메모리를 소모하기 때문입니다.
2. 4대원칙
1) 추상화
정의: 공통된 속성과 메소드를 묶어 이름을 붙이는 것을 추상화라고 합니다. 객체지향적 관점에서 클래스를 정의하는 것이 추상화를 정의하는 것이라고 할 수 있습니다.
예시: A 고등학교 학생과 B 고등학교 학생이 있고 이들로 객체를 만들려고 한다고 하자. 이때 고등학교 학생 혹은 학생으로 공통된 특성을 묶는다면, 고등학교 학생 혹은 학생으로 추상화된다고 말할 수 있다.
장점: 의견 주시면 감사하겠습니다.
단점: 의견 주시면 감사하겠습니다.
2) 캡슐화
정의: 연관된 데이터와 기능을 하나로 묶고, 불필요한 요소를 외부에 노출되지 않도록 설계하는 방식.
장점
- 객체의 오남용을 막을 수 있습니다.
How?: 현실 세계의 물리를 구현하는 객체가 있다고 합시다. 해당 객체의 중력 가속도 값은 고정되야겠죠? 누군가가 해당 속성에 접근하여 수정하게 하면 안됩니다. 중력 가속도 값은 Read-only여야겠죠
- 객체의 내부 구현 방법과 속성이 바뀌어도 다른 객체의 구현에 영향이 없습니다.
How?: 물품.GetPrice()라는 호출이 있다고 생각해보죠. 여기서 사용자는 GetPrice()를 호출하면 되구나만 알면 됩니다. 함수 안에 얼마만큼의 세일이 들어갔는지 등을 알 필요가 없죠.
- 사용자 객체가 캡슐화된 객체의 내부 동작 원리를 모르기 때문에 객체간 결합도가 낮아집니다.
Why?: 장점 2번을 다른 방식으로 바라본 해석입니다. 객체가 다른 객체를 실행하기 위해 데이터를 2개 아는 것과 1개 아는 것중 어느게 객체간 결합도가 낮을까요? 당연히 적을 수록 좋습니다. 이렇듯 캡슐화는 객체간 결합도를 낮게 만듭니다.
단점
- 과도한 캡슐화는 확장성에 안좋은 영향을 끼칩니다.
Why?: 예를들어 게임 물리를 관리하는 객체가 있다고 해보죠. 게임 물리는 현실과 달리 중력이 꼭 9.81이 될 필요가 없습니다. 이때 중력에 대한 수정을 막아버리면 또 다른 물리 관리 클래스를 만들어야하는 단점이 존재합니다. 객체지향적 설계를 할 때는 항상 변경에는 보수적이고 확장에는 열려있어야합니다.
3) 상속
정의: 서브 클래스가 슈퍼 클래스의 속성과 메소드를 물려 받는 기능.
예시: 상의, 하의, 모자 객체를 만들려고 한다고 생각해보죠. 객체지향적 관점에서 클래스를 정의하는 것이 추상화니까 공통된 속성과 개념을 살펴보면, 우리는 '옷'이라는 클래스를 만들 수 있습니다. 옷은 천의 속성을 가지고 입을 수 있죠. 상의, 하의와 모자 또한 공통된 속성과 개념을 가집니다.
장점
- 코드의 재활용성
- 유지보수의 편의
단점
- 과도한 상속은 캡슐화를 깨뜨려 유지보수 및 확장성을 저해한다.
How?: Lotto 클래스가 있고(속성으로 List<int>를 가진다), LottoBonus 클래스가 Lotto 클래스를 상속 받았다고 생각하자. 이때 Lotto 관련 요구사항이 바뀌어 List<int>가 int[]과 되야된다고 가정하자. 그렇다면 LottoBonus 클래스의 구현 또한 바뀌어야한다. 만약 상속이 4-5중으로 되어있으면 일이 무수히 많아진다. 이렇듯 과도한 상속은 클래스간 결합도를 높여 캡슐화를 깨뜨린다. 이러한 상속의 문제점은 조합으로 해결할 수도 있다.
(참조: https://tecoble.techcourse.co.kr/post/2020-05-18-inheritance-vs-composition/)
- 다중상속은 다이아몬드 문제를 만든다. 자바나 C#과 같은 언어는 해당 문제가 해결되었지만, C++과 같은 언어는 여전히 다이아몬드 문제가 존재한다.
4) 다형성
정의: '프로그램 언어 각 요소들이 다양한 자료형(type)에 속하는 것'이 허가된 성질. 자바에서는 부모타입의 레퍼런스로 자식타입 객체를 참조할수 있게 하여 이를 구현합니다. 또한 오버라이딩, 오버로딩 방법을 지원하여 다형성을 가집니다.
* 가끔 상속이 다형성의 필수 요소라고 하는 글들이 있지만, 이는 옳지 해석이 아니라고 생각합니다. 다형성은 '프로그램 언어 각 요소'가 대상입니다. 함수가 될 수도 있고 객체가 될 수도 있습니다. 함수가 되면 오버라이딩, 오버로딩이 다형성의 특징을 보이죠. 객체는 상속을 통한 구현 말고도 인터페이스의 구현 또한 다형성을 구현하는 방법입니다.
예시: 옷 클래스의 서브 클래스인 하의 클래스 타입인 객체는 하의 클래스 레퍼런스 변수로도 참조가 가능하고 옷 클래스 래퍼런스 변수로도 참조가 가능합니다.
장점
- 유지 보수가 쉬워집니다.
Why?: 다양한 객체들을 하나의 자료형으로 관리할 수 있기 때문입니다. 예를들어 상의, 하의, 모자 클래스의 인스턴스들을 List<옷>에 넣어 관리할 수 있습니다.
- 확장이 용이해집니다.
How?: 생성자 및 메소드 오버로딩은 메소드가 다양한 매개변수를 가질 수 있게합니다. 또한 상속에서의 오버라이딩은 슈퍼 클래스의 기능을 서브 클래스가 확장할 수 있게 돕습니다.
단점
- 디버깅이 어렵습니다. 객체를 눈으로 추적하기 어렵기 때문이죠. 하지만 이는 다향성이 객체간 결합을 줄이기 때문에 나오는 Trade-off라고 생각합니다.
'Computer launguage > Java' 카테고리의 다른 글
자바 NIO (1) 채널, 버퍼의 동작 과정을 간단한 채팅 서버/클라 애플리케이션 구현을 통해 리서치 (0) | 2024.09.01 |
---|---|
제한된 메모리 크기 환경에서의 LinkedList와 HashMap 튜닝 방법 (0) | 2022.07.03 |
[Deep dive] 부동 소수점, 고정 소수점 표현 방법? 연산 속도? 오차? 돈 계산? (0) | 2022.03.26 |
[Deep Dive] Garbage Collector(GC) 구조? 동작 과정? SE7, 8 차이? (0) | 2022.03.11 |
[Deep dive] JVM 구조? 자바 애플리케이션 실행 과정? 컴파일 과정? (2) | 2022.03.05 |