5주차 Unit 5.3 — 두 패턴의 한계

Psj·2026년 5월 27일

F-lab

목록 보기
171/238

Unit 5.3 — 두 패턴의 한계

F-LAB JAVA · 5주차 · Phase 5 · 디자인 패턴의 적용
🏆 Phase 5 완주 — 상속의 한계와 합성으로의 전환


📌 학습 목표

이 Unit을 끝내면 다음을 답할 수 있어야 한다.

  • 상속을 이용한 분리의 단점 3가지는?
  • 단일 상속 제약 의 문제는?
  • 컴파일 타임 결합 의 문제는?
  • 상속의 깨지기 쉬움 (fragile base class) 은?
  • "Composition over Inheritance" 원칙은?
  • 상속 (is-a) vs 합성 (has-a) 의 차이는?
  • 상속을 인터페이스로 대체 하면 좋아지는 것은?
  • 인터페이스 + 합성 이 필요한 이유는?
  • Phase 5 전체 의 종합은?

🎯 핵심 한 문장

템플릿 메소드·팩토리 메소드 패턴은 상속을 기반으로 하기에 단일 상속 제약·컴파일 타임 결합·상속의 깨지기 쉬움이라는 한계가 있으며, 이를 극복하려면 "상속보다 합성 (Composition over Inheritance)" 원칙에 따라 인터페이스 + 합성으로 전환해야 한다.
상속 기반의 세 가지 단점은 (1) 단일 상속 제약 — UserDao 를 상속하면 다른 클래스를 상속할 수 없고, (2) 컴파일 타임 결합 — 새 DB 를 추가하려면 새 클래스를 만들어 컴파일해야 하며, (3) 상속 관계의 깨지기 쉬움 — 부모가 변경되면 모든 자식이 영향을 받는다.
이 한계의 근본 원인은 상속이 컴파일 시점에 부모-자식 관계가 고정되는 강한 결합 이기 때문이다.
"Composition over Inheritance" 는 상속 (is-a, 강결합) 대신 합성 (has-a, 느슨한 결합) 을 우선하라는 원칙으로, 변하는 부분을 별도 객체로 분리해 보유 (합성) 하면 런타임에 교체할 수 있다.
따라서 다음 Phase 에서는 getConnection 을 추상 메서드 대신 ConnectionMaker 인터페이스 로 분리하고 이를 주입 (합성) 받아, 상속의 한계를 극복한다.

비유 — 가구 붙박이 vs 모듈

상속 vs 합성 = 붙박이 가구 vs 모듈 가구:

상속 (붙박이 — is-a):
  - 책장이 벽에 붙박이
  - 한 벽에만 (단일 상속)
  - 벽 바꾸면 책장 다 영향 (깨지기 쉬움)
  - 설치 시 고정 (컴파일 타임)

합성 (모듈 — has-a):
  - 책장을 방에 "놓음" (보유)
  - 여러 가구 조합 가능
  - 책장만 교체 가능 (런타임)
  - 독립적 (느슨한 결합)

Composition over Inheritance:
  - 붙박이보다 모듈 우선
  - 유연한 조합

인터페이스 + 합성:
  - "연결 담당" 을 부품으로 (인터페이스)
  - DAO 가 보유 (합성)
  - 부품 교체 가능

→ 상속(붙박이) 한계 → 합성(모듈) 전환, Composition over Inheritance.


🧭 9개 섹션 로드맵

1. 상속 분리의 단점 개요
2. 단일 상속 제약
3. 컴파일 타임 결합
4. 깨지기 쉬움 (fragile base class)
5. Composition over Inheritance
6. 상속(is-a) vs 합성(has-a)
7. 인터페이스로 대체하면
8. Phase 5 완주 정리
9. 면접 + 자기 점검

1️⃣ 상속 분리의 단점 개요

1.1 세 가지 단점

상속 기반 분리 단점:

1. 단일 상속 제약
   - 한 클래스만 상속

2. 컴파일 타임 결합
   - 새 클래스 컴파일

3. 깨지기 쉬움
   - 부모 변경 → 자식 영향

1.2 근본 원인

근본 원인:

  상속 = 강한 결합:
    - 컴파일 시 고정
    - 부모-자식 묶임
    - 유연성 ↓

1.3 패턴들의 공통 한계

템플릿/팩토리 공통 한계:

  둘 다 상속 기반:
    - 서브클래스 만듦
    - 상속 단점 공유

