delpho
Java에 대하여 - 3 본문
1. SOLID(객체지향 5대원칙)에 대해서 설명해주세요.
# 객체지향 프로그래밍의 5가지 설계 원칙 (SOLID)
- SOLID = 객체지향 프로그래밍을 하면서 지켜야하는 5대 원칙
- SRP(단일 책임 원칙), OCP(개방-폐쇄 원칙), LSP(리스코프 치환 원칙), DIP(의존 역전 원칙), ISP(인터페이스 분리 원칙)
- SOLID 원칙을 철저히 지킨다면?
- 시간이 지나도 변경 용이
- 유지보수와 확징이 쉬운 프로그램 개발 가능
1. SRP (단일 책임 원칙, Single Responsibility Principle)
- 하나의 모듈은 한 가지 책임을 가져야 한다는 것
- 즉, 모듈이 변경되는 이유가 한가지여야 함
- 어떤 클래스가 단 하나의 책임 만을 갖고 있다면, 특정 액터로부터 변경을 특정할 수 있으므로 해당 클래스를 변경해야 하는 이유와 시점이 명확해짐!
- 만약 어떤 모듈이 여러 액터에 대해 책임을 가지고 있다면 여러 액터들로부터 변경에 대한 요구가 올 수 있으므로, 해당 모듈을 수정해야 하는 이유 역시 여러 개가 될 수 있다
- 시스템이 커질수록 극대화되는데, 시스템이 커지면서 서로 많은 의존성을 갖게되는 상황에서 변경 요청이 오면 딱 1가지만 수정하면 되기 때문이다.
@Service
@RequiredArgsConstructor
public class UserService {
private final UserRepository userRepository;
public void addUser(final String email, final String pw) {
final StringBuilder sb = new StringBuilder();
for(byte b : pw.getBytes(StandardCharsets.UTF_8)) {
sb.append(Integer.toString((b & 0xff) + 0x100, 16).substring(1));
}
final String encryptedPassword = sb.toString();
final User user = User.builder()
.email(email)
.pw(encryptedPassword).build();
userRepository.save(user);
}
}
- 해당 UserSevice의 addUser의 기능 = 사용자 정보 받은 후, 비밀번호 암호화하여 DB에 저장
- 여러 상황으로부터 코드 수정이 발생할 수 있음!
- 기획팀 : 사용자 추가 시 Role에 대한 정의 필요
- 보안팀 : 암호화 방식 개선 필요
- 등등
- 여러 상황으로부터 코드 수정이 발생할 수 있음!
- 따라서, UserService가 가지고 있는 비밀번호 암호회 책임 분리 필요!
- 별도의 클래스를 만들어 기능 분리!
@Component
public class SimplePasswordEncoder {
public void encryptPassword(final String pw) {
final StringBuilder sb = new StringBuilder();
for(byte b : pw.getBytes(StandardCharsets.UTF_8)) {
sb.append(Integer.toString((b & 0xff) + 0x100, 16).substring(1));
}
return sb.toString();
}
}
@Service
@RequiredArgsConstructor
public class UserService {
private final UserRepository userRepository;
private final SimplePasswordEncoder passwordEncoder;
public void addUser(final String email, final String pw) {
final String encryptedPassword = passwordEncoder.encryptPassword(pw);
final User user = User.builder()
.email(email)
.pw(encryptedPassword).build();
userRepository.save(user);
}
}
2. OCP (개방-폐쇄 원칙, Open-Closed Principle)
- 확장에 대해 열려있고 수정에 대해서는 닫혀있어야 한다는 원칙
3. LSP (리스코프 치환 원칙, Liskov Substitution Principle)
- 하위 타입은 상위 타입을 대체할 수 있어야 한다는 것
- 해당 객체를 사용하는 클라이언트는 상위 타입이 하위 타입으로 변경되어도, 차이점을 인식하지 못한 채 상위 타입의 퍼블릭 인터페이스를 통해 서브 클래스를 사용할 수 있어야 한다는 것
4. DIP (의존 역전 원칙, Dependency Inversion Principle)
- 고수준 모듈은 저수준 모듈의 구현에 의존해서는 안 되며, 저수준 모듈이 고수준 모듈에서 정의한 추상 타입에 의존해야 한다는 것
5. ISP (인터페이스 분리 원칙, Interface segregation principle)
- 목적과 관심이 각기 다른 클라이언트가 있다면 인터페이스를 통해 적절하게 분리
2. 동일성(identity)와 동등성(equality)에 대해 설명해주세요. (equals(), ==)
# 동등성 (equality)
- 두 개의 객체(변수)가 같은 정보(값)을 가지고 있는 경우
- 예를들어, 두 변수의 값이 같고 주소값이 다를때, 두 객체는 동등하다.
# 동일성 (identity)
- 두 개의 객체(변수)가 완전히 같은 경우
- 두 객체가 사실상 하나의 객체로 봐도 무방할 경우 (주소값이 같을때)
- 원시 타입(Primitive)은 객체가 아니기때문에 주소가 없으므로 값이 같다면 동일하다. (==)
# String의 특이한점
- 참조타입이지만 원시타입처럼
- String은 정확하게는 reference 타입이지만 new 가 아닌 primitve 타입처럼 초기화 가능! (String st = "aaa";)
- 자바에서 문법적으로 허락 (특별대우)
String st1 = "aaa";
String st2 = "aaa";
System.out.println(st1==st2);
2. String Constant Pool
- 리터럴 값으로 초기화할 경우
- Heap 영역안에 특별한 메모리 공간인 String Constant pool에 저장됨
- String constant pool에 존재하는 리터럴 값 사용하면, 해당 참조값 그대로 사용
- Heap 영역안에 특별한 메모리 공간인 String Constant pool에 저장됨
- new 키워드를 통해 초기화할 경우
- 일반 객체와 같이 Heap 영역에 동적으로 메모리 공간이 할당됨
- 같은 문자열이더라도 새롭게 생성됨
- 일반 객체와 같이 Heap 영역에 동적으로 메모리 공간이 할당됨
String strA = "abc";
String strB = new String("abc");
String strC = "abc";
String strD = new String("abc");
System.out.println(strA==strB); //false
System.out.println(strA==strC); //true
System.out.println(strB==strD); //false
- 결과는 true
- 문자열 상수에 대해서 문자열이 동일할 경우 하나의 인스턴스만 생성하고, 이를 공유하도록 함
- "aaa"라는 문자열이 메모리에 생성되면서 st1에 주소값을 넘겨주었고, st2를 생성하는데 이미 생성된 "aaa" 문자열과 똑같으므로 새로 메모리에 생성하지 않고 기존에 생성된 "aaa" 문자열의 주소를 돌려줘서 공유하게 하는 것!
- String만 특별대우 해주는 이유!
- 문자열 이라는 특성 때문
- 인스턴스의 생성이란 사실 시스템에 부담이 되는 요소!!
- 그런데 문자열을 표현할 때 마다 인스턴스가 생성되니, 이를 줄일 필요가 있었던 것
3. 원시타입과 참조타입의 차이에 대해 설명해주세요.
# 원시타입
- 정수, 실수, 문자, 논리 리터럴 등 실제 데이터 값을 저장하는 타입
- 장점
- 접근 속도가 빠르다
- 원시 타입은 스택 공간에 값이 존재
- 참조 타입은 하나의 인스턴스이기 때문에 참조 변수는 스택 영역에, 실제 객체는 힙 공간에 존재
- 따라서, 과정이 하나 더 추가되니 접근속도 차이 발생
- 접근 속도가 빠르다
# 참조 타입 (reference 타입)
- 우리가 흔히 사용하는, new 연산자로 생성할 수 있는 객체
- 기본 타입을 제외한 타입들을 말한다. 객체의 주소를 저장하는 타입
- new 연산자란 간단히 클래스의 객체를 생성하는 연산자라고 표현할 수 있지만
- 좀 더 상세하게 얘기하면 클래스의 객체를 생성하여 메모리에 올리고, 그 참조변수를 반환해주는 연산자
- 원시 타입과의 차이점 = 참조변수
- 참조변수 = 메모리에 올라간 객체를 가리키는 주소값
- reference 타입 자료형을 비교할 때는 primitive 타입 변수와는 달리, 값의 비교가 두 가지의 의미를 가지게 됨
- 동등성, 동일성
따라서,
# 원시타입, 참조 타입 차이점
1. Null을 담을 수 있는가?
- 기본 타입은 null을 담을 수 x
- 참조 타입은 가능
2. 제네릭 타입에서 사용할 수 있는가?
- 기본 타입은 제네릭 타입에서 사용할 수 x
- 참조 타입은 가능
3. 값의 비교 시 주소값을 참고하는가
- 기본 타입은 참고 x
- 참조 타입은 참고 o
4. 접근 속도, 메모리 양
- 기본 타입이 참조타입에 비해 접근 속도가 훨씬 빠르고 메모리 양도 훨씬 적게 사용한다.
4. String, StringBuilder, StringBuffer 각각의 차이에 대해 설명해주세요.
1. String은 불변 객체, StringBuilder, StringBuffer는 가변 객체
- String의 불변성으로 인해, 문자열 수정시 메모리 낭비가 생김
- 이를 해결하기 위해 StringBuilder, StringBuffer 등장
2. StringBuilder는 동기화 미지원, StringBuffer는 동기화 지원
- StringBuilder
- 동기화를 미지원해서 멀티스레드 환경에 사용은 부적합
- 대신, 단일 스레드에서의 성능은 StringBuffer보다 뛰어남
- StringBuffer
- 동기화를 지원해서 멀티스레드 환경에서 안전 (내부 메서드 별로 synchronized 키워드가 선언)
- 동기화 작업을 거쳐야하기때문에 속도 성능은 떨어짐.
- String
- 불변 객체이기때문에 멀티스레드 환경에서 안전
따라서...
5. Checked Exception과 Unchecked Exception에 대해 설명해주세요.
# 예외
- 입력 값에 대한 처리가 불가능하거나, 프로그램 실행 중에 참조된 값이 잘못된 경우 등 정상적인 프로그램의 흐름을 어긋나는 것
# 예외 종류
- Checked Exception
- RuntimeException을 상속하지 않는 클래스
- Compile 시점에서 Exception 발생
- 반드시 에러 처리를 해야함 (try/catch or throw)
- ex. FileNotFoundException, ClassNotFoundException
- Unchecked Exception
- RuntimeException을 상속하는 클래스
- Runtime 시점에서 Exception 발생이 확인
- 에러 처리를 강제하지 않음
- ex. NullPointerException, ClassCastException
# RuntimeException
- 말그대로 런타임 중에 발생
- 명시적으로 예외 처리를 하지 않아도 되는 exception
- ex. System 환경적으로나, Input Value가 잘못된 경우, 의도적으로 개발자가 설정한 조건을 위배했을 때 throw 되게 하는 등
출처
https://mangkyu.tistory.com/194
[OOP] 객체지향 프로그래밍의 5가지 설계 원칙, 실무 코드로 살펴보는 SOLID
이번에는 객체 지향 프로그래밍의 5가지 핵심 원칙인 SOLID에 대해 알아보고자 합니다. 실제로 애플리케이션을 개발할 때 어떻게 적용할 수 있을지 구체적인 예시를 들어 살펴보고자 합니다. 아
mangkyu.tistory.com
동일성, 동등성
두 변수의 값을 비교하기 위해, 우리는 == 연산자를 사용했습니다. 하지만 이 연산자를 이용한 비교는, primitive(원시) 타입의 자료형에만 해당하는 사항입니다. ( primitive 타입 자료형이란 int, doubl
joont.tistory.com
https://siyoon210.tistory.com/139
Java에서 원시타입 vs 참조타입 어떤 걸 사용해야 할까?
[개요] 자바에서 숫자를 다루기 위한 타입들은 크게 두 가지로 분류할 수 있습니다. 하나는 '원시 타입(primitive type)'이고, 또 다른 하나는 참조 타입(reference type)'입니다. 원시 타입은 (int, double, boo
siyoon210.tistory.com
https://week-year.tistory.com/141
[Java] 기본 타입 vs 참조 타입 (feat. heap, stack 영역)
1. 기본 타입 (Primitive type) 정수, 실수, 문자, 논리 리터럴을 저장하는 타입을 말하고 원시 타입이라고도 부른다. 정수형 : byte, short, int, long 실수형 : float, double 문자형 : char 논리형 : boolean..
week-year.tistory.com
StringBuilder와 StringBuffer는 무슨 차이가 있는가?
Java에서 String 클래스는 불변성을 갖습니다. 그래서 변하지 않는 문자열을 자주 사용하는 경우엔 좋은 성능을 기대할 수 있습니다. 하지만 문자열에 대한 변경이 자주 일어나는 프로그램에서 Stri
velog.io
https://ifuwanna.tistory.com/221
[Java] String, StringBuffer, StringBuilder 차이 및 장단점
Java 에서 문자열을 다루를 대표적인 클래스로 String , StringBuffer, StringBuilder 가 있습니다. 연산이 많지 않을때는 위에 나열된 어떤 클래스를 사용하더라도 이슈가 발생할 가능성은 거의 없습니다
ifuwanna.tistory.com
https://madplay.github.io/post/java-checked-unchecked-exceptions
자바 예외 구분: Checked Exception, Unchecked Exception
자바에서 예외는 어떻게 구분할까? Checked Exception과 Unchecked Exception의 차이는 무엇일까?
madplay.github.io
https://velog.io/@gillog/JavaException-Error%EC%9D%98-%EC%B0%A8%EC%9D%B4
'CS' 카테고리의 다른 글
Spring에 대하여 - 5 (0) | 2022.06.19 |
---|---|
Java에 대하여 - 4 (0) | 2022.06.10 |
Java에 대하여 - 2 (0) | 2022.06.08 |
Java에 대하여 - 1 (0) | 2022.06.08 |
Spring에 대하여 - 3 (0) | 2022.06.04 |