객체 지향 프로그래밍
OOP, Object Oriented Programming
웹 개발을 할 때 필요한 수많은 프로그래밍 언어 중 JAVA를 공부하는 이유 하나만 말하자면, JAVA는 객체를 지향하는 언어라 사용하기 쉽고 편리하기 때문.
객체 지향이 무엇인지 알아보자면 그 반대인 절차지향 언어와 비교해서 알아보자.
절차 지향 프로그래밍이란? (Procedural Programming)
대표적으로 C언어가 절차지향 언어로 프로그램의 데이터를 처리하는 방법인 알고리즘을 중요시하며 순차적으로 실행하는 구조를 가진다. 이는 컴퓨터의 작업 처리 방식과 유사하기 때문에 객체 지향 언어를 사용하는 것에 비해 더 빨리 처리되어 시간적으로 유리하다. 옛날에는 하드웨어와 소프트웨어의 개발 속도 차이가 크지 않았다. 하지만 소프트웨어 언어의 발달과 컴파일러의 발달로 하드웨어가 소프트웨어의 발달을 따라오지 못하는 상황이 발생했다. 이는 객체 지향 언어가 등장하게 되는 계기로 작용했다. 객체 지향 프로그래밍은 개발하려는 것을 기능별로 묶어 모듈화 함으로써 하드웨어가 같은 기능을 중복으로 연산하지 않도록 하고, 모듈을 재활용하기 때문에 하드웨어의 처리량을 획기적으로 줄여주었다.
장점
- 컴퓨터의 처리구조와 유사해 실행속도가 빠르다.
- 완성된 코드의 실행처리 속도가 빠르다.
단점
- 유지보수가 어렵다.
- 실행 순서가 정해져 있으므로 코드의 순서가 바뀌면 동일한 결과값을 도출하기 어렵다.
- 디버깅이 어렵다.
- 대형 프로젝트에는 부적합하다.
객체 지향 프로그래밍이란? (Object Oriented Programming)
객체지향의 정의를 살펴보면 객체지향이란 실제 세계를 모델링하여 소프트웨어를 개발하는 방법이다. 객체 지향 프로그래밍에서는 데이터와 절차를 하나의 덩어리로 묶어서 생각하게 된다. 이는 마치 컴퓨터 부품을 하나씩 사다가 컴퓨터를 조립하는 것과 같은 방법이다.
장점
- 코드의 재활용성이 높다.
- 코딩이 절차지향보다 간편하다.
- 디버깅이 쉽다.
단점
- 처리속도가 절차지향보다 느리다.
(객체지향은 객체와 클래스를 사용하여 각 모듈의 높은 독립성을 권장한다. 그래서 여러 클래스를 상속해서 사용해 중복코드를 최소화하고, 유지보수 확장성을 높인다. 이로 인해 실행 속도가 느리다.) - 설계에 많은 시간소요가 들어간다.
OOP의 핵심은 객체(Object)와 클래스(Class)라고 할 수 있다.
객체와 클래스 Object and Class
객체는 클래스의 인스턴스이다. 각각의 객체는 상태, 행동 그리고 식별자를 갖고 있다. 또한 객체들은 서로간의 호출을 통해 통신할 수 있으며 이를 message passing이라고 한다.
하나의 클래스를 통해 필요로 하는 어플리케이션에 여러 개의 객체를 생성할 수 있다. 각 객체의 식별은 일반적으로 JVM에 의해 유지되며 JAVA 객체를 만들 때마다 JVM은 객체에 대한 해시코드를 만들고 할당하게 된다. 이를 통해 JVM은 모든 객체가 고유하게 식별되도록 한다.
생성자 Constructor
생성자는 반환 값이 없는 특수한 메소드이다. 생성자의 이름은 항상 클래스의 이름과 동일하며 초기 객체 상태를 설정하기 위한 매개 변수를 사용할 수도 있다. 생성자를 작성하지 않는 경우 JVM은 기본 생성자를 할당하며 이는 매개변수를 허용하지 않기 때문에 매개변수가 필요한 경우에는 개발자가 직접 생성자를 작성해야 한다.
OOP의 4가지 특징
1. 추상화(Abstraction)
추상화는 context와 관련이 없는 정보를 숨기거나 관련된 정보만 알 수 있도록 하는 것이다.
일반적인 추상화는 데이터 추상화와 제어 추상화로 볼 수 있는데 데이터 추상화는 복잡한 데이터 형태를 생성하기 위해 여러 작은 데이터 타입을 사용하는 방법을 의미한다.
제어 추상화는 어떤 클래스의 메소드를 사용하는 사용자에게 해당 메소드의 작동방식과 같은 로직을 숨기기 위함이다. 만일 메소드 내 로직이 변경된더라도 실제 사용자는 변경된 내용이 어떤 것인지 알 필요 없이 이전과 동일하게 메소드를 사용할 수 있다. 따라서 로직이 변경되더라도 사용자에게 영향을 주지 않는다.
2. 캡슐화(Encapsulation)
캡슐화는 관련이 있는 변수와 함수를 하나의 클래스로 묶고 외부에서 쉽게 접근하지 못하도록 은닉하는 것이다. 객체의 직접적인 접근을 막고 외부에서 내부의 정보에 직접 접근하거나 변경할 수 없고 객체가 제공하는 필드와 메소드를 통해서만 접근이 가능하다. 캡슐화는 정보은닉과 구현은닉을 모두 갖고 있다.
정보은닉의 방법으로는 접근 제한자를 사용하여 외부에서 접근할 수 없도록 하며 인터페이스를 통해 구현은닉을 달성하는 것이다. 구현은닉은 객체가 책임을 이행하는 방식을 수정할 수 있도록 개발자에게 자유를 제공한다. 이는 설계가 변경 될 때 유용하게 작용할 수 있다.
JS 에서는 현재 class 내부 변수 앞에 #을 붙여, private하게 이용하고 있다. (메소드는 불가)
JAVA 에서는 접근 제한자를 사용한다. (private, public, protected, default)
- public : 모든 접근을 허용
- protected : 같은 패키지에 있는 객체와 상속관계의 객체만 허용
- default : 같은 패키지에 있는 객체만 허용
- private : 현재 객체 내에서만 허용
3. 상속(Inheritance)
JAVA에서의 상속은 하나의 클래스가 부모클래스의 속성과 행동을 얻게 되는 방법이다.
상속은 코드의 재사용성과 유지보수를 위해 사용된다. 상속을 사용하기 위해서는 extends 키워드를 상속 받을 클래스에 명시하여 사용할 수 있습니다. 상속되는 클래스는 superclass라 부르고 새롭게 생성된 클래스를 subclass라 한다.
subclass는 superclass의 non-private 맴버들을 상속 받게되며 생성자는 맴버가 아니기 때문에 상속되지 않는다. 하지만 subclass에서 superclass의 생성자를 호출할 수 있다.
단점
- 상위 클래스 변경이 어렵다. (상위 클래스에 의존성이 높다.)
- 클래스의 불필요한 증가
- 상속의 오용
> 객체 조립으로 해결, 재사용의 관점이 아니라 기능 확장의 관점에서 상속
4. 다형성(Polymorphism)
다형성은 같은 자료형에 여러가지 객체를 대입하여 다양한 결과를 얻어내는 성질을 의미한다. 이를 통해 동일한 이름의 같은 여러 형태의 메소드를 만들 수 있다.
JAVA에서는 다형성을 다루는 근본적인 방법 2가지가 있는데 compile time polymorphism과 runtime polymorphism 이다.
compile time polymorphism은 컴파일러가 필요한 모든 정보를 가지고 있고 프로그램 컴파일 중에 호출할 방법을 알기 때문에 컴파일 시간에 적절한 메소드를 각각의 객체에 바인딩할 수 있다. 정적바인딩(static binding)이나 early binding이라고도 불린다. JAVA에서는 메소드 오버로딩(method overloading)을 통해 사용된다. 메소드 오버로딩을 통해 메소드의 매개변수의 형태가 달라질 수 있다. (반환타입은 달라도 되지만, 매개변수가 같으면 성립X)
runtime polymorphism은 동적바인딩(dynamic binding)이라고 불리며 메소드 오버라이딩(method overriding)과 연관이 있다. 일반적으로 런타임 다형성은 부모 클래스와 자식 클래스가 존재할 때 사용되는데 부모자식 클래스에 존재하는 메소드를 실행시키게 되면 런타임과정에서 해당 인스턴스에 맞는 메소드를 호출하게 된다.
Reference
1. HowToDoInJava - Java Object Oriented Programming
2. Zin0's님의 개발 기록 공간 - 객체지향 프로그래밍 (OOP)
'JAVA' 카테고리의 다른 글
[JAVA] Exception in thread "main" java.lang.ArithmeticException: / by zero (2) | 2022.03.09 |
---|---|
JAVA - 반복문 (for문) (0) | 2022.02.05 |
JAVA - 배열 (Array) (2) | 2022.01.31 |
JAVA - 스캐너 클래스 (Scanner Class) (0) | 2022.01.26 |
JAVA - 변수(Variable) (0) | 2021.12.15 |