OOP는 무엇일까?
객체지향 프로그래밍 (OOP)
--
OOP는
말 그대로 "객체" 지향적인 프로그래밍을 의미하는데
이는 프로그램을 "객체(Object)"의 집합으로 보는 방식이다.
즉, 각 객체들이 서로 상호작용하는 구조로 동작을 수행하게 된다.
간단하게 설명하자면
전체적으로 수행할 동작들 중에서 각 역할에 알맞게 "객체(클래스)"를 여러 공간에 분리하고
프로그램을 동작할 때는 특정 동작에 필요한 객체들을 원하는 순서대로 불러다가 동작시켜
프로그램의 동작을 완수하는 것이다.
즉, 각 역할(동작)을 수행할 모듈들을 먼저 설계한 다음
해당 모듈들을 가지고 실행할 흐름을 짜서 동작시키는 방식이다.
비유를 하자면
각각의 도구와 재료(인스턴스 변수)를 가지고 자신이 맡은 역할(메서드)만 수행하는 여러 요리사(객체)가 존재한다.
요리(프로그램)를 완성하기 위해 필요한 역할을 수행하는 여러 요리사(객체)들을 불러 순차적으로 요리를 수행하여
완성하는 것이 객체 지향이다.
장단점
- 코드 재사용성이 높음
- 코딩 과정이 편함
- 모델링이 편함
- 설계에 시간이 상대적으로 많이 소모
- 상대적으로 처리 속도가 느림
--
절차지향과 객체지향의 차이
--
절차지향 (Procedural Programming)은
함수의 연속적인 호출로 이루어진 작업 흐름인 방식으로
위에서 아래로 순차적으로 차근차근 동작을 수행한다.
먼저 각 역할을 수행하는 모듈을 설계하고 원하는 동작을 골라 수행하는 "객체지향"과 달리
먼저 실행에 대한 흐름을 설계하고 나서 필요한 동작(함수)들을 설계하여 수행하는 방식이다.
장단점
- 코드가 단순하여 이해하기 쉬움
- 컴퓨터의 처리구조와 비슷하여 속도가 빠름
- 실행 순서가 정해져 있어 순서 변경시 동일한 결과를 보장하기 힘듦
- 유지보수가 어려움
절차지향에서 각 역할을 수행하는 메서드를 분리하여 원하는 메서드를 가져다가 수행하는 것이
객체지향에서 원하는 객체를 가져다가 수행하는 것과 비슷해 보이는데 무슨 차이일까?
가장 큰 차이는
메서드는 동작을 수행 후 해당 결과 값을 반환해야 하고 이를 따로 다른 곳에서 저장하고 있어야 하지만
객체에는 메서드뿐만 아니라 변수(인스턴스 변수)도 존재하여 자기가 필요한 값은 스스로 관리할 수 있다.
즉, 절차지향에서는 데이터와 동작이 분리되어 있지만,
객체지향에서는 데이터와 동작이 함께 존재하여 관리한다.
그래서 객체지향에서는
동작을 수행하는 메서드에서 필요한 데이터를 객체 자신이 가지고 있어서
다른 데이터를 따로 전달받지 않고 객체 자체만으로 동작을 수행할 수 있다는 것이 핵심이다.
물론 객체도 외부의 데이터를 받아 수행하는 메서드가 존재할 수 있지만
기본적으로 필요한 데이터는 본인이 관리하고 있으며
특정 작업을 할 때 외부에서 추가적인 데이터를 받아 처리하는 방식으로
객체지향의 유연성과 협력성을 보여주는 부분이다.
--
OOP의 핵심 개념
--
캡슐화 (Encapsulation)
객체가 독립적인 역할을 수행할 수 있도록 "데이터"와 "메서드"를 하나로 묶어서 관리하는 것을 의미한다.
그리고 해당 객체의 외부에서는 접근할 수 없도록 제한하여 해당 객체의 정보를 은닉할 수 있다.
캡슐화를 통해
외부에서 객체의 데이터에 직접 접근하지 못하고 제공된 메서드를 통해서만 접근하도록 하여
데이터의 무결성을 유지하고 보안을 강화하는 역할을 수행한다.
예시 코드
class 고객 {
private int 보유금액; // 외부에서 직접 접근 불가
public 고객(int 보유금액) {
this.보유금액 = 보유금액;
}
public int get보유금액() { // getter 메서드를 통해 접근
return 보유금액;
}
public void set보유금액(int 금액) { // setter 메서드로 값 변경
if (금액 >= 0) { // 조건을 걸어 무결성 유지
보유금액 = 금액;
} else {
System.out.println("유효하지 않은 금액입니다.");
}
}
}
public class Main {
public static void main(String[] args) {
고객 customer = new 고객(1000);
System.out.println("현재 보유 금액: " + customer.get보유금액());
customer.set보유금액(500); // 보유 금액을 변경
System.out.println("변경된 보유 금액: " + customer.get보유금액());
customer.set보유금액(-200); // 유효하지 않은 금액
}
}
상속 (Inheritance)
부모 클래스의 속성(데이터)과 메서드를 자식 클래스가 물려받는 개념으로
이를 통해 코드의 재사용성을 높이고, 기존 기능에서 확장하거나 수정을 하여 새로운 클래스로 사용한다.
예시 코드
class 자판기 {
int 보유금액 = 10000;
public void 제품구매(int 금액) {
보유금액 += 금액;
System.out.println("자판기 보유 금액: " + 보유금액);
}
}
class 음료자판기 extends 자판기 { // 자판기 클래스를 상속(재사용)하여 새로운 클래스 생성
String[] 제품목록 = {"콜라", "사이다", "커피"};
public void 제품목록출력() {
System.out.println("음료 목록:");
for (String 제품 : 제품목록) {
System.out.println(제품);
}
}
}
public class Main {
public static void main(String[] args) {
음료자판기 vendingMachine = new 음료자판기();
vendingMachine.제품목록출력();
vendingMachine.제품구매(1000); // 상속받은 자판기의 메서드 사용
}
}
다형성 (Polymorphism)
같은 이름의 메서드가 서로 다른 객체에서 다르게 동작하는 개념으로
"오버로딩", "오버라이딩" 두 가지 형태로 나타낼 수 있다.
- 오버로딩 : 하나의 클래스에 같은 이름의 메서드를 매개변수나 반환 타입 등을 다르게 하여 구현
- 오버라이딩 : 부모 클래스로부터 상속받은 메서드를 자식 클래스에서 재정의
예시 코드
class 자판기 {
public void 제품구매() {
System.out.println("기본 제품 구매 메서드입니다.");
}
public void 테스트() {
System.out.println("테스트 1");
}
public void 테스트(int a) { // 테스트() 메서드의 오버로딩
System.out.println("테스트 1");
}
}
class 음료자판기 extends 자판기 {
@Override
public void 제품구매() { // 부모 메서드 오버라이딩
System.out.println("음료를 구매합니다.");
}
}
public class Main {
public static void main(String[] args) {
자판기 vendingMachine = new 음료자판기(); // 다형성
vendingMachine.제품구매(); // 자식 클래스의 메서드 호출
}
}
추상화 (Abstraction)
불필요한 세부 사항(정보)을 핵심적인 기능의 틀만 외부에 제공하는 개념으로
이를 통해 복잡한 시스템을 단순화하여 중요한 정보만을 노출시키고, 세부적인 구현은 감춘다.
즉, 메서드의 구현부까지 완성하지 않고 선언만 하여 틀만 잡아놓는 것을 추상화라고 하며
인터페이스나 추상 클래스를 사용하여 필수적인 기능만 정의하고,
해당 구현은 나중에 세부적으로 처리할 수 있도록 하는 개념이다.
추상화와 추상 메서드는 다른 개념으로
추상 메서드는 추상화를 구현하는 여러 방법 중에서 하나일 뿐이다.
예시 코드
abstract class 자판기 {
public abstract void 제품목록출력(); // 추상 메서드 (구현 X)
public abstract void 제품구매(String 제품, int 금액);
}
class 음료자판기 extends 자판기 {
@Override
public void 제품목록출력() {
System.out.println("음료 목록: 콜라, 사이다, 커피");
}
@Override
public void 제품구매(String 제품, int 금액) {
System.out.println(제품 + "을(를) " + 금액 + "원에 구매했습니다.");
}
}
public class Main {
public static void main(String[] args) {
자판기 vendingMachine = new 음료자판기();
vendingMachine.제품목록출력();
vendingMachine.제품구매("콜라", 1000);
}
}
--
'Terminology' 카테고리의 다른 글
의존성 주입 (DI, Dependency Injection) (+ IoC, DIP) (0) | 2024.10.27 |
---|---|
SOLID 원칙 ( 객체 지향 설계 원칙) (1) | 2024.10.26 |
CI / CD 파이프라인 (0) | 2024.07.05 |
DevOps (Development Operations) 란? (0) | 2024.07.04 |
네트워크란? (feat. IP, 네트워크 인터페이스, 포트, NAT, 포트포워딩, DNS) (0) | 2024.06.23 |