📦
객체 지향 프로그래밍 (OOP, Object-Oriented Programming)
February 21, 2023
🧠 Why?
객체 지향 프로그래밍이 왜 필요할까?
- 객체 지향 프로그램 이전의 패러다임을 살펴보면 먼저 순차적(비구조적) 프로그래밍과 절차적(구조적)프로그래밍이 있다.
순차적(비구조적) 프로그래밍
- 순차적으로 흘러가는 프로그래밍 구조를 의미
- 순차를 중점으로 보는 코드
- 코드의 흐름, 순서에 기반하는 프로그래밍
비구조적 프로그래밍에서는 주로 goto문을 활용 따라서 규모가 커질수록 goto문이 범람하게 되어 알아보기 어려운 코드가 만들어진다. ->
코드의 중복을 피하기 위해
코드를 단위화할 방법을 모색
절차적(구조적) 프로그래밍
- 절차적 프로그래밍에서의 절차란, 우리가 평소에 알고있는 절차가 아닌 프로시저를 의미한다.
프로시저란? 반환값(리턴)이 존재하지 않는 함수를 의미
- 프로시저의 사용으로 goto문이 범람했던 순차적 프로그래밍과 달리 반복 가능성이 있는 부분을 프로시저로 쪼개고 각각의 프로시저안에서 중복되는 부분은 반복문으로 구성
- 하지만 이런 프로시저는 추상적이라는 문제점을 가지고 있다.
예시
📚 도서관리 프로그램 도서관리 프로그램을 구현하기 위해선 책이라는 자료형과 이것을 사용할 함수가 필요할 것이다. 구조적 프로그래밍에선 책 자료형과 이것을 사용하는 함수가 물리적으로 같은 곳에 기록될 순 있지만(모듈) 논리적으로는(개념) 함께 할 수 없는 구조이다. 따라서 이를 묶기 위한 새로운 패러다임이 필요
⭐️ 이처럼 특정한 개념의 함수와 자료형을 한번에 묶기 위한 패러다임이 바로 객체지향 프로그래밍이다.
객체 지향 프로그래밍이란?
- 프로그래밍에서 필요한 데이터를 추상화시켜 상태와 행위를 가진 객체로 만들고, 객체들간의 상호작용을 통해 로직을 구성하는 프로그래밍 방법
- 객체 내부에 자료형(필드)과 함수(메서드)가 함께 존재
📦 객체란?
값을 저장할 변수와 작업을 수행할 메소드를 서로 연관된 것들끼리 묶어서 만든 것 레고를 구성하는 레고 조각이라고 생각하면 이해하기 쉽다 !
객체 지향 프로그래밍의 특징
1. 추상화 (Abstraction)
- 객체에서 공통된 속성과 행위 추출
- 공통의 속성과 행위를 찾아서 타입을 정의하는 과정
- 불필요한 정보는 숨기고 중요한 정보만 표현 -> 프로그램을 간단하게 만듦
예시 아우디, BMW, 벤츠는 모두 ‘자동차’라는 공통점이 있다. 이 때, ‘자동차’라는 추상화 집합을 만들어 자동차들이 가진 공통적인 특징들을 만들어 활용
2. 캡슐화 (Encapsulation)
- 변수와 함수를 하나로 묶는 것
- 낮은 결합도를 유지할 수 있도록 설계하는 것
낮은 결합도란?
한 곳에서 변화가 일어나도 다른 곳에 미치는 영향을 최소화 시키는 것을 의미
정보은닉의 활용
외부에서 접근할 필요가 없는 것들은 private으로 접근하지 못하도록 제한
3. 상속 (Inheritance)
- 클래스의 속성과 행위를 하위 클래스에 물려주거나 하위 클래스가 상위 클래스의 속성과 행위를 물려받는 것
- 새로운 클래스가 기존의 클래스의 데이터와 연산을 이용할 수 있게 하는 기능
일반화 관계 (Generalization)
라고도 하며, 여러 개체들이 지닌 공통된 특성을 부각시켜 하나의 개념이나 법칙으로 성립하는 과정
상속 재사용의 단점
- 상위 클래스 (부모 클래스)의 변경이 어려워진다.
- 불필요한 클래스가 증가할 수 있다.
- 상속이 잘못 사용될 수 있다.
4. 다형성 (Polymorphism)
- 하나의 변수명, 함수명이 상황에 따라 다른 의미로 해석될 수 있는 것
- 서로 다른 클래스의 객체가 같은 메세지를 받았을 때 각자의 방식으로 동작하는 능력
부모 클래스의 메소드를 자식 클래스가 오버라이딩해서 자신의 역할에 맞게 활용하는 것
객체 지향 설계 원칙 (SOLID)
1. 단일 책임 원칙 (SRP, Single Responsibility)
- 하나의 클래스는 단 한 개의 책임을 가져야 한다.
- 클래스를 변경하는 이유는 단 한개여야 한다.
2. 개방-폐쇄 원칙 (OCP, Open-Closed)
- 확장에는 열려 있어야 하고, 변경에는 닫혀 있어야 한다.
- 기능을 변경하거나 확장할 수 있으면서, 그 기능을 사용하는 코드는 수정하지 않는다.
3. 리스코프 치환 원칙 (LSP, Liskov Substitution)
- 상위 타입의 객체를 하위 타입의 객체로 치환해도, 상위 타입을 사용하는 프로그램은 정상적으로 동작해야 한다.
4. 인터페이스 분리 원칙 (ISP, Interface Segregaiton)
- 인터페이스는 그 인터페이스를 사용하는 클라이언트를 기준으로 분리해야 한다.
- 각 클라이언트가 사용하지 않는 인터페이스에 변경이 발생하더라도 영향을 받지 않도록 만들어야 한다.
5. 의존 역전 원칙 (DIP, Dependa)
- 고수준 모듈은 저수준 모듈의 구현에 의존해서는 안된다.
- 저수준 모듈이 고수준 모듈에서 정의한 추상 타입에 의존해야 한다.
- 저수준 모듈이 변경되어도 고수준 모듈은 변경할 필요가 없다.