시청할 것
이번 주 키워드 정리
상속(Inheritance) vs 조합(Composition)
1. 상속(Inheritance)
- 부모 클래스의 속성과 메서드를 자식 클래스가 물려받는 방식
- 코드 재사용성이 높지만, 부모 클래스에 종속되어 강한 결합(High Coupling) 발생
- 부모 클래스가 변경되면 자식 클래스에도 영향을 미쳐 유지보수가 어려워질 수 있음
2. 조합(Composition)
- 기존 클래스를 포함(Has-A 관계)하여 기능을 재사용하는 방식
- 강한 결합을 피할 수 있어 유지보수가 용이하고 유연성이 높음
- 상속보다 유연하며, 런타임 시 객체를 변경할 수도 있음
🚀 언제 사용해야 할까?
- 상속: 명확한 "is-a" 관계(예: Car is a Vehicle)
- 조합: 유연한 "has-a" 관계(예: Car has an Engine)
- 가능하면 조합을 우선적으로 고려하고, 정말 필요한 경우에만 상속을 사용하자.
메서드 오버로딩(Overloading) vs 오버라이딩(Overriding)
1. 오버로딩(Overloading)
- 같은 클래스 내에서 메서드 이름은 같지만 매개변수의 타입 또는 개수가 다른 경우
- 정적 바인딩(컴파일 타임에 결정)
- 메서드 시그니처(이름 + 매개변수)가 다르면 같은 이름의 메서드를 여러 개 만들 수 있음
class MathUtils {
int add(int a, int b) {
return a + b;
}
double add(double a, double b) {
return a + b;
}
}
2. 오버라이딩(Overriding)
- 부모 클래스의 메서드를 자식 클래스에서 재정의하는 것
- 동적 바인딩(런타임에 결정)
- 메서드 이름, 매개변수, 반환 타입이 모두 같아야 함
class Parent {
void show() {
System.out.println("부모 클래스");
}
}
class Child extends Parent {
@Override
void show() {
System.out.println("자식 클래스");
}
}
🚀 차이점 요약
구분 | 오버로딩(Overloading) | 오버라이딩(Overriding) |
정의 | 같은 이름의 메서드를 매개변수 다르게 여러 개 정의 | 부모 클래스의 메서드를 자식 클래스에서 재정의 |
실행 시점 | 컴파일 타임(정적 바인딩) | 런타임(동적 바인딩) |
적용 대상 | 같은 클래스 내에서 | 상속 관계에서 부모-자식 클래스 간 |
반환 타입 | 다를 수도 있음 | 반드시 같아야 함 |
DTO(Data Transfer Object)란?
- 데이터를 전달하기 위한 객체
- 보통 Getter, Setter만 포함하며, 비즈니스 로직을 가지지 않음
- Controller ↔ Service, Service ↔ Repository 간 데이터 교환에 사용
- 불변 객체(Immutable)로 만들어야 안전함
📌 예제
public class UserDTO {
private String name;
private int age;
public UserDTO(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() { return name; }
public int getAge() { return age; }
}
🚀 DTO를 쓰는 이유?
- 엔티티(Entity) 보호: 직접 노출하면 보안/유지보수 문제 발생
- 레이어 간 데이터 전달 용이
- 불필요한 데이터 제외: 필요한 정보만 전달 가능
- API 응답 형식 통일
결국 핵심은,
직접 노출시키지 않으면서 필요한 데이터만 전달 가능하다는 것이다.
객체지향 생활체조 (소트웍스 앤솔러지)
객체지향 원칙을 더 잘 따르기 위한 일종의 개발 가이드라인
🔹 1️⃣ 모든 원시값과 문자열을 포장한다.
원시값을 객체로 만들면, 그 값이 어떤 값이며, 왜 쓰이고 있는지를 알릴 수 있다.
→ int 값 자체는 아무 의미도 없다. 시간, 돈 같은 원시값들도 객체로 만들어 의도를 전달하자.
→ 메서드 이름과 매개변수 이름을 짓는 데 노력하자.
🔹 2️⃣ 1급 컬렉션을 사용한다.
컬렉션(List, Set, Map 등)을 직접 사용하지 않고 이를 감싸는 클래스를 만든다.
→ 원시값뿐만 아니라, 컬렉션도 객체로 감싸 관리해야 한다.
→ 본래 컬렉션이 제공하는 다양한 메서드들에 대해, 외부에 노출할 메서드를 직접 조절할 수 있다.
→ 참고로, 컬렉션을 포함한 클래스는 다른 멤버 변수를 지니지 않아야 한다.
🔹 3️⃣ 클래스가 가능한 적은 인스턴스 변수를 갖도록 한다.
객체의 상태를 최소화하여 결합도를 낮추고 응집도를 높인다.
→ 인스턴스 변수가 많은 클래스일수록 응집력 있는 단일 작업을 설명하기 어렵다.
→ 객체의 크기를 작게 유지하는 것이 중요하며, 필요하면 새로운 클래스로 분리한다.
🔹 4️⃣ 모든 엔티티를 작게 유지한다.
하나의 객체는 한 가지 책임만 가지도록 한다.
→ 50줄 이상 되는 클래스와 10개 파일 이상 되는 패키지는 없어야 한다.
→ 만약 이러한 클래스가 있다면 높은 확률로 한 가지 이상의 책임을 하는 것이다.
🔹 5️⃣ 한 메서드에 오직 한 단계의 들여쓰기만 한다.
if, for, while 등의 중첩을 최소화하여 가독성을 높인다.
→ 메서드당 하나의 제어 구조나 하나의 문장 단락으로 구성되도록 노력한다.
→ 중첩된 제어 구조가 있다면, 다단계 추상화를 코드로 짠 것으로, 하나 이상의 일을 하고 있을 확률이 높다.
🔹 6️⃣ else 예약어를 사용하지 않는다.
조건문을 단순하게 만들고, 조기 반환(early return)을 활용한다.
→ 불필요한 중첩을 없애고 가독성을 높인다.
🔹 7️⃣ 한 줄에 점을 하나만 찍는다.
디미터 법칙(Law of Demeter)을 지켜 결합도를 낮춘다.
→ 객체가 다른 객체의 내부 구조를 알지 못하도록 캡슐화를 유지해야 한다.
→ 어떠한 코드 한 줄에 점이 하나 이상 있으면 다른 곳에서 동작이 일어나고 있을 확률이 높다.
→ 캡슐화의 요점은 클래스 경계를 벗어나 알 필요 없는 타입으로 진입하지 않는 것이다.
🔹 8️⃣ 명령과 조회를 분리한다.
void 메서드는 상태를 변경하고, return 메서드는 값을 조회하는 역할만 한다.
→ 명령(사이드 이펙트)과 조회를 분리하면 코드의 예측 가능성이 높아진다.
🔹 9️⃣ Getter, Setter, Property를 사용하지 않는다.
데이터를 직접 꺼내지 말고 객체에 메시지(요청)를 보내도록 한다.
→ 데이터를 꺼내서 조작하는 것이 아니라, 객체가 스스로 책임을 수행해야 한다.
추가로 "줄여 쓰지 않는다."까지 알고 있으면 더 좋다.
이는 멋사 1차 과제 후 받은 전체 피드백에도 포함되는 내용이다!
'멋쟁이사자처럼 > 정기 세션' 카테고리의 다른 글
[🦁2] Web App & Spring MVC #2 (2) | 2025.03.23 |
---|---|
[🦁2] Web App & Spring MVC #1 (0) | 2025.03.21 |
[🦁1] Git & GitHub (0) | 2025.03.14 |