→ 같은 한계

1.4 ILIC 의 맥락

// 상속 기반 (한계 내포)
public abstract class ShipmentDao {
    protected abstract Connection getConnection() throws Exception;
}

// 새 DB = 새 서브클래스 (상속)
class MySqlShipmentDao extends ShipmentDao { /* ... */ }
class OracleShipmentDao extends ShipmentDao { /* ... */ }

// 한계:
// 1. ShipmentDao 상속 → 다른 클래스 못 상속
// 2. 새 DB → 새 클래스 컴파일
// 3. ShipmentDao 변경 → 모든 자식 영향

1.5 자기 점검 답변

상속을 이용한 분리의 단점 3가지는?

:
1. 세 단점:

  • 단일 상속
  • 컴파일 타임
  • 깨지기 쉬움
  1. 근본 원인:

    • 강한 결합
  2. 공통:

    • 템플릿/팩토리 둘 다
  3. 상속 기반:

    • 같은 한계

2️⃣ 단일 상속 제약

2.1 단일 상속

단일 상속 제약:

  자바:
    - 클래스 하나만 상속
    - extends 하나

  ShipmentDao 상속하면:
    - 다른 클래스 상속 불가

2.2 문제

// 단일 상속 문제
public class CustomerShipmentDao 
    extends ShipmentDao {       // ShipmentDao 상속
    // extends BaseEntity       // ❌ 불가 (이미 상속)
    // extends CommonRepository // ❌ 불가
}
// 공통 기능 상속 못 함

2.3 상속 슬롯 낭비

상속 슬롯 낭비:

  상속 = 1회용 슬롯:
    - 연결 위해 써버림
    - 다른 용도 불가

  → 귀한 상속을 연결에 소비

2.4 합성은 다중 가능

// 합성은 여러 개 가능
public class ShipmentDao {
    private final ConnectionMaker connectionMaker;   // 합성 1
    private final QueryLogger queryLogger;            // 합성 2
    private final CacheManager cacheManager;          // 합성 3
    // 여러 협력 객체 보유 (제약 X)
}

2.5 ILIC 의 맥락

// 단일 상속 한계
public abstract class ShipmentDao {
    protected abstract Connection getConnection() throws Exception;
}

// 고객사 DAO 가 다른 공통 베이스도 상속하고 싶다면?
public class CustomerShipmentDao extends ShipmentDao {
    // extends AuditableEntity   // ❌ 이미 ShipmentDao 상속
    // → 감사 기능 상속 불가
}

// ✓ 합성으로 해결 (여러 개)
public class ShipmentDaoComposed {
    private final ConnectionMaker connectionMaker;   // 연결
    private final AuditLogger auditLogger;            // 감사
    private final MetricsCollector metrics;           // 메트릭
    // 여러 기능 조합 (단일 상속 제약 X)
    
    public ShipmentDaoComposed(ConnectionMaker cm, 
                                AuditLogger al, 
                                MetricsCollector mc) {
        this.connectionMaker = cm;
        this.auditLogger = al;
        this.metrics = mc;
    }
}
interface ConnectionMaker { Connection makeConnection(); }
interface AuditLogger { void log(String s); }
interface MetricsCollector { void collect(String s); }

2.6 자기 점검 답변

단일 상속 제약의 문제는?

:
1. 단일 상속:

  • 클래스 하나만
  1. 문제:

    • 다른 베이스 불가
  2. 슬롯 낭비:

    • 연결에 소비
  3. 합성:

    • 여러 개 가능

3️⃣ 컴파일 타임 결합

3.1 컴파일 타임 결합

컴파일 타임 결합:

  상속 관계:
    - 컴파일 시 고정
    - 런타임 변경 X

  새 DB:
    - 새 클래스 작성
    - 컴파일
    - 배포

3.2 정적 결정

정적 결정:

  extends 는 컴파일 타임:
    - MySqlShipmentDao extends ShipmentDao
    - 코드에 고정

  → 런타임 교체 불가

3.3 새 DB 추가 과정

새 DB 추가 (상속):

  1. 새 클래스 작성
     class PostgreSqlShipmentDao extends ShipmentDao

  2. getConnection 구현

  3. 컴파일

  4. 배포

→ 코드 + 컴파일 필요

3.4 합성은 런타임

// 합성은 런타임 교체
ShipmentDao dao = new ShipmentDao(mysqlConnectionMaker);   // 런타임 결정
// 또는
ShipmentDao dao = new ShipmentDao(oracleConnectionMaker);  // 런타임

