22.04.15 자바와 객체지향

Seunghan·2022년 4월 15일
0

Java

목록 보기
5/6

프로그래밍 언어는 이해하기 어려운 기계어, 어셈블리어 자바까지 개발자르 더욱 편하고 이롭게 하기 위해 발전되어 왔다. 또한 0과 1에 대변되는 기계에 맞춰 사고하던 방식 절차적/구조적 프로그래밍을 거쳐 현실 세계처럼 프로그래밍 할 수 없을까라는 고민 속에 객체 지향의 개념이 탄생했다.

객체지향에 대해서 알아보자!

객체의 특징

  • 각각은 고유하다.
  • 객체는 속성을 갖는다.
  • 객체는 행위를 한다.

객체 지향의 4대 특성

클래스와 객체의 관계

객체 : 세상에 존재하는 유일무이한 사물

클래스 : 분류, 집합. 같은 속성과 기능을 가진 객체를 총칭하는 개념

객체(Object) = 클래스(Class)의 인스턴스

추상화(Abstraction) : 모델링

그럼 왜 객체지향에서 추상화가 필요할까?

추상의 사전적 의미 : 여러가지 사물이나 개념에서 공통되는 특성이나 속성 따위를 추출하여 파악하는 작용

사람 클래스

속성(Properties) : 시력, 몸무게, 혈액형, 키, 나이, 직업, 연봉 ...

행위(Method) : 먹다(), 자다(), 일하다(), 운전하다(), 입금하다(), 출금하다(), 이체하다() ...

개발자는 어플리케이션을 개발할 때 클래스를 설계하는데 과연 이 모든 특성이 필요할까?

예를 들어 병원 어플리케이션을 개발한다고 하면 사람의 직업과 연봉이라는 속성은 필요가 없을 것이다.

또한 게임 어플리케이션을 제작한다고 하면 운전하다(), 먹다(), 자다()라는 행위는 필요 없을 것이다.

🍔 개발자에게 추상화란 구체적인 것을 분해해서 관심 영역(어플리케이션 경계, Application Boundary)에 있는 특성만 가지고 재조합, 모델링 하는 것이라고 할 수 있다.

개발자는 추상화를 통해 객체 지향에서 클래스를 설계하고 데이터베이스의 테이블을 설계한다.

객체가 생성되는 과정(Mouse 예제)

Mouse mouse = new Mouse

  1. main 메서드가 시행 되기 전 static 영역에 Mouse 클래스가 등록됩니다.
  2. main 메서드가 실행되면서 main() 스택 프레임이 실행되고, Mouse mouse 를 통해 Mouse 객체에 대한 참조 변수가 만들어집니다.
  3. new Mouse()를 통해 Mouse 클래스의 인스턴스를 힙에 생성합니다.
  4. 새로 생성된 Mouse 객체에 대한 주소(포인터)를 참조 변수 mouse에 할당합니다.
  5. 이후 객체가 더 이상 사용(참조)되지 않는다면 가비지 컬렉터에 의해 수거됩니다.

클래스 멤버(Static 멤버) VS 객체 멤버(Instance 멤버)

클래스 멤버 : 모든 객체가 같은 값을 가질 때 사용 (ex mouse의 꼬리의 수, 자동차의 바퀴 개수)

객체 멤버 : 객체마다 다른 값을 가질 때 사용(ex 사람의 나이)

상속(Inheritance, kind) : 재사용 + 확장

객체 지향에서의 상속 이란?

상위 클래스의 특성을 하위 클래스에서 상속(특성 상속)하고 거기에 필요한 특성을 추가, 즉 확장해서 사용할 수 있다는 의미

그러므로 일반적인 상속(Inheritence) 부모-자식이 아닌 확장(Extends) 이 더 정확한 표현

또한 자바 언어의 아버지 제임스 고슬링은 inheritence(상속)이라는 키워드 대신 extends(확장)을 씀으로써 상속이 아닌 확장이라는 의미를 냈다.

다중 상속과 자바

