이것이 점프 투 공작소

OOP(객체 지향 프로그래밍)에 대해 쉽게 알아보자! 본문

객체지향

OOP(객체 지향 프로그래밍)에 대해 쉽게 알아보자!

겅겅겅 2024. 8. 22. 21:30

OOP(object-oriented programming)란?

OOP란 '현실 세계에 가까운 방식으로 프로그램을 만드는 프로그래밍 방법론'입니다.

OOP를 통해 현실 세계의 개념들을, 프로그램 내에서 '객체'로 바라보며
객체들간의 상호작용을 통해 프로그램이 동작하도록 합니다.

이러한 객체들의 상호작용을 '협력'이라고 하며,
각 객체들은 '협력'안에서 '메세지'를 보내 서로 소통하면서 자신의 '역할'을 '책임'을 가지고 수행해야합니다.

OOP방식으로 프로그램을 설계하면 유지보수와 확장에 유리한 프로그램을 만들 수 있습니다.

 

OOP의 철학 (협력, 역할, 책임 그리고 메세지)

앞서 OOP를 설명하며 중요한 키워드들을 따옴표 안에 넣어서 언급하였습니다.
키워드의 의미를 보다 쉽게 이해하기 위하여 현실 세계의 상황 커피주문을 예시로 간단한 OOP설계를 해보려고합니다.

'커피 주문'을 위해 일어나야하는 일들을 순서대로 정리하면 아래와 같습니다.

1. 손님은 메뉴를 바리스타에게 주문한다.
2. 바리스타는 손님에게 주문받은 메뉴에 맞는 커피를 제조한다.
3. 바리스타는 완성된 커피를 손님에게 전달한다.

커피를 주문하는 프로그램을 OOP방식으로 설계한다면 프로그램의 최종 목적 커피 주문은 '협력'을 의미허며
‘손님’, ‘커피’, '바리스타' 등은 각각의 객체로 정의합니다.
각 객체들은 커피 주문이라는 공통의 협력 안에서 각각 손님, 커피, 바리스타 등 고유한 '역할'과 '책임'부여받습니다.

객체들은 서로 '메세지'를 통해 상호작용하며 프로그램의 목적인 커피 주문이 성공하도록 '협력'해야합니다.
위의 '커피주문 프로그램'에 대한 객체들간의 협력 구조를 OOP적 관점에서 설명하면 아래와 같습니다.

손님객체는 바리스타객체에게 커피를 만들어달라는 요청(request)을 메시지를 통해 전달합니다.
이때 메세지를 보내는 손님객체는 송신자(sender)가 되고 메세지를 받는 바리스타객체는 수신자(receiver)가 됩니다.

요청(request)를 받은 바리스타객체는 요청에 응답할 '책임'이 있기에 스스로 요청을 처리해야합니다.
이때 객체가 요청을 처리하는 방법을 메서드(method)라고 합니다.

바리스타객체는 커피를 만들기 위해 커피객체에 요청(request)을 메세지를 통해 전달합니다.
객체는 스스로 자신의 상태를 결정해야 하기에, 커피객체는 바리스타객체에게 요청을 받고 스스로 만들어집니다. (OOP의 객체는 완전히 현실세계의 개념과 동일 할 수는 없습니다)

커피객체가 만들어졌다면 바리스타객체에게 요청(request)에 대한 응답을 보내고, 응답을 받은 바리스타객체는 손님객체에게 응답을 보냄으로서 협력이 마무리됩니다.

OOP의 요소 

OOP에서는 캡슐화, 추상화, 상속, 다형성 크게 4가지 특징이 있습니다.

캡슐화(Encapsulation)

'손님이 커피를 주문했을때 손님은 바리스타가 커피를 만드는 과정을 알 수 없다'

 

바리스타가 커피를 만드는 과정은 바리스타의 역할이자 책임이기에 손님이 그 과정에 관여 할 수 없습니다.

캡슐화는 구현에 대한 메서드를 외부에서 확인하지 못하도록 은닉하는 행위를 말합니다.

 



캡슐화를 통해 외부에게 원하는 인터페이스 부분만 노출 할 수 있고, 구현을 은닉함으로서 스스로 자신의 상태를 하며 자율적인 객체를 구현 할 수 있습니다.
자율적인 책임을 가진 객채들이 협력함으로서 객체끼리의 협력을 단순하게 만들 수 있습니다.
또한 구현이 은닉되어 있으므로 구현이 변경되어도 외부 객체에 영향을 끼치지 않아 유지보수가 용이합니다.

자바에서는 접근 제어자 public, default, protected, private를 통해 외부 객체에 대핸 접근범위를 제한 할 수 있습니다.

추상화 (Abstraction)

'손님이 느낄때는 1급 바리스타와 2급 바리스타 모두 그냥 내게 커피를 만들어주는 바리스타일 뿐이다'

 

커피를 주문하는 손님은 바리스타의 실력에 관계 없이 커피를 주는 바리스타로만 보여집니다.

1급 바리스타와 2급 바리스타는 두 객체는 '바리스타'라는 하나의 형태로 손님에게 추상화 되어 보여집니다.