// 설정/조건에 따라 런타임에 주입
ConnectionMaker cm = loadFromConfig();   // 동적
ShipmentDao dao = new ShipmentDao(cm);

3.5 ILIC 의 맥락

// 컴파일 타임 (상속)
// 새 DB → 새 클래스 컴파일
class PostgreSqlShipmentDao extends ShipmentDao {
    protected Connection getConnection() { return null; }
}
// 컴파일 + 배포 필요

// ✓ 런타임 (합성)
public class ShipmentDao {
    private final ConnectionMaker connectionMaker;
    public ShipmentDao(ConnectionMaker cm) {
        this.connectionMaker = cm;   // 런타임 주입
    }
}

// 설정으로 런타임 결정
String dbType = config.get("db.type");
ConnectionMaker cm = switch (dbType) {
    case "mysql" -> new MySqlConnectionMaker();
    case "postgres" -> new PostgreSqlConnectionMaker();
    default -> throw new IllegalArgumentException();
};
ShipmentDao dao = new ShipmentDao(cm);   // 런타임 조립
// 코드 수정/컴파일 없이 설정만으로
interface ConnectionMaker { Connection makeConnection(); }
class MySqlConnectionMaker implements ConnectionMaker {
    public Connection makeConnection() { return null; }
}
class PostgreSqlConnectionMaker implements ConnectionMaker {
    public Connection makeConnection() { return null; }
}

3.6 자기 점검 답변

컴파일 타임 결합의 문제는?

:
1. 컴파일 타임:

  • 상속 고정
  • 런타임 변경 X
  1. 정적 결정:

    • 코드에 고정
  2. 새 DB:

    • 새 클래스 컴파일
  3. 합성:

    • 런타임 교체

4️⃣ 깨지기 쉬움 (fragile base class)

4.1 fragile base class

깨지기 쉬운 베이스 클래스:

  부모(베이스) 변경:
    - 모든 자식 영향
    - 예상치 못한 버그

  → 부모 수정이 위험

4.2 강한 결합

강한 결합:

  상속:
    - 자식이 부모 내부 의존
    - 부모 구현 변경 시
    - 자식 깨질 수 있음

  → 캡슐화 약화

4.3 예시

// 부모 변경이 자식 깨뜨림
public abstract class ShipmentDao {
    public void add(Shipment s) throws Exception {
        Connection c = getConnection();
        validate(s);   // 부모가 validate 추가 (변경)
        // ...
    }
    protected void validate(Shipment s) { }   // 새 메서드
}

// 자식이 우연히 같은 이름 메서드 있으면?
class CustomerShipmentDao extends ShipmentDao {
    protected Connection getConnection() { return null; }
    // protected void validate(...) 충돌/오버라이드 의도치 않게
}
// 부모 변경 → 자식 예상치 못한 동작

4.4 캡슐화 약화

캡슐화 약화:

  상속:
    - 자식이 부모 protected 접근
    - 내부 노출
    - 변경 영향 ↑

  합성:
    - public 인터페이스만
    - 내부 숨김
    - 변경 격리

4.5 ILIC 의 맥락

// 깨지기 쉬운 상속
public abstract class ShipmentDao {
    // 부모에 메서드 추가 (변경)
    public void add(Shipment s) throws Exception {
        Connection c = getConnection();
        beforeSave(s);   // 새로 추가한 훅
    }
    protected void beforeSave(Shipment s) { }   // 추가
    protected abstract Connection getConnection() throws Exception;
}

// 기존 자식이 영향 받을 수 있음
class ExistingShipmentDao extends ShipmentDao {
    protected Connection getConnection() { return null; }
    // beforeSave 가 새로 추가됨 → 동작 변경 가능성
}

// ✓ 합성은 안전
public class ShipmentDaoSafe {
    private final ConnectionMaker connectionMaker;   // 인터페이스 (계약)
    // ConnectionMaker 인터페이스만 의존
    // 구현 변경되어도 계약 같으면 안전
    public ShipmentDaoSafe(ConnectionMaker cm) {
        this.connectionMaker = cm;
    }
}
interface ConnectionMaker { Connection makeConnection(); }

4.6 자기 점검 답변

상속의 깨지기 쉬움 (fragile base class) 은?

