객체 지향 프로그래밍이란?
Date:
객체 지향 프로그래밍(Object Oriented Programming)
OOP란?
- 컴퓨터 프로그래밍 패러다임 중 하나로, 프로그래밍에서 필요한 데이터를 추상화시켜 상태와 행위를 가진 객체를 만들고 그 객체들 간의 유기적인 상호작용을 통해 로직을 구성하는 프로그래밍 방법
- 가장 중요한 점은 객체 내부에 자료형(필드)과 함수(메소드)가 같이 존재한다는 점
- 모든 물리적, 논리적 요소를 객체로 만드려는 것
- 과거 순차적(sequential programming)/비구조적 프로그래밍(non-structured programming),절차적(Procedural Programming),구조적(Structured Programming) 패러다임들의 단점을 보완하기 위해서 탄생한 패러다임이다.
- 프로그램의 규모가 점점 커지고 사용자들의 요구가 빠르게 변화해가는 상황에서 절차적 언어로는 한계를 느껴서 탄생하게 됨.
순차적 프로그래밍은 구조라는 개념이 없고 goto문을 남발하게 되어 규모가 조금이라도 커지게 되면 개발 생산성이 엄청 떨어진다.
절차적 프로그래밍의 절차(Procedual)은 함수와 유사한데 반환값이 없다.
구조적 프로그래밍은 모듈을 기준으로 나눈다 (둘이 비슷하게 취급되기도한다)
프로시저나 모듈이 추상적인 단위이기 때문에 묶여져 있어야 할 자료형들과 함수들이 논리적으로 함께 할 수 없는 구조이다.
객체지향의 장점
- 코드 재사용이 용이
이미 만들어진 클래스를 가져와서 이용할 수 있고 상속을 통해서 확장하여 사용이 가능하다.
새로운 코드를 작성할 때 기존의 코드를 이용하여 쉽게 작성할 수 있다.
- 유지보수가 쉬움
절차 지향 프로그래밍에서는 코드를 수정해야할 때 일일이 찾아 수정해야하는 반면 객체 지향 프로그래밍에서는 수정해야 할 부분이 클래스 내부에 멤버 변수 혹은 메소드로 있기 때문에 해당 부분만 수정하면 됨 또한 디버깅이 쉽다.
코드 간의 관계를 이용해서 적은 노력으로 쉽게 코드를 변경할 수 있다.
- 대형 프로젝트에 적합
클래스단위로 모듈화시켜서 개발할 수 있으므로 대형 프로젝트처럼 여러명, 여러회사에서 개발이 필요할 시 업무 분담하기가 쉽다
- 신뢰성이 높은 프로그래밍이 가능 제어자와 메서드를 이용해서 데이터를 보호하고 올바른 값을 유지하도록 하며, 코드의 중복을 제거하여 코드의 불일치로 인한 오동작을 방지할 수 있다.
객체 지향의 단점
- 처리속도가 상대적으로 느림
- 객체가 많으면 용량이 커질 수 있음
- 설계시 많은 시간과 노력이 필요
객체 간의 정보 교환이 모두 메시지 교환을 통해 일어나므로 실행 시스템에 많은 overhead 가 발생하게 된다.
하지만 이것은 하드웨어의 발전으로 많은 부분 보완되었다.
객체 지향 프로그래밍의 치명적인 단점은 함수형 프로그래밍 패러다임의 등장 배경을 통해서 알 수 있다.
바로 객체가 상태를 갖는다는 것이다.
변수가 존재하고 이 변수를 통해 객체가 예측할 수 없는 상태를 갖게 되어 애플리케이션 내부에서 버그를 발생시킨다는 것이다.
이러한 이유로 함수형 패러다임이 주목받고 있다.
반면 절차 지향 프로그래밍의 단점은
- 유지보수가 어렵다
- 프로그램을 분석하기 어렵다
- 대형프로젝트에는 부적합하다
- 추가적인 요구사항에 대응이 어렵다
- 재사용이 어렵다
절차지향은 데이터를 중심으로 함수를 구현
절차지향은 데이터와 함수를 별개로 취급
객체지향은 기능을 중심으로 메서드를 구현
절차지향은 데이터를 중심으로 순차적 실행에 초점
객체지향 프로그래밍도 절차적으로 실행되나(반대개념이 아님)
객체간의 관계와 기능에 초점을 두고 코드를 작성한다.
클래스
어떤 문제를 해결하기 위한 데이터를 만들기 위해,
추상화를 거쳐서 집단에 속하는 ‘속성(attribute)’과 ‘행위(behavior)’를 변수와 메서드로 정의한 것
(행위 대신 연산이라고도 한다)
인스턴스(객체) : 클래스에서 정의한 것을 토대로 실제 메모리상에 할당된 것으로 실제 프로그램에서 사용되는 데이터
추상화
불필요한 정보는 숨기고 중요한 정보만을 표현함으로써 공통의 속성이나 기능을 묶어 이름을 붙이는 것
필요로 하는 속성이나 행동을 추출하는 작업
캡슐화
데이터(속성)와 데이터를 처리하는 함수를 하나로 묶는 것
캡슐화된 객체들은 재사용이 용이
캡슐화된 객체는 인터페이스를 제외한 세부 내용이 은폐(정보 은닉)되어 외부에서의 접근이 제한적이기 때문에 외부 모듈의 변경으로 인한 파급 효과가 적음
객체들 간의 메시지를 주고받을 때 상대 객체의 세부 내용은 알 필요가 없으므로 인터페이스가 단순해짐
낮은 결합도를 유지할 수 있도록 설계하는 것
한 곳에서 변화가 일어나도 다른 곳에 미치는 영향을 최소화 시키는 것
(객체가 내부적으로 기능을 어떻게 구현하는지 감추는 것)
결합도(coupling)란, 어떤 기능을 실행할 때 다른 클래스나 모듈에 얼마나 의존적인가를 나타내는 말
독립적으로 만들어진 객체들 간의 의존도가 최대한 낮게 만드는 것이 중요하다.
(객체들 간의 의존도가 높아지면 굳이 객체 지향으로 설계하는 의미가 없어진다)
객체 안의 모듈 간의 요소가 밀접한 관련이 있는 것으로 구성하여 응집도를 높이고 결합도를 줄여야 요구사항 변경에 대처하는 좋은 설계 방법
정보 은닉(외부에서 접근할 필요가 없는 것은 private으로 선언)을 사용
상속
상속은 이미 정의된 상위 클래스의 모든 속성과 연산을 하위 클래스가 물려 받는 것
상속을 이용하면 하위 클래스는 상위 클래스의 모든 속성과 연산을 자신의 클래스 내에서 다시 정의하지 않고서도 즉시 자신의 속성으로 사용할 수 있다.
하위 클래스는 상위 클래스로부터 상속받은 속성과 연산 외에 새로운 속성과 연산을 첨가하여 사용할 수 있다.
상위 클래스의 속성과 연산을 하위 클래스가 사용할 수 있기 때문에 객체와 클래스의 재사용, 즉 소프트웨어의 재사용(Reuse)을 높이는 중요한 개념이다.
기능의 일부분을 변경해야 할 경우 상속받은 자식클래스에서 해당 기능만 다시 수정하여 사용할 수 있게 한다.
절차 지향에서도 라이브러리를 통해서 소스코드를 가져와 사용할 수 있었으나 내 의도에 맞게 수정하게 되면 다른 라이브러리가 되어 버전에 따라 동작하지 않을 수 있고, 불필요한 코드의 수정작업을 해야한다
다중상속은 쓰지 않는다. (필요에 따라 인터페이스를 활용한다.)
다중상속은 클래스 계층을 복잡하게 만들어 상속 순서 추적이 어렵고, 상위 클래스의 변경이 하위 클래스에 의도하지 않은 영향을 미칠 수도 있다.
다중 상속을 허용하지 않는 PL도 있음(ex 자바). 되도록 지양하되 쓰더라도 신중히 써야함
상속은 일반화 관계라고도 하며, 여러 개체들이 지닌 공통된 특성을 부각시켜 하나의 개념이나 법칙으로 성립하는 과정이다.
상속(일반화)는 또 다른 캡슐화이다.
자식 클래스를 외부로부터 은닉하는 캡슐화의 일종이다.
이처럼 자식 클래스를 캡슐화해두면, 외부에선 이러한 클래스들에 영향을 받지 않고 개발을 이어갈 수 있는 장점이 있다.
상속 재사용의 단점
상속을 통한 재사용을 할 때 나타나는 단점도 존재한다.
- 상위 클래스(부모 클래스)의 변경이 어려워진다.
부모 클래스에 의존하는 자식 클래스가 많을 때, 부모 클래스의 변경이 필요하다면?
이를 의존하는 자식 클래스들이 영향을 받게 된다. - 불필요한 클래스가 증가할 수 있다.
유사기능 확장시, 필요 이상의 불필요한 클래스를 만들어야 하는 상황이 발생할 수 있다. - 상속이 잘못 사용될 수 있다.
같은 종류가 아닌 클래스의 구현을 재사용하기 위해 상속을 받게 되면, 문제가 발생할 수 있다.
상속 받는 클래스가 부모 클래스와 IS-A 관계가 아닐 때 이에 해당한다.
해결책은?
객체 조립(Composition), 컴포지션이라고 부르기도 한다.
객체 조립은, 필드에서 다른 객체를 참조하는 방식으로 구현된다.
상속에 비해 비교적 런타임 구조가 복잡해지고, 구현이 어려운 단점이 존재하지만 변경 시 유연함을 확보하는데 장점이 매우 크다.
따라서 같은 종류가 아닌 클래스를 상속하고 싶을 때는 객체 조립을 우선적으로 적용하는 것이 좋다.
그럼 상속은 언제 사용?
- IS-A 관계가 성립할 때
- 재사용 관점이 아닌, 기능의 확장 관점일 때
다형성
오버라이딩, 오버로딩
서로 다른 클래스의 객체가 같은 메시지를 받았을 때 각자의 방식(방법,특성)으로 동작/응답하는 능력이다.
객체 지향의 핵심과도 같은 부분이다.
다형성은, 상속과 함께 활용할 때 큰 힘을 발휘한다.
즉, 부모 클래스의 메소드를 자식 클래스가 오버라이딩해서 자신의 역할에 맞게 활용하는 것이 다형성이다
객체들은 동일한 메소드명을 사용하며 같은 의미의 응답을 한다.
Getter, setter 사용하는 이유
멤버변수에 직접 접근하지 못하게 private으로 접근지정자를 설정하고 public으로 getter, setter 만드는 이유는
메서드를 통해서 접근하기 때문에 메서드 안에서 올바르지 않은 입력에 대해 사전에 처리할 수 있게 제한하거나 조절할 수 있기 때문이다.
예를 들면 setter는 유효범위를 넘은 정수가 들어왔을 때 처리를 하고 나서 set하거나 예외처리를 한다.
Getter도 마찬가지로 자료에 무언가 더하거나 빼고 줄 수 있다.
댓글