객체지향 프로그래밍 설계 원칙 SOLID 및 JAVA 컴파일 과정 & JVM 구성

Danny·2023년 10월 23일
0

백엔드

목록 보기
4/10

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

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

  2. OCP(Open-closed principle) : 개방-폐쇄 원칙

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

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

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


SRP - 단일 책임 원칙

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

모든 클래스는 각각 하나의 책임만 가져야 하며, 수정할 이유는 단 한 가지여야 한다.

즉, 클래스는 그 책임을 완전히 캡슐화해야 함을 말한다.

예를들어, 결제 클래스가 있다치면 이 클래스는 오직 결제 기능만을 책임지고,

만약 이 클래스를 수정해야 한다면 결제에 관련된 문제일 뿐일 것이다.

OCP - 개방-폐쇄 원칙

확장에는 열려있고 변경에는 닫혀 있어야 한다.

소프트웨어의 구성요소(컴포넌트, 클래스, 모듈, 함수)는 확장에는 열려 있어야 하지만 변경에는 폐쇄적이어야 함을 의미한다.

즉, 기존의 코드를 변경하지 않으면서, 기능을 추가할 수 있도록 설계가 되는 원칙을 말한다.

예를들어, 캐릭터 하나를 생성한다고 할 때 각 캐릭터마다 움직임이 다를 경우,

움직임 패턴 구현을 하위 클래스에 맡긴다면 캐릭터 클래스의 수정은 필요없고(Closed),

움직임 패턴만 재정의 하면 된다.(Open)

개방-폐쇄 원칙을 적용하기 위한 중요 메커니즘은 추상화와 다형성이다.

LSP - 리스코프 치환 원칙

서브 타입은 언제나 자신의 기반 타입으로 변경할 수 있어야 한다.

상위 타입은 항상 하위 타입으로 대체될 수 있어야 함을 의미한다.

즉, 부모 클래스가 들어갈 자리에 자식 클래스를 넣어도 역할을 하는데 문제가 없어야 한다는 의미이다.

image

image

리스코프 치환 원칙은 다형성과 확장성을 극대화하며, 개방-폐쇄 원칙을 구성한다.

ISP - 인터페이스 분리 원칙

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

인터페이스 분리 원칙은 각 역할에 맞게 인터페이스를 분리하는 것이다.

인터페이스 내에 메소드는 최소한 일수록 좋다. 즉, 최소한의 기능만 제공하면서 하나의 역할에 집중하라는 뜻이다.

단일 책임 원칙(SRP)과 인터페이스 분할 원칙(ISP)은 같은 문제에 대한 두 가지 다른 해결책이라고 볼 수 있다.

가능한 최소한의 인터페이스를 사용하도록 하여 단일 책임을 강조한다고 볼 수 있다.

일반적으로 ISP보다 SRP 할 것을 권장하고 있다.

DIP - 의존관계 역전 원칙

구체적인 것이 추상화된 것에 의존해야 한다. 자주 변경되는 구체 클래스에 의존하지마라.

의존 관계를 맺을 때 변화하기 쉬운 것 또는 자주 변화하는 것보다는 변화하기 어려운 것, 거의 변화가 없는 것에 의존하라는 것이다.
즉, 구체적인 클래스보다 상위 클래스, 인터페이스, 추상 클래스와 같이 변하지 않을 가능성이 높은 클래스와 관계를 맺으라는 것
image

image

DIP 원칙을 따르는 가장 인기 있는 방법은 의존성 주입(DI; Dependency Injection)을 활용하는 것이다.

참고자료 :

https://hckcksrl.medium.com/solid-%EC%9B%90%EC%B9%99-182f04d0d2b

https://devlog-wjdrbs96.tistory.com/380

https://code-lab1.tistory.com/121

JAVA 컴파일 과정 & JVM 구성

자바는 OS에 독립적인 특징을 가지고 있다. 그게 가능한 이유는 JVM(Java Vitual Machine) 덕분

image

1.개발자가 자바 소스코드(.java)를 작성합니다.

2.자바 컴파일러(Java Compiler)가 자바 소스파일을 컴파일합니다. 이때 나오는 파일은 자바 바이트 코드(.class)파일로 아직 컴퓨터가 읽을 수 없는 자바 가상 머신이 이해할 수 있는 코드입니다. 바이트 코드의 각 명령어는 1바이트 크기의 Opcode와 추가 피연산자로 이루어져 있습니다.

3.컴파일된 바이트 코드를 JVM의 클래스로더(Class Loader)에게 전달합니다.

4.클래스 로더는 동적로딩(Dynamic Loading)을 통해 필요한 클래스들을 로딩 및 링크하여 런타임 데이터 영역(Runtime Data area), 즉 JVM의 메모리에 올립니다.

#

  • 로드 : 클래스 파일을 가져와서 JVM의 메모리에 로드합니다.

  • 검증 : 자바 언어 명세(Java Language Specification) 및 JVM 명세에 명시된 대로 구성되어 있는지 검사합니다.

  • 준비 : 클래스가 필요로 하는 메모리를 할당합니다. (필드, 메서드, 인터페이스 등등)

  • 분석 : 클래스의 상수 풀 내 모든 심볼릭 레퍼런스를 다이렉트 레퍼런스로 변경합니다.

  • 초기화 : 클래스 변수들을 적절한 값으로 초기화합니다. (static 필드)

5.실행엔진(Execution Engine)은 JVM 메모리에 올라온 바이트 코드들을 명령어 단위로 하나씩 가져와서 실행합니다. 이때, 실행 엔진은 두가지 방식으로 변경합니다.

  • 인터프리터 : 바이트 코드 명령어를 하나씩 읽어서 해석하고 실행합니다. 하나하나의 실행은 빠르나, 전체적인 실행 속도가 느리다는 단점을 가집니다.

  • JIT 컴파일러(Just-In-Time Compiler) : 인터프리터의 단점을 보완하기 위해 도입된 방식으로 바이트 코드 전체를 컴파일하여 바이너리 코드로 변경하고 이후에는 해당 메서드를 더이상 인터프리팅 하지 않고, 바이너리 코드로 직접 실행하는 방식입니다. 하나씩 인터프리팅하여 실행하는 것이 아니라 바이트 코드 전체가 컴파일된 바이너리 코드를 실행하는 것이기 때문에 전체적인 실행속도는 인터프리팅 방식보다 빠릅니다.

https://gyoogle.dev/blog/computer-language/Java/%EC%BB%B4%ED%8C%8C%EC%9D%BC%20%EA%B3%BC%EC%A0%95.html

https://velog.io/@minseojo/Java-%EC%9E%90%EB%B0%94-%EC%BB%B4%ED%8C%8C%EC%9D%BC-%EA%B3%BC%EC%A0%95-JVM-%EB%82%B4%EB%B6%80-%EA%B5%AC%EC%A1%B0

https://velog.io/@bcj0114/%EC%BB%B4%ED%8C%8C%EC%9D%BC%EB%9F%AC%EC%99%80-%EC%9D%B8%ED%84%B0%ED%94%84%EB%A6%AC%ED%84%B0-%EA%B7%B8%EB%A6%AC%EA%B3%A0-JIT-%EC%BB%B4%ED%8C%8C%EC%9D%BC

0개의 댓글