본문 바로가기
JAVA/자바기초

[JAVA] 객체지향 프로그래밍

by DeveloperJW 2023. 1. 18.

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

  • 자바는 대표적인 객체지향 프로그래밍 언어이다.
  • 실제 세계를 객체라는 단위로 나누고 객체들간의 상호작용을 의미한다.
  • 즉, 프로그램을 여러개의 독립된 단위인 객체들의 모임으로 파악하고자 하는 것이다.

 

객체란?

  • 객체(Object)는 우리 주변에 있는 모든 것이 될 수 있다.
  • 예를 들어 TV, 컴퓨터, 책, 건물, 의자, 사람 등 모두 객체가 될 수 있다.
  • 객체는 자신만의 고유한 특성과 행동을 가지며 다른 객체들에게 행동을 요청하거나 정보를 주고 받는 등 상호작용을 하면서 존재한다.
  • 객체지향 프로그래밍에서 객체는 크게 속성(필드, field)과 동작(메소드, method)으로 구성되어 있다.                                     ex) 학생이라는 객체의 속성 : 이름, 학년, 학번                                                                                                                                                      동작 : 공부하기, 밥먹기, 놀기

객체지향 프로그래밍 특징

캡슐화(Encapsulation)

 

  • 캡슐화란 관련된 필드와 메소드를 하나로 묶고 실제 구현내용을 외부로부터 감추는 기법으로 정보은닉할 수 있다.
  • 외부에서는 공개된 메소드를 통해 접근할 수 있다.
  • 캡슐약을 생각해보면 이해하기 쉬운데, 캡슐에 든 약은 어떤 성분인지 언떤 색인지 보이지 않으며 외부의 접근으로부터 안전한 상태와 같습니다.

 

 

상속(Inheritance)

 

  • 상속이란 상위클래스의 모든걸 하위 클래스가 이어 받는 것이다.
  • 즉, 이미 작성된 클래스(상위클래스)의 특성을 그대로 이어받아 새로운 클래스(하위클래스)를 생성하는 기법이다.
  • 상속이 필요한 이유는 코드의 중복을 없애기 위함입니다. 코드의 중복이 많아지면 개발단계와 유지보수에서 많은 비용이 소요되기 때문에 코드 중복은 피하는 것이 좋습니다.

 

 

추상화(Abstraction)

 

  • 추상화는 객체에서 공통된 속성과 행위를 추출하는 기법이다.
  • 다시 말해 실제 존재하는 객체들을 프로그램으로 만들기 위해 공통적인 특성을 파악하고 불필요한 특성을 제거하는 과정을 말한다.

 

 

다형성(Polymorphism)

 

  • 사전적 의미로는 다양한 형태로 나타날 수 있는 능력을 의미한다.
  • 다형성은 같은 이름의 메소드를 호출하더라도 객체에 따라 다르게 동작하는 것을 말한다.
  • 상위클래스의 동작을 하위클래스에서 다시 정의하여(오버라이딩, Overriding)하는 것 또한 다형성으로 볼 수 있다.
  • 하나의 클래스 내에서 이름은 같지만 서로 다르게 동작하는 메소드를 여러개 만드는 오버로딩(Overloading) 또한 다형성의 사례로 볼 수 있다.

 

 

  • 예를 들어 강아지, 고양이, 병아리 클래스는 Animal 클래스를 상속받아 소리내기(speak())라는 메소드를 호출하지만 자신의 특징에 맞게 다시 구현하여 사용된다.

 

객체지향 프로그래밍 설계 원칙

  • 단일 책임 원칙 (SRP, Single Responsibility Principle)
  • 개방 폐쇄 원칙 (OCP, Open Closed Principle)
  • 리스코프 치환 원칙 (LSP, Liskov Substitution Principle)
  • 인터페이스 분리 원칙 (ISP, Interface Segregation Principle)
  • 의존관계 역전 원칙 (DIP, Dependency Inversion Principle)

1. 단일 책임 원칙 (SRP, Single Responsibility Principle)