:
1. fragile base class:

  • 부모 변경 → 자식 영향
  1. 강한 결합:

    • 자식이 부모 내부 의존
  2. 예시:

    • 부모 메서드 추가 → 자식 영향
  3. 캡슐화:

    • 상속 약화, 합성 격리

5️⃣ Composition over Inheritance

5.1 원칙

Composition over Inheritance:

  "상속보다 합성을 우선하라"

  - 상속 (is-a): 강결합
  - 합성 (has-a): 느슨

→ 합성 권장

5.2 의미

의미:

  기능 재사용/확장 시:
    - 상속보다
    - 합성 (객체 보유)

  → 유연성 ↑

5.3 왜 합성

왜 합성:

  - 런타임 교체
  - 다중 조합
  - 느슨한 결합
  - 캡슐화 유지
  - 테스트 용이

5.4 합성 예시

// 합성 (객체 보유)
public class ShipmentDao {
    private final ConnectionMaker connectionMaker;   // has-a (합성)
    
    public ShipmentDao(ConnectionMaker cm) {
        this.connectionMaker = cm;   // 주입
    }
    
    public void add(Shipment s) throws Exception {
        Connection c = connectionMaker.makeConnection();   // 위임
    }
}
// 상속 대신 보유 + 위임

5.5 ILIC 의 맥락

// Composition over Inheritance 적용

// ❌ 상속 (강결합)
public abstract class ShipmentDaoInheritance {
    protected abstract Connection getConnection() throws Exception;
}

// ✓ 합성 (느슨)
public class ShipmentDaoComposition {
    private final ConnectionMaker connectionMaker;   // 합성
    
    public ShipmentDaoComposition(ConnectionMaker cm) {
        this.connectionMaker = cm;   // 주입 (런타임)
    }
    
    public void add(Shipment s) throws Exception {
        Connection c = connectionMaker.makeConnection();   // 위임
        // ...
    }
}

// 효과:
// - 런타임 ConnectionMaker 교체
// - 단일 상속 제약 X
// - 부모 변경 영향 X (인터페이스 계약)
// → 다음 Phase (전략 패턴)
interface ConnectionMaker { Connection makeConnection() throws Exception; }

5.6 자기 점검 답변

"Composition over Inheritance" 원칙은?

:
1. 원칙:

  • 상속보다 합성
  1. 의미:

    • 객체 보유 (합성)
  2. :

    • 런타임 교체, 느슨
  3. 예시:

    • ConnectionMaker 보유

6️⃣ 상속(is-a) vs 합성(has-a)

6.1 관계 차이

관계 차이:

상속 (is-a):
  - "MySqlDao 는 ShipmentDao 다"
  - 종류 관계

합성 (has-a):
  - "ShipmentDao 는 ConnectionMaker 를 가진다"
  - 보유 관계

6.2 is-a

// is-a (상속)
class MySqlShipmentDao extends ShipmentDao {
    // MySqlShipmentDao IS-A ShipmentDao
}

6.3 has-a

// has-a (합성)
class ShipmentDao {
    private ConnectionMaker connectionMaker;
    // ShipmentDao HAS-A ConnectionMaker
}

6.4 선택 기준

선택 기준:

상속 (is-a):
  - 진짜 종류 관계
  - 부모 모두 물려받음

합성 (has-a):
  - 기능 사용/보유
  - 유연성 필요
  - 대부분 권장

6.5 잘못된 상속

잘못된 상속:

  코드 재사용만 위해 상속:
    - is-a 아닌데 상속
    - 강결합
    - 깨지기 쉬움

  → 합성이 맞음

6.6 ILIC 의 맥락

// is-a 판단

// "ShipmentDao 는 ConnectionMaker 인가?" → NO (is-a X)
// → 상속 부적절

// "ShipmentDao 는 ConnectionMaker 를 가지는가?" → YES (has-a)
// → 합성 적절

public class ShipmentDao {
    private final ConnectionMaker connectionMaker;   // has-a
    // ShipmentDao 가 연결 기능을 "사용" (보유)
    // 연결의 한 종류가 아님
    
    public ShipmentDao(ConnectionMaker cm) {
        this.connectionMaker = cm;
    }
}
// 연결은 기능 (has-a) → 합성이 자연스러움
interface ConnectionMaker { Connection makeConnection() throws Exception; }

6.7 자기 점검 답변

상속(is-a) vs 합성(has-a)의 차이는?

