[Java] 객체 지향 프로그래밍이란?

hyunoi·2024년 11월 11일
0

Java

목록 보기
5/20
post-thumbnail

객체?


우선 객체 지향 프로그래밍에 대해 알기 전에 객체가 무엇인지에 대해 알아보자
사실 아직도 객체를 설명하라고 하면 명확하게 설명을 잘 하지 못한다... ㅎㅎ
이번 기회에 제대로 알아보자

객체의 본래 의미는 본인이 다른 실체를 바라볼 때, 그 실체가 객체가 되는 것이다.
우리가 보고 느낄 수 있는 모든 것을 객체라고 하는 것이다.

객체는 속성(State)행위(Behave)를 가진 실체이다.

  • 속성
    객체가 스스로를 나타낼 수 있는 특징
  • 행위
    객체가 할 수 있는 행동, 역량, 기능

예시를 들어보자면,
사람의 얼굴(객체)는 눈(객체) + 코(객체) + 입(객체), 이렇게 각각의 객체로 이루어져 있다.
객체가 모여 객체가 되는 것


상태와 행위의 경우 이렇게 나눌 수 있다.

속성과 행위는 프로그래밍에서 다른 언어로도 불리는데
속성은 변수, 행위는 메소드가 된다

객체 지향 프로그래밍(OOP, Object-Oriented Programming)


객체 지향 프로그래밍은 프로그래밍 패러다임 중 하나로 상태와 행위로 이루어진 객체를 이용하여 서비스를 설계, 개발하는 것이다.
즉, 객체를 만들어서 개발하는 것이다.

프로그램을 유연하고 변경을 쉽게(컴퓨터 부품을 갈아 끼우듯이 컴포넌트를 변경 가능) 만들기 때문에 대규모 소프트웨어 개발에 많이 사용된다.

객체 지향 프로그래밍에는 네 가지 특징이 있다.

  • 추상화
  • 캡슐화
  • 상속성
  • 다형성

이에 대해 알아보자.

추상화

객체들의 공통적인 특징(기능, 속성)들을 뽑아내서 정의하는 것
공통적인 부분이 있는 객체를 각각 하나씩 만드는 것은 비효율적이다.

공통적인 부분이 있는 것은 하나로 묶어서 재활용이 가능하도록 하고, 세부적으로 다른 것은 추가를 하면 되는 것

자동차, 오토바이는 모두 '탈 것'이고, 모두 시동 걸기, 전진, 후진 등을 할 수 있다는 기능적 공통점이 존재한다.

'탈 것'을 추상화로 구현했으면 이후에는 다른 코드를 건들지 않고 추가할 부분만 만들어주면 된다.
얘를 현대 차로 만들지 기아 차로 만들지,,,

캡슐화

관련 있는 변수와 함수, 데이터들을 하나의 클래스로 묶고 이를 외부에서 쉽게 접근하지 못하도록 은닉하는 것

캡슐화를 사용하는 것에는 크게 두 가지 이유가 있다.

  • 데이터 보호
    외부에서 쓸데 없이 객체를 손상 시키는 것을 방지하기 위함이다. 이전에 알아보았던 접근 제한자를 이용하여 구현이 가능하다.
  • 데이터 은닉
    내부의 동작을 감추고 외부에는 필요한 것만 보여준다. getter/setter를 이용하여 구현이 가능하다.

공통적으로 각 객체 고유의 독립성과 책임 영역을 안전하게 지키고자 하는 것이 목적이다.

getter/setter

public class Car {
	private String name;
    
    public String getName() {
    	return name;
    }
    
    public void setName() {
    	this.name = name;
    }
}

이런 식으로 속성인 name은 private로 설정이 되어 있고, getter/setter 메소드만 public으로 접근이 열려 있다. 그래서 외부에서는 getter/setter만으로 name 설정이 가능하다.

상속성

이미 정의된 상태인 상위 클래스(부모 클래스)의 모든 속성과 연산을 하위 클래스(자식 클래스)가 사용할 수 있는 것

기존에 있던 코드를 재활용하는 것이기 때문에 반복적인 코드를 최소화하고 공유하는 속성과 기능에 간편하게 접근을 할 수 있다.