다중 상속의 문제점

만약 인어 클래스가 사람, 물고기 두 클래스를 상속받고 있다고 했을 때 만약 두 클래스가 동일한 메서드 시그니처를 구현하고 있다면 인어 클래스는 무슨 메서드를 호출해야 할까?

다중 상속은 득보다 실이 많았기에 자바와 C#은 다중상속을 포기했다.

자바는 다중상속을 포기한 대신 인터페이스(Interface)를 도입했고, 인터페이스는 클래스가 ‘무엇을 할 수 있다’ 라고 하는 기능을 구현하도록 강제한다.

인터페이스가 어떠한 구현을 하도록 강제하기 때문에 인터페이스는 be able to(무엇을 할 수 있는)의 표현 형태로 만드는 것이 좋다.

  • Serializable 인터페이스 : 직렬화 할 수 있는
  • Cloneable 인터페이스 : 복제 할 수 있는
  • Comparable 인터페이스 : 비교할 수 있는
  • Runnable 인터페이스 : 실행할 수 있는

상위 클래스는 풍성할수록 좋다 - LSP(리스코프 치환 법칙).
인터페이스는 메서드가 적을 수록 좋다 - ISP(인터페이스 분할 원칙)

다형성 (Polymorphism) : 사용 편의성

OverRiding

같은 메서드 이름, 같은 인자 목록으로 상위 클래스의 메서드를 재정의

상속에서 상위 클래스의 특성을 상속하고 필요한 특성을 추가, 확장할 수 있다고 했는데 상속받은 특성을 변경하여 사용하는 경우 Overriding이라고 한다.

OverLoading

같은 메서드 이름, 다른 인자 목록으로 다수의 메서드를 중복 정의

만약 OverLoading을 지원하지 않는다면?

두 숫자를 더해서 반환하는 함수

add(int , int)

addIntDouble(int, double)

addDoubleInt(double, int)....

이런식으로 계속 확장해 나가야 한다. 아찔하다..

🍔 OverRiding을 통한 메서드 재정의, OverLoading을 통한 메서드 중복 정의를 통해 다형성을 제공하고, 이 다형성이 개발자가 프로그램을 작성할 때 사용편의성을 준다!

캡슐화(Encapsulation) : 정보 은닉(information hiding)

정보 은닉을 왜 해야할까?

잘 설계된 컴포넌트는 모든 내부 구현을 완벽하게 숨겨, 구현과 API를 깔끔하게 분리한다.

개발자는 오직 공개 API를 통해서만 컴포넌트 소통하며, 컴포넌트의 내부 동작을 알 필요가 없기 때문에 훨씬 쉽게 사용할 수 있다. (내부 정보를 알 필요가 없기 때문에 어떻게 동작하는지 공부할 필요도 없는거죠!)

이렇듯 시스템을 구성하는 컴포넌트들을 서로 독립시켜서 개발, 테스트, 최적화, 적용, 분석, 수정 등을 개별적으로 할 수 있게 해줌으로써 개발에 다양한 장점을 가지게 된다.

정보 은닉을 위한 접근 제어 메커니즘 중 하나 : 접근 제어자

  • public : 모두가 접근 가능
  • protected : 상속/ 같은 패키지 내의 클래스에서 접근 가능
  • [default] : 같은 패키지 내의 클래스에서 접근 가능
  • private : 본인만 접근 가능

접근 제어자 고려 순서

  • 클래스의 공개 API를 세심하게 설계한 후, 그 외의 모든 멤버는 private
  • 같은 패키지의 다른 클래스가 접근해야 하는 멤버에 한하여 [default]

만약 권한을 풀어주는 일을 자주 하게 된다면 → 컴포넌트를 분해해야 하는지 고려하라

“모든 클래스와 멤버의 접근성을 가능한 한 좁혀야 한다”라는 기본 원칙에 맞춰 설계를 진행함으로써
정보 은닉, 즉 내부를 숨기도록 하자!

profile
주니어 백엔드 개발자입니다!

0개의 댓글