:
1. is-a:

  • 종류 관계 (상속)
  1. has-a:

    • 보유 관계 (합성)
  2. 선택:

    • 진짜 종류: 상속
    • 기능 사용: 합성
  3. 잘못된 상속:

    • 재사용만 위한 상속

7️⃣ 인터페이스로 대체하면

7.1 인터페이스 + 합성

인터페이스 + 합성:

  변하는 부분:
    - 인터페이스로 추상화
    - DAO 가 보유 (합성)
    - 주입

→ 상속 한계 극복

7.2 좋아지는 것

인터페이스로 대체하면:

1. 다중 구현
   - 단일 상속 X

2. 런타임 교체
   - 컴파일 타임 X

3. 느슨한 결합
   - 깨지기 쉬움 X

4. 테스트
   - Mock 구현

7.3 코드

// 인터페이스 + 합성
public interface ConnectionMaker {
    Connection makeConnection() throws Exception;
}

public class ShipmentDao {
    private final ConnectionMaker connectionMaker;   // 인터페이스 보유
    
    public ShipmentDao(ConnectionMaker cm) {
        this.connectionMaker = cm;   // 주입
    }
    
    public void add(Shipment s) throws Exception {
        Connection c = connectionMaker.makeConnection();
    }
}

// 구현체들
class MySqlConnectionMaker implements ConnectionMaker {
    public Connection makeConnection() { return null; }
}
class OracleConnectionMaker implements ConnectionMaker {
    public Connection makeConnection() { return null; }
}

7.4 전략 패턴 예고

전략 패턴 예고:

  인터페이스 + 합성 + 주입:
    = 전략 패턴

  - Strategy: ConnectionMaker
  - Context: ShipmentDao
  - 주입

→ Phase 6

7.5 ILIC 의 맥락

// 인터페이스 + 합성 (Phase 6 미리보기)

public interface ConnectionMaker {
    Connection makeConnection() throws Exception;
}

public class ShipmentDao {
    private final ConnectionMaker connectionMaker;
    
    public ShipmentDao(ConnectionMaker connectionMaker) {
        this.connectionMaker = connectionMaker;   // 합성 + 주입
    }
    
    public void add(Shipment shipment) throws Exception {
        Connection c = connectionMaker.makeConnection();
        // SQL...
    }
}

// 좋아진 점:
// 1. ShipmentDao 가 다른 클래스 상속 가능 (단일 상속 X)
// 2. 런타임에 ConnectionMaker 교체
// 3. ConnectionMaker 구현 변경되어도 계약 같으면 안전
// 4. Mock ConnectionMaker 로 테스트

// 고객사별 (런타임 주입)
ConnectionMaker cm = new MySqlConnectionMaker();
ShipmentDao dao = new ShipmentDao(cm);
// → 전략 패턴 (Phase 6)
class MySqlConnectionMaker implements ConnectionMaker {
    public Connection makeConnection() { return null; }
}

7.6 자기 점검 답변

상속을 인터페이스로 대체하면 좋아지는 것은?

:
1. 다중 구현:

  • 단일 상속 X
  1. 런타임 교체:

    • 컴파일 타임 X
  2. 느슨한 결합:

    • 깨지기 쉬움 X
  3. 테스트:

    • Mock

8️⃣ Phase 5 완주 정리

8.1 Phase 5 학습 종합

Phase 5 — 디자인 패턴의 적용

Unit 5.1 — 템플릿 메소드 패턴
  - 흐름(부모) + 변동(자식)
  - Phase 4.3 의 정체

Unit 5.2 — 팩토리 메소드 패턴
  - 객체 생성 위임
  - 같은 코드 두 패턴

Unit 5.3 — 두 패턴의 한계
  - 상속 단점
  - 합성으로

8.2 핵심 메시지

Phase 5 핵심 메시지:

  "Phase 4 의 리팩토링은
   템플릿/팩토리 메소드 패턴이었다.
   하지만 상속 기반이라 한계가 있고,
   인터페이스 + 합성으로 넘어가야 한다."

8.3 진화 과정

진화 과정:

추상클래스 (Phase 4.3)
    ↓ 패턴 인식
템플릿/팩토리 메소드 (Phase 5.1~5.2)
    ↓ 한계 발견
인터페이스 + 합성 (Phase 5.3 → Phase 6)

8.4 다음 Phase 예고

Phase 5 → Phase 6:
  - 상속 한계 → 인터페이스/전략