추상화란 객체의 공통적인 속성과 기능을 추출하여 정의하는 것을 의미합니다.


여러 프로그래밍 언어들은 현실세계의 개념을 어플리케이션의 type으로 정의합니다.

문자들을 string type, 숫자들을 int 타입으로 규정하듯이 현실세계의 개념은 어플리케이션 안에서 객체들은 '행동'을 기준으로 하여 각각의 type으로서 정의됩니다.

 

객체들이 가진 내부의 타입들과 값들이 다르더라도 동일한 '행동'을 한다면 동일한 type으로 정의 할 수 있고 이는 동일한 '책임'을 가지고 있다는걸 의미합니다.

 

추가로 OOP관점에서 Type은 크게 두가지로 나눌 수 있습니다.

슈퍼타입과 서브타입 

어떤 타입이 다른 타입보다 일반적이라면 슈퍼타입, 특수하다면 서브타입이라고 하며, "일반화와 특수화"라고 이야기하기도 합니다.

특정 타입이 다른 타입의 서브타입이 되기 위해서는 'Is-a 규칙'을 준수해야합니다.

 

ls-a 규칙이란 흔히 말하는 일반화 관계입니다.

 

"아메리카노는 커피다." 라는 명제를 예시로 들면

아메리카노는 커피의 부분집합이고 커피는 음료의 부분집합입니다.

 

아메리카노 입장에서는 아메리타노는 커피의 서브타입이고, 커피는 슈퍼타입이 됩니다.

커피의 입장에서는 커피는 서브타입이고, 음료가 슈퍼타입이 됩니다.

물론 아메리카노는 음료의 서브타입이기도 합니다. 

 

이렇든 슈퍼타입과 서브타입의 관계는 "SubType is SuperType" 이라는 조건을 만족시켜야 합니다.

 

추상화를 함으로서 우리는 수신을 받는 객체에 대해 다형성을 줄 수 있고, 추상화된 객체에 메세지를 보냄으로서 유연한 협력을 만들 수 있습니다.

 

자바에서는 추상클래스(abstract)와 인터페이스(interface)를 통해 추상화를 구현 할 수 있습니다.

상속 (Inheritance)

'1급 바리스타와 2급 바리스타는 동일한 바리스타 자격증을 취득하였으며 커피를 만들 수 있는 기술이 있다'

 

두 바리스타는 동일하게 커피를 만들 수 있는 방법(method)를 알고있습니다.

 

일반화와 특수화를 객체로 구현하기 가장 좋은 방법은 상속입니다.

크게 인터페이스 상속(interface inheritiance)과 서브클래싱 구현 상속(implemantaion inheritiance)  두가지가 있습니다.

각각 서브타이핑과 서브클래싱이라고도 합니다.

 

인터페이스 상속은 설계의 유연성을 위해 사용되며

서브클래싱 구현 상속은 주로 코드의 중복제거와 재사용성을 높히기 위해 사용됩니다.

인터페이스 상속과 서브클래싱 구현 상속을 구분하기 위해서는 클라이언트 관점에서 상속과 관련된 객체들이 어떻게 사용되고 있는지 확인해야 합니다.

 

추가로 서브타입이 슈퍼타입을 대체 할 수 있는 경우에는 인터페이스 상속을 대체 할 수 없는 경우에는 서브클래싱 구현 상속이 주로 사용됩니다.

 

상속을 받은 어떤 객체가 이해할 수 없는 메시지가 있다면 자신의 상위 클래스에게 책임을 위임(delegration) 합니다.

만약 위임을 받은 클래스도 이해 할 수 없다면 상속의 최상위 클래스까지 그 요청을 계속해서 위임하게됩니다.

 

상속을 적절히 사용하면 코드의 중복제거와 재사용성을 높히며 설계의 유연성 또한 늘어납니다.

자바에서는 implements와 extand키워드를 사용해 각각 서브타이핑과 서브클래싱을 구현 할 수 있습니다.

다형성 (Polymorphism)

'"아메리카노를 만들어 줘" 라는 요청을 받은 1급 바리스타와 2급 바리스타는 각각 다른 방법으로 커피를 만들 수 있다'

 

두 바리스타는 동일한 커피를 만들어달라는 요청에 대해 자율적으로 행동해서 응답 할 수 있습니다.


서로 다른 유형의 객체가 동일한 메시지에 대해 서로 다르게 반응하는 것을 말합니다.
서로 다른 타입의 객체들이 동일한 메시지를 수신 할 경우 서로 다른 메서드를 이용해 메서드를 처리 할 수 있다는 의미입니다.

다형성을 통해 협력이 수행되는 방식(메시지)을 재사용하기 쉬워지며, 협력이 수행되는 방식을 확장 할 수 있습니다.
송신자는 수신자가 메시지를 이해 할 수 있다면 누구라도 관계없이 요청을 보내고 응답 받을 수 있기에 협력이 유연해질 수 있습니다.

자바에서는 오버라이딩(Overriding), 오버로딩(Overloading)을 통해 다형성을 구현합니다.