F-LAB JAVA · 5주차 · Phase 5 · 디자인 패턴의 적용
이 Unit을 끝내면 다음을 답할 수 있어야 한다.
팩토리 메소드 패턴은 객체 생성을 서브클래스에 위임하는 패턴으로, Phase 4.3 의 getConnection() 은 "어떤 Connection 을 만들지 결정" 하므로 팩토리 메소드이며, 같은 코드가 관점에 따라 템플릿 메소드 패턴이면서 동시에 팩토리 메소드 패턴으로 해석된다.
팩토리 메소드는 객체를 생성하는 메서드를 추상화하여, 부모는 "객체가 필요하다" 는 사실만 알고 어떤 구체 객체를 만들지는 서브클래스가 결정 하게 한다.
Phase 4.3 의getConnection()은 Connection 객체를 생성하는데, 어떤 종류 (MySQL·Oracle) 의 Connection 을 만들지 서브클래스가 결정하므로 객체 생성을 서브클래스에 위임 하는 팩토리 메소드다.
흥미롭게도 같은 코드가 두 패턴으로 해석된다 — "기본 흐름 + 변하는 부분" 관점에서는 템플릿 메소드, "객체 생성을 서브클래스가 결정" 관점에서는 팩토리 메소드다.
Spring 의BeanFactory이름에 "Factory" 가 붙은 것도 같은 맥락 — 빈 (객체) 의 생성을 책임지는 팩토리 역할을 하기 때문이다.
같은 코드, 두 패턴 = 착시 그림:
같은 그림이 두 가지로 보임:
- 어떻게 보면 토끼
- 어떻게 보면 오리
Phase 4.3 의 getConnection:
- 흐름 관점: 템플릿 메소드
"흐름은 부모, 빈칸은 자식"
- 생성 관점: 팩토리 메소드
"객체 생성을 자식이 결정"
팩토리 메소드 (생성 위임):
- 부모: "Connection 이 필요해"
- 자식: "MySQL Connection 만들게"
"Oracle Connection 만들게"
→ 객체 만드는 책임을 자식에게
BeanFactory:
- 빈(객체) 만드는 공장
- "Factory" = 객체 생성 담당
→ 팩토리 메소드 = 객체 생성을 서브클래스에 위임, 같은 코드가 두 패턴으로.
1. 팩토리 메소드 패턴의 정의
2. 객체 생성 위임
3. getConnection이 팩토리 메소드
4. 같은 코드, 두 패턴
5. 두 패턴의 관점 차이
6. 팩토리 메소드 구조
7. 단순 팩토리 vs 팩토리 메소드
8. BeanFactory의 Factory
9. 면접 + 자기 점검
팩토리 메소드 패턴:
객체 생성을 서브클래스에 위임.
- 부모: 객체 필요 (어떤 건 모름)
- 자식: 구체 객체 생성 결정
GoF 디자인 패턴:
생성 패턴 (Creational):
- 객체 생성 추상화
"객체 생성 인터페이스 정의,
인스턴스화는 서브클래스가"
의도:
- 객체 생성 분리
- 구체 클래스 의존 ↓
- 확장 (새 객체 = 새 서브클래스)
- 생성 로직 캡슐화
// 팩토리 메소드 패턴
public abstract class ShipmentDao {
public void add(Shipment s) throws Exception {
Connection c = getConnection(); // 팩토리 메소드 호출
// 어떤 Connection? 자식이 만듦
}
// 팩토리 메소드 (객체 생성을 자식이)
protected abstract Connection getConnection() throws Exception;
}
// 자식이 구체 Connection 생성 결정
class MySqlShipmentDao extends ShipmentDao {
protected Connection getConnection() throws Exception {
// MySQL Connection 생성 (팩토리)
return DriverManager.getConnection(
"jdbc:mysql://localhost/ilic", "root", "password");
}
}
팩토리 메소드 패턴의 정의는?
답:
1. 정의:
GoF:
의도:
부모/자식:
객체 생성 위임:
부모:
- 객체 사용 (생성 X)
- "이 객체가 필요해"
자식:
- 객체 생성
- "이렇게 만들어"
부모는 추상 타입:
부모는 인터페이스/추상에 의존:
- Connection (인터페이스)
- 구체 (MySQL Connection) 모름
→ 구체 클래스 분리
생성 캡슐화:
객체 생성 로직:
- 팩토리 메소드 안
- 캡슐화
사용처:
- new 직접 X
- 팩토리 메소드 호출
new 의 문제:
직접 new:
- 구체 클래스 의존
- 강한 결합
팩토리 메소드:
- 생성 분리
- 결합 ↓
// 객체 생성 위임
// ❌ 직접 new (강한 결합)
public class ShipmentDaoBad {
public void add(Shipment s) throws Exception {
// 구체 클래스 직접 생성 (결합)
Connection c = DriverManager.getConnection(
"jdbc:mysql://localhost/ilic", "root", "password");
// MySQL 에 묶임
}
}
// ✓ 팩토리 메소드 (생성 위임)
public abstract class ShipmentDaoGood {
public void add(Shipment s) throws Exception {
Connection c = getConnection(); // 위임
// 구체 모름
}
// 생성을 자식에게 위임
protected abstract Connection getConnection() throws Exception;
}
객체 생성을 서브클래스에 위임하는 의미는?
답:
1. 위임:
부모:
캡슐화:
new 문제:
getConnection 이 팩토리 메소드:
getConnection():
- Connection 객체 생성
- "어떤 Connection 만들지" 결정
- 자식이 구체 결정
→ 객체 생성 위임 = 팩토리 메소드
생성하는 객체:
getConnection 의 반환:
- Connection (추상)
- 구체: MySQL/Oracle Connection
→ 객체를 만들어 반환
→ 팩토리
// 서브클래스가 어떤 Connection 만들지 결정
class MySqlShipmentDao extends ShipmentDao {
protected Connection getConnection() {
// MySQL Connection 생성
return null;
}
}
class OracleShipmentDao extends ShipmentDao {
protected Connection getConnection() {
// Oracle Connection 생성
return null;
}
}
// 같은 getConnection, 다른 객체 생성
팩토리 메소드 관점:
getConnection:
- 이름은 "get" 이지만
- 실제로 Connection 생성
- 어떤 구체 생성? 자식
→ 본질은 팩토리 메소드
// getConnection = 팩토리 메소드 관점
public abstract class ShipmentDao {
public void add(Shipment s) throws Exception {
// 팩토리 메소드로 Connection 객체 획득
Connection c = getConnection();
// ShipmentDao 는 어떤 구체 Connection 인지 모름
}
// 팩토리 메소드 — Connection 객체 생성 위임
protected abstract Connection getConnection() throws Exception;
}
// 각 자식이 구체 Connection 객체 생성
class CustomerAShipmentDao extends ShipmentDao {
protected Connection getConnection() throws Exception {
// 고객사 A 의 Connection 객체 생성 (MySQL)
return DriverManager.getConnection(
"jdbc:mysql://customerA/ilic", "userA", "passA");
}
}
// getConnection 이 객체 생성을 책임 → 팩토리 메소드
getConnection이 팩토리 메소드인 이유는?
답:
1. 이유:
생성 객체:
서브클래스 결정:
본질:
같은 코드 = 두 패턴:
Phase 4.3 의 코드:
템플릿 메소드 관점:
- 흐름(부모) + 변동(자식)
팩토리 메소드 관점:
- 객체 생성을 자식이 결정
add 메서드 관점 (템플릿 메소드):
add():
- 연결 → SQL → 해제 (흐름)
- getConnection 만 자식
- = 템플릿 메소드
getConnection 관점 (팩토리 메소드):
getConnection():
- Connection 객체 생성
- 자식이 구체 결정
- = 팩토리 메소드
동시 성립:
add (템플릿) 안에서
getConnection (팩토리) 호출
→ 한 코드가 두 패턴
→ 관점의 차이
public abstract class ShipmentDao {
// [템플릿 메소드 관점]
// add = 변하지 않는 흐름 (템플릿 메서드)
public void add(Shipment s) throws Exception {
Connection c = getConnection(); // [팩토리 메소드 호출]
PreparedStatement ps = c.prepareStatement("insert ...");
ps.executeUpdate();
ps.close(); c.close();
// add: 흐름 고정 → 템플릿 메소드
}
// [팩토리 메소드 관점]
// getConnection = Connection 객체 생성 위임 (팩토리 메소드)
protected abstract Connection getConnection() throws Exception;
}
// 같은 코드:
// - add 를 보면 → 템플릿 메소드 패턴
// - getConnection 을 보면 → 팩토리 메소드 패턴
같은 코드가 두 패턴으로 해석되는 이유는?
답:
1. 두 패턴:
add 관점:
getConnection 관점:
동시:
관점 차이:
템플릿 메소드:
- "흐름의 일부를 자식이"
- 알고리즘 골격
- 행위 패턴
팩토리 메소드:
- "객체 생성을 자식이"
- 객체 생성
- 생성 패턴
강조점:
템플릿 메소드:
- 전체 흐름 강조
- getConnection 은 일부
팩토리 메소드:
- 객체 생성 강조
- getConnection 이 핵심
| 항목 | 템플릿 메소드 | 팩토리 메소드 |
|---|---|---|
| GoF 분류 | 행위 | 생성 |
| 강조 | 흐름 | 객체 생성 |
| 추상 메서드 | 흐름 일부 | 객체 생성 |
| 관점 | 알고리즘 | 인스턴스화 |
실제 관계:
팩토리 메소드는
템플릿 메소드의 특수 형태로 봄:
- 템플릿 메소드의 추상 메서드가
- 객체 생성이면
- 팩토리 메소드
public abstract class ShipmentDao {
public void add(Shipment s) throws Exception {
Connection c = getConnection();
// ...
}
protected abstract Connection getConnection() throws Exception;
}
// 관점 1: 템플릿 메소드
// - add 의 흐름이 핵심
// - getConnection 은 흐름의 한 단계
// 관점 2: 팩토리 메소드
// - getConnection 의 객체 생성이 핵심
// - Connection 인스턴스화를 자식이
// 두 관점 모두 유효 (같은 코드)
템플릿 메소드 vs 팩토리 메소드의 관점 차이는?
답:
1. 관점:
GoF:
강조:
관계:
팩토리 메소드 구조:
[Creator (추상)]
- factoryMethod() (추상)
- someOperation() (팩토리 사용)
↑
[ConcreteCreator]
- factoryMethod() 구현
↓ 생성
[Product]
4가지 요소:
1. Product (제품 인터페이스)
- Connection
2. ConcreteProduct (구체 제품)
- MySQL Connection
3. Creator (추상 생성자)
- ShipmentDao
4. ConcreteCreator (구체 생성자)
- MySqlShipmentDao
| 요소 | ILIC |
|---|---|
| Product | Connection |
| ConcreteProduct | MySQL/Oracle Connection |
| Creator | ShipmentDao (추상) |
| ConcreteCreator | MySqlShipmentDao |
| factoryMethod | getConnection |
// Creator (추상)
public abstract class ShipmentDao {
// factoryMethod
protected abstract Connection getConnection() throws Exception;
// 팩토리 메소드 사용
public void add(Shipment s) throws Exception {
Connection c = getConnection(); // Product 획득
}
}
// ConcreteCreator
class MySqlShipmentDao extends ShipmentDao {
protected Connection getConnection() throws Exception {
return DriverManager.getConnection(...); // ConcreteProduct
}
}
// 팩토리 메소드 구조 (ILIC)
// Product: Connection (JDBC 인터페이스)
// Creator (추상)
public abstract class ShipmentDao {
// factoryMethod
protected abstract Connection getConnection() throws Exception;
public void add(Shipment shipment) throws Exception {
Connection c = getConnection(); // 팩토리 메소드 사용
// ...
}
}
// ConcreteCreator 들
class MySqlShipmentDao extends ShipmentDao { // ConcreteCreator
protected Connection getConnection() throws Exception {
return DriverManager.getConnection( // ConcreteProduct (MySQL)
"jdbc:mysql://localhost/ilic", "root", "password");
}
}
class OracleShipmentDao extends ShipmentDao { // ConcreteCreator
protected Connection getConnection() throws Exception {
return DriverManager.getConnection( // ConcreteProduct (Oracle)
"jdbc:oracle:thin:@localhost:1521:ilic", "ilic", "pass");
}
}
팩토리 메소드의 구조는?
답:
1. 4요소:
매핑:
factoryMethod:
구조:
단순 팩토리 (Simple Factory):
하나의 팩토리 클래스/메서드:
- 조건 분기로 생성
- if-else / switch
엄밀히는 패턴 X (관용구)
// 단순 팩토리 (분기)
public class ConnectionFactory {
public static Connection create(String dbType) {
if (dbType.equals("mysql")) {
return mysqlConnection();
} else if (dbType.equals("oracle")) {
return oracleConnection();
}
// 새 DB → 이 메서드 수정 (OCP X)
throw new IllegalArgumentException();
}
}
// 팩토리 메소드 (서브클래스)
public abstract class ShipmentDao {
protected abstract Connection getConnection(); // 서브클래스가
}
// 새 DB → 새 서브클래스 (OCP 향)
| 항목 | 단순 팩토리 | 팩토리 메소드 |
|---|---|---|
| 생성 | 분기 (if-else) | 서브클래스 |
| 확장 | 메서드 수정 | 서브클래스 추가 |
| OCP | 위반 | 부분 준수 |
| GoF | X (관용구) | O (패턴) |
// 단순 팩토리 (분기 — OCP X)
public class ConnectionFactory {
public static Connection create(String type) throws Exception {
return switch (type) {
case "mysql" -> DriverManager.getConnection(
"jdbc:mysql://localhost/ilic", "root", "pass");
case "oracle" -> DriverManager.getConnection(
"jdbc:oracle:thin:@localhost:1521:ilic", "ilic", "pass");
default -> throw new IllegalArgumentException();
// 새 DB → 여기 수정
};
}
}
// 팩토리 메소드 (서브클래스 — OCP 향)
public abstract class ShipmentDao {
protected abstract Connection getConnection() throws Exception;
// 새 DB → 새 서브클래스 (수정 X)
}
단순 팩토리 vs 팩토리 메소드의 차이는?
답:
1. 단순 팩토리:
팩토리 메소드:
확장:
OCP:
Spring BeanFactory:
빈(객체)을 생성·관리하는 팩토리:
- getBean() → 객체 반환
- 객체 생성 책임
"Factory" = 객체 생성 담당
BeanFactory 빈 생성:
getBean("shipmentDao"):
- 빈 정의 확인
- 객체 생성
- 의존성 주입
- 반환
→ 객체 팩토리
팩토리 정신:
팩토리 메소드:
- 객체 생성 분리/위임
BeanFactory:
- 모든 빈 생성 담당
- 객체 생성을 컨테이너가
→ 같은 정신 (생성 분리)
IoC 로 발전:
팩토리 메소드:
- 객체 생성을 서브클래스가
BeanFactory (IoC 컨테이너):
- 객체 생성을 컨테이너가
- 더 발전된 형태
→ Phase 7~8 에서
// 팩토리 메소드 (Phase 5) → BeanFactory (Phase 8)
// 팩토리 메소드: 서브클래스가 생성
public abstract class ShipmentDao {
protected abstract Connection getConnection();
}
// BeanFactory: 컨테이너가 생성 (Phase 8 미리보기)
@Configuration
public class DaoFactory {
@Bean
public ShipmentDao shipmentDao() {
return new ShipmentDao(connectionMaker()); // 컨테이너가 생성
}
@Bean
public ConnectionMaker connectionMaker() {
return new MySqlConnectionMaker();
}
}
// ApplicationContext ctx = ...;
// ShipmentDao dao = ctx.getBean("shipmentDao", ShipmentDao.class);
// → 객체 생성을 컨테이너(Factory)가 담당
// → 팩토리 메소드의 발전된 형태
interface ConnectionMaker { Connection makeConnection(); }
class MySqlConnectionMaker implements ConnectionMaker {
public Connection makeConnection() { return null; }
}
Spring BeanFactory의 Factory와의 관련은?
답:
1. BeanFactory:
빈 생성:
팩토리 정신:
발전:
| Q | 핵심 답변 |
|---|---|
| 팩토리 메소드? | 객체 생성 서브클래스 위임 |
| 객체 생성 위임? | 부모 사용, 자식 생성 |
| getConnection? | Connection 생성 (팩토리) |
| 같은 코드 두 패턴? | 흐름(템플릿)/생성(팩토리) |
| 관점 차이? | 흐름 vs 객체 생성 |
| 구조? | Creator/Product |
| 단순 vs 메소드? | 분기 vs 서브클래스 |
| BeanFactory? | 빈 생성 팩토리 |
| 장점? | 생성 분리, 확장 |
| IoC 발전? | 컨테이너 생성 |
답:
답:
답:
답:
답:
1. 팩토리 메소드 패턴
2. 같은 코드, 두 패턴
3. BeanFactory
이번 Unit에서 팩토리 메소드를 봤다면, 다음은 두 패턴의 한계 (Phase 5 마지막).
🌱 Phase 5 — 디자인 패턴의 적용
✅ Unit 5.1 템플릿 메소드 패턴
✅ Unit 5.2 팩토리 메소드 패턴 ← 여기
⏭ Unit 5.3 두 패턴의 한계 — Phase 5 완주
✅ Part A — 동시성 마무리 (7 Unit)
🌱 Part B — 토비의 스프링
✅ Phase 3 — 전통 DAO (3 Unit)
✅ Phase 4 — 관심사의 분리 (3 Unit)
🌱 Phase 5 — 디자인 패턴 (2/3 진행)
총: 15/26 Unit