Phase 6 — OCP & 전략 패턴 (6.2 ★깊이):
  - 인터페이스로 결합도 ↓
  - OCP (개방폐쇄)
  - 전략 패턴

8.5 자기 점검 답변

Phase 5의 종합은?

:
1. 3 Unit:

  • 템플릿 메소드
  • 팩토리 메소드
  • 두 패턴 한계
  1. 메시지:

    • Phase 4 = 패턴
    • 상속 한계 → 합성
  2. 진화:

    • 추상클래스 → 패턴 → 합성
  3. 다음:

    • OCP/전략 패턴

9️⃣ 면접 + 자기 점검

9.1 면접 단골 질문 매핑

Q핵심 답변
상속 단점 3가지?단일상속/컴파일타임/깨지기쉬움
단일 상속?다른 베이스 불가
컴파일 타임?새 클래스 컴파일
깨지기 쉬움?부모 변경 → 자식 영향
Composition over Inheritance?합성 우선
is-a vs has-a?종류 vs 보유
인터페이스 대체?다중/런타임/느슨
합성 장점?유연, 교체
다음?전략 패턴
Phase 5?패턴 → 합성

9.2 자기 점검 체크리스트

상속 단점

  • 단일 상속
  • 컴파일 타임
  • 깨지기 쉬움

Composition over Inheritance

  • 원칙

is-a vs has-a

  • 차이

인터페이스 대체

  • 좋아지는 것

Phase 5

  • 종합

9.3 추가 심화 질문

Q1: 상속이 적절한 경우?

답:

  • 진짜 is-a 관계
  • 부모 전체 의미 있음
  • 안정적 부모
  • 다형성 필요 (제한적)

Q2: 위임(delegation)?

답:

  • 합성 + 메서드 위임
  • 보유 객체에 작업 넘김
  • 상속 효과 (재사용)
  • 느슨한 결합

Q3: 인터페이스 default 메서드?

답:

  • Java 8+ 인터페이스 구현
  • 다중 상속 효과 (제한적)
  • 합성과 보완
  • 공통 동작 제공

Q4: 믹스인?

답:

  • 여러 기능 조합
  • 인터페이스 + default
  • 다중 상속 대안
  • 자바는 제한적

Q5: 상속 깊이?

답:

  • 깊으면 복잡 (이해 어려움)
  • 보통 2-3 단계
  • 깊은 상속 → 합성 검토
  • 얕게 유지

🎯 핵심 요약 — 3줄 정리

1. 상속의 세 단점

  • 단일 상속 제약, 컴파일 타임 결합, 깨지기 쉬움
  • 근본 원인: 강한 결합 (컴파일 시 고정)

2. Composition over Inheritance

  • 상속(is-a, 강결합)보다 합성(has-a, 느슨) 우선
  • 변하는 부분을 객체로 보유 → 런타임 교체

3. 인터페이스 + 합성

  • 다중 구현, 런타임 교체, 느슨한 결합, 테스트 용이
  • → 전략 패턴 (Phase 6)

🏆 Phase 5 완주 — 디자인 패턴의 적용

🌱 Phase 5 — 디자인 패턴의 적용
  ✅ Unit 5.1 템플릿 메소드 패턴
  ✅ Unit 5.2 팩토리 메소드 패턴
  ✅ Unit 5.3 두 패턴의 한계 ← 여기, Phase 5 완주

→ 템플릿 메소드 (흐름/변동)
→ 팩토리 메소드 (객체 생성)
→ 상속 한계 → 합성으로

📚 다음으로...

Phase 6 — 객체지향 설계 원칙 (OCP & 전략 패턴)

Phase 6 — OCP & 전략 패턴 (6.2 ★깊이)
  Unit 6.1 — 인터페이스로 결합도 낮추기
  Unit 6.2 — OCP (개방폐쇄원칙) ★깊이
  Unit 6.3 — 전략 패턴

5주차 누적 진행

✅ Part A — 동시성 마무리 (7 Unit)
🌱 Part B — 토비의 스프링
  ✅ Phase 3 — 전통 DAO (3 Unit)
  ✅ Phase 4 — 관심사의 분리 (3 Unit)
  ✅ Phase 5 — 디자인 패턴 (3 Unit) ← 완주
  ⏭ Phase 6 — OCP & 전략 패턴 (3 Unit)

총: 16/26 Unit

🏆 Phase 5 완주 — 상속의 한계와 합성으로의 전환

profile
Software Developer

0개의 댓글