공통적인 기능인 start, moveForward, moveBackward는 추상화하여 vehicle 부모 클래스로 정의를 한 뒤에, 각각의 자동차, 오토바이 자식 클래스에서는 본인의 특성에 맞춘 필요한 기능들을 정의를 해준다.

이렇게 해서 이미 vehicle 클래스에 정의되어 있는 메소드를 재활용하기 때문에 코드 재사용성을 줄일 수 있고, 코드 변경이 필요한 경우 자식 클래스에서 여러번 수정하는 것이 아니고 부모 클래스에서만 수정하면 된다.

다형성

어떤 객체의 속성이나 기능이 상황에 따라 여러 가지 형태를 가질 수 있는 것
맥락에 따라 다른 기능을 수행할 수 있어야 한다

  • 메서드 오버라이딩
    같은 매개변수와 이름의 메소드를 각각의 클래스의 상황에 맞게 재정의하여 사용을 할 수 있다.
    즉, 같은 이름의 메소드가 상황에 따라 다른 역할을 수행하는 것
  • 메서드 오버로딩
    하나의 클래스 안에서 동일한 이름의 메소드를 매개변수를 다르게 하여 여러 개 중복 정의하여 사용할 수 있다.

객체 지향이란 무엇인가?
위 글에 다형성 부분에 굉장히 설명이 잘 되어 있다.
이 글을 정리해보자면,

  • 인터페이스를 사용하지 않으면 객체 간의 결합도가 높아진다.
    - 결합도가 높아지면 객체 지향적 설계를 하는데 매우 불리하다.
    - 주체만 다르고 동일한 상황이 많아진다면 코드가 굉장히 많아질 것
    - 클래스가 변경되어야 하는 상황에서도 코드 변경이 많아진다.
  • 인터페이스를 사용한 클래스는 더이상 각각의 클래스 내부의 변경이나 다른 객체가 새롭게 교체되는 것을 생각하지 않아도 된다.
  • 인터페이스에만 의존하여 수정이 있을 때마다 코드 변경을 안해도 된다.

SOLID

SRP 단일 책임 원칙 (Single responsibility principle)

하나의 클래스는 하나의 책임만 가지기
변경을 기준으로 한다. 변경이 있을 때 파급 효과가 적으면 잘 적용한 것

OCP 개방-폐쇄 원칙 (Open/closed principle)

소프트웨어 요소는 확장에는 열려 있으나 변경에는 닫혀 있어야 함
기능 구현 요청이 온다면, 클래스 확장을 통해 쉽게 구현하면서 확장에 따른 클래스 수정은 최소화 해야 한다.
추상화 개념을 사용하여 관계 구축을 하는 것

LSP 리스코프 치환 원칙 (Liskov substitution principle)

어떠한 인터페이스 규약이 있으면 무조건 지켜야 한다.
기능적으로 보장을 해줘야 하는 것
예를 들어, 자동차 인터페이스에서 엑셀 기능이 있다면 이것은 무조건 앞으로만 가능한 기능이어야 하는 것
뒤로 간다면? LSP에 위배되는 것이다.

ISP 인터페이스 분리 원칙 (Interface segregation principle)

특정 클라이언트를 위한 특정 인터페이스를 따로 만드는 것이 여러 개가 합쳐진 범용 인터페이스보다 좋다.
범용 인터페이스의 경우 안의 상세한 기능을 바꾸더라도 수정해야 할 게 많아지는 반면, 특정 인터페이스의 경우 해당 기능만 바꾸면 된다.
기능을 적당한 크기에 맞게 적당히 쪼개는 것이 중요하다.

DIP 의존관계 역전 원칙 (Dependency inversion principle)

구현 클래스에 의존하지 말고, 인터페이스에 의존해야 한다.
서비스는 레포지토리 인터페이스만 바라봐야 한다! 다른 레포지토리를 알고 있으면 안된다.
역할에 집중해야 한다. 구현은 신경 안 쓰기.
시스템을 언제든지 갈아 끼울 수 있게 해야 나중에 변경이 쉬워진다.

0개의 댓글