하나의 클래스는 하나의 책임만 가져야 한다.

  • 좋은 객체 지향 설계를 위해서는 기본적으로 하나의 클래스에는 수행할 수 있는 하나의 책임(기능)을 가져야 한다.
  • 하나의 클래스가 책임이 많아지면(=기능이 많아지면) 클래스 내부의 함수끼리 강한 결합력을 가지게 되므로 책임을 분리시킬 필요가 있다.
  • 프로그램의 변경이 요구되는 경우 파급 효과가 적으면 단일 책임 원칙을 잘 따른 것이다.

2. 개방 폐쇄 원칙 (OCP, Open Closed Principle)

소프트웨어 요소는 확장에는 열려 있으나 변경에는 닫혀 있어야 한다.

  • 프로그램을 설계할 때 기존의 코드는 변경되지 않으면서 기능을 추가할 수 있도록 설계해야 한다.
  • 이는 설계의 기본 원칙이라고 할 수 있는데, 프로그램 중 변경이 자주 필요한 부분은 쉽게 수정하여 변경할 수 있도록 하고, 반대로 변경이 필요하지 않은 부분은 다른 것의 영향을 받지 못하도록 해야 한다는 것이다.
  • 개방 폐쇄 원칙은 다형성을 활용하면 만족할 수 있는데, 기본적으로 클래스에 구현되어 있는 기능을 변경해서 적용해야 하는 경우 바로 인터페이스를 구현한 새로운 클래스를 하나 만들어 분리시킨 다음 해당 기능을 재정의하여 설계하면 되는 것이다.
  • 즉, 인터페이스를 구현한 새로운 클래스를 만드는 것은 기존의 코드를 변경하지 않고 기능은 확장시키는 것이 되므로 좋은 객체 지향 설계를 할 수 있다.

3. 리스코프 치환 원칙 (LSP, Liskov Substitution Principle)

프로그램의 객체는 프로그램의 정확성을 깨뜨리지 않으면서 하위 타입의 인스턴스로 바꿀 수 있어야 한다.

  • 다형성에서 하위 클래스(자식 클래스)는 상위 클래스(부모 클래스)의 기능을 모두 수행할 수 있어야 한다.
  • 즉, 객체 지향 프로그래밍에서 부모 클래스의 인스턴스 대신 자식 클래스의 인스턴스를 사용해도 전혀 문제가 없어햐 한다는 것을 의미한다.
  • 이는 단순히 컴파일에 성공하는 것을 넘어 부모 클래스와 자식 클래스 사이의 행위에는 일관성이 있어야 한다는 원칙이다.

4. 인터페이스 분리 원칙 (ISP, Interface Segregation Principle)

하나의 일반적인 인터페이스보다 여러 개의 구체적인 인터페이스가 낫다.

  • 특정 클라이언트는 자신이 이용하지 않는 기능에는 영향을 받지 않도록 하므로 역할에 맞게 인터페이스를 분리 시켜야 한다.
  • 하나의 인터페이스에는 최소한의 메소드를 구현하는 것이 좋다.
  • 즉, 최소한의 기능을 제공하며 하나의 역할에만 집중하라는 의미이다.

  • 예를 들어 행위라는 이름을 가진 클래스 하나가 존재한다고 해보자. 행위 클래스 안에는 요리 하기(), 개발 하기() 등 여러 개의 메소드가 가 있다. 이때 요리사와 개발자라는 2개의 클라이언트가 있다고 했을 때 요리사는 요리 하기()의 기능은 필요하지만 개발 하기()의 기능은 필요하지 않다.
  • 즉, 클라이언트 각자 역할에 맞는 기능만이 필요하다.
  • 이때 ISP 원칙을 적용하여 행위 클래스의 기능을 여러 개의 인터페이스로 분리시켜 하나의 역할에만 집중하도록 한다면 훨씬 명확한 인터페이스 설계가 가능해진다.

5. 의존관계 역전 원칙 (DIP, Dependency Inversion Principle)

의존 관계를 맺을 때 자신보다 변화하기 쉬운 것에 의존하지 않아야 한다.

  • 추상 클래스 또는 상위 클래스는 변화 하기 쉬운 하위 클래스에 의존하면 안 되고, 모두 추상화에 의존해야 한다.
  • 즉, 구현 클래스에 의존하지 말고 인터페이스에 의존하라는 뜻이다.
  • 상위 클래스일수록 변하지 않을 가능성이 높으므로 하위 클래스의 변화에 영향을 받지 않아야 한다.

댓글