이런 분들이 읽으면 좋아요!
멋쟁이사자처럼 백엔드 자바 부트캠프가 어떻게 운영되는지 궁금한 분
Spring Framework와 Spring Boot의 차이, GoF 디자인 패턴을 처음 공부하는 분
부트캠프 합류 전, 수강생의 실제 공부 방식이 궁금한 분
배우고 잊어버리는 건 누구나 있는 일이에요. 하지만 멋쟁이사자처럼 부트캠프는 단순히 배우는 것에 그치지 않고, 배운 내용을 내 것으로 만드는 방법까지 고민하고 있어요. 그렇다면, 배운 것을 가장 효과적으로 습득하는 방법은 무엇일까요? 바로 기록하고 정리하는 시간을 갖는 거예요. 배운 내용을 정리하고 기록하면, 기억은 오래 남고 실력은 더 빠르게 쌓여 나가니까요!
멋쟁이사자처럼 부트캠프는 수강생들이 배운 내용을 정리하고 공유할 수 있도록 TIL(Today I Learned) 블로그 챌린지를 진행하고 있어요. 그래서 오늘, 강사님과 멘토님에게 배운 내용을 체계적으로 기록하고 성장하고 있는 수강생의 이야기를 가져왔어요.
오늘 소개할 수강생 TIL의 주제는 Spring Framework와 디자인 패턴이에요. 백엔드 개발의 핵심 뼈대인 Spring이란 무엇인지, Spring Boot와는 어떻게 다른지, 그리고 실무에서 반드시 마주치게 되는 GoF 디자인 패턴 23가지는 어떤 개념인지를 꼼꼼하게 정리한 수강생의 소중한 기록을 지금 확인해 보세요.
💡
이런 분들이 읽으면 좋아요!
멋쟁이사자처럼 백엔드 자바 부트캠프가 어떻게 운영되는지 궁금한 분
Spring Framework와 Spring Boot의 차이, GoF 디자인 패턴을 처음 공부하는 분
부트캠프 합류 전, 수강생의 실제 공부 방식이 궁금한 분
(51~61일 차 : Node.js 프로젝트 진행)
오픈소스 자바 엔터프라이즈 프레임워크 : Java 기반의 오픈소스 프레임워크로, 엔터프라이즈급 애플리케이션 개발을 위한 다양한 기능 제공
Java : 언어.
new 키워드로 객체를 생성한다.
**다형성(포함 관계)**이라는 강한 결합을 가진다.
객체성을 확립하고, 한다.
DB 등을 연결
결과물이 라이브러리로 도출된다.
Spring : 프레임워크.
클래스 구조를 어느 정도 만들어놓은 구현체이다.
**객체 IoC(Inversion of Control, 제어 역전)**를 관리한다.
외부에서 관계를 설정하므로 약한 결합을 가진다.
통합 솔루션 및 추상화를 제공한다.
결과물이 **서비스 객체(서비스 컴포넌트)**로 도출된다.
경량 컨테이너 : 객체 생성과 소멸을 관리하며, 싱글톤 패턴으로 메모리 효율성 보장
확장성 및 유지보수 : 모듈식 아키텍처로 대규모 애플리케이션의 확장성과 유지보수 용이
Spring의 역사와 발전
2002년, 처음 소개 되었다.
2003년, 오픈소스 프로젝트로 공개되어 전 세계 개발자 커뮤니티에 확산되었다.
2014년 ~, Spring Boot, Spring Cloud 등으로 생태계를 확장하고 있으며, 마이크로서비스 지원을 강화하고 있다.
Spring 온라인 자료
Spring 공식 문서 | Spring Framework에 대한 공식 가이드 및 레퍼런스 문서 | |
|---|---|---|
Spring Boot 문서 | Spring Boot에 특화된 문서 및 가이드 | |
Baeldung | Spring 관련 깊이 있는 튜토리얼과 예제 코드 제공 | |
Spring 블로그 | Spring 팀의 공식 블로그최신 업데이트 및 기술 정보 제공 | |
Spring 프로젝트 GitHub | Spring 프로젝트의 소스 코드 저장소 | |
InfoQ Spring 섹션 | Spring 관련 최신 트렌드와 심층 분석 아티클 | |
Spring Academy | VMware에서 제공하는 Spring 공식 교육 과정 |
Spring 개발 환경
Eclipse (STS) | Spring Tool Suite를 통한 스프링 전용 기능 제공 | IDE |
|---|---|---|
InterlliJ IDEA | Spring 프로젝트 지원이 뛰어난 통합 개발 환경 | IDE |
VSCode | 확장 프로그램을 통한 스프링 개발 지원 | 경량 에디터 |
Spring Initializr | Spring 프로젝트 생성 및 의존성 설정 도구 | 웹 서비스 |
JDOODLE | 간단한 Spring 코드 테스트 가능한 온라인 도구 | 온라인 컴파일러 |
GitPod | 브라우저에서 Spring 개발 환경 제공 | 클라우드 IDE |
구분 | Spring Framework | Spring Boot |
|---|---|---|
설정 방식 | XML 또는 Java 기반 설정 파일 필요 | 자동 설정(Auto Configuration) 지원 |
서버 구동 | 외부 서버 설정 필요(Tomcat, Jetty 등) | 내장 서버(Embedded Server) 제공 |
의존성 관리 | 각 라이브러리별 버전 관리 필요 | 스타터(Starter)를 통한 의존성 자동 관리 |
배포 방식 | WAR 파일 생성 후 웹 서버에 배포 | JAR 파일로 독립 실행 가능(Standalone) |
개발 생산성 | 초기 설정 및 환경 구성에 시간 소요 | 빠른 개발 시작과 마이크로서비스 지원 |
프로젝트 구조 | 개발자가 직접 구조 설계 필요 | 프로젝트 구조와 규칙 자동 생성 |
모니터링 | 별도 모니터링 도구 연동 필요 | Actuator를 통한 모니터링 기능 기본 제공 |
프로젝트 요구사항에 맞게 프레임워크 선택
Spring Framework 선택 시기
기존 레거시 시스템과의 통합이 필요할 때
애플리케이션 구성을 세밀하게 제어해야 할 때
특정 서버 환경에 최적화가 필요한 경우
맞춤형 설정과 구성이 중요한 대규모 엔터프라이즈 애플리케이션
Spring Boot 선택 시기
빠른 개발 및 배포가 필요한 프로젝트
마이크로서비스 아키텍처 구현 시
개발 생산성과 빠른 시작이 중요한 경우
클라우드 네이티브 애플리케이션 개발 시
최소한의 설정으로 빠르게 시작하려는 신규 프로젝트
디자인 패턴은 SW 개발 과정에서 발생하는 문제들을 해결하기 위한 검증된 솔루션이다. 크게 생성 패턴, 구조 패턴, 행위 패턴 3가지로 분류되어 있다.
GoF(Gang of Four) 디자인 패턴은 1994년 처음 소개된 23가지 디자인 패턴을 의미한다.
객체 지향 설계에서 자주 발생하는 문제들에 대한 표준화된 해결책으로, 시키고 있다.
SW 개발자들 사이에서 공통 언어를 제공하여 코드 품질, 유지보수성, 확장성을 크게 향상
Spring 프레임워크는 다양한 디자인 패턴을 기반으로 설계되었으며, 이러한 패턴을 이해하면 Spring의 내부 동작 원리를 더 깊이 파악할 수 있다.
프레임워크 이해도 향상 : Spring의 핵심 기능인 IoC, DI, AOP 등은 모두 디자인 패턴을 기반으로 구현되어 있어, 패턴을 이해하면 Spring을 더 효과적으로 활용할 수 있다.
코드 품질 개선 : 디자인 패턴을 적용하면 유지보수성, 확장성이 높은 코드를 작성할 수 있으며, Spring과의 통합이 더욱 자연스러워진다.
문제 해결 능력 강화 : Spring에서 발생하는 문제들을 디자인 패턴 관점에서 분석하면, 근본 원인을 파악하고 해결책을 도출하는 데 도움이 된다.
생성 패턴(Creational Patterns) : 객체 생성 메커니즘을 다루는 패턴으로, 객체가 생성되는 방식을 유연하게 제어하여 상황에 적합한 객체를 생성하고 있다.
구조 패턴(Structual Patterns) : 클래스와 객체를 더 큰 구조로 조합하는 방법을 다루는 패턴으로, 유연하고 효율적인 구조를 설계하고 있다.
행위 패턴(Behavioral Patterns) : 객체 간 상호작용과 책임 분배를 다루는 패턴으로, 객체 간 커뮤니케이션을 개선하고 있다.
패턴명 | 개념 | 실무 사용 예 |
|---|---|---|
추상 팩토리 | 관련된 객체들의 집합을 생성하는 인터페이스 제공 | UI 테마 시스템, DB 구현체 교체, 다양한 플랫폼 호환 컴포넌트 |
빌더 | 복잡한 객체 생성 과정과 표현 분리 | 복잡한 DTO 객체 생성, 문서 변환기, Lombok @Builder |
팩토리 메서드 | 객체 생성을 서브 클래스로 위임 | 프레임워크 API, UI 컴포넌트 생성, JDBC 드라이버 매니저 |
프로토타입 | 기존 객체를 복제하여 새로운 객체 생성 | 복잡한 객체 캐싱, 설정 복제, Java Cloneable 인터페이스 |
싱글톤 | 클래스의 인스턴스가 하나만 생성되도록 보장 | Spring Bean, DB 연결 객체, 로깅 인스턴스 |
new 연산자를 직접 사용하지 않음으로써, 객체 지향 설계의 핵심인 캡슐화와 유연성을 준수할 수 있다.
결합도 약화
new Student() 처럼 직접 new를 사용하면, 그 코드는 Student라는 구체적인 클래스와 강하게 결합된다. 이 경우, Student 대신 다른 클래스명(구체적인 클래스 등)으로 바꿔야 하는 경우, new를 썼던 모든 코드를 직접 수정해야 한다.
StudentFactory.create() 처럼 팩토리 메서드만 사용하여 만들 경우, 내부에서는 어떤 객체가 만들어졌는지 알 수 없으며, 클래스 수정이 필요할 경우엔 팩토리 메서드만 수정하면 된다.
이때 팩토리 메서드가 구체적인 클래스가 아닌 Person 같은 인터페이스를 반환하도록 설계하면, 결합도를 낮출 수 있다.
생성 로직 감춤
어떤 객체는 new만 한다고 바로 쓸 수 없고, 복잡한 설정이 필요하기도 하다. 객체를 만들 때마다 이 설정 코드를 써야 하면 중복 코드가 많아진다.
빌더 패턴을 사용해 생성 과정의 설정을 별도의 Builder 클래스에 몰아넣고, 실제 사용할 땐 build()로만 사용할 수 있다. new를 사용할 때 생성자의 인자가 많아 생길 수 있던 매개변수 순서 혼동 오류를 방지할 수 있다.
생성 정책 강제
언제든 new를 사용할 수 있다면, 클래스 당 인스턴스가 하나만 생성되도록 강제할 수 없다.
**생성자를 private**로 숨기고, getInstance() 메서드를 통해서만 객체를 만들 수 있게 하면, 시스템 전체에서 단 하나의 인스턴스만 존재함을 보장할 수 있다.
이를 통해 **제어의 역전(IoC)**을 구현할 수 있는 것이다. 직접 new를 함으로써 객체의 생명주기를 관리하는 것이 아닌, 외부(Spring 컨테이너)에 그 권한을 위임함으로써 객체 간의 결합도를 낮추고 유연한 아키텍처를 완성한다.
추상 팩토리 패턴 (Abstract Factory Pattern) : 연관된 여러 객체(제품군)를 한꺼번에 일관성 있게 생성
interfaceButton{ voidpaint(); }
interfaceCheckbox{ voidpaint(); }
// 윈도우 스타일 제품군
classWinButtonimplementsButton{ publicvoidpaint(){ System.out.println("윈도우 버튼"); } }
classWinCheckboximplementsCheckbox{ publicvoidpaint(){ System.out.println("윈도우 체크박스"); } }
// 팩토리 인터페이스
interfaceGUIFactory{
ButtoncreateButton();
CheckboxcreateCheckbox();
}
classWinFactoryimplementsGUIFactory{
public ButtoncreateButton(){ return new WinButton(); }
public CheckboxcreateCheckbox(){ return new WinCheckbox(); }
}
빌더 패턴 (Builder Pattern) : 생성자 인자가 너무 많거나, 객체 생성 단계가 복잡할 때
public classUser{
private String name; // 필수
private int age; // 선택
private String email; // 선택
public static classBuilder{
private String name;
private int age;
private String email;
publicBuilder(String name){ this.name = name; } // 필수값은 생성자로
public Builderage(int val){ age = val; return this; }
public Builderemail(String val){ email = val; return this; }
public Userbuild(){ return new User(this); }
}
privateUser(Builder builder){ /* 데이터 복사 */ }
}
// 사용 예시
User user = new User.Builder("Gemini").age(20).email("test@test.com").build();
팩토리 메서드 패턴 (Factory Method Pattern) : 객체 생성 로직을 자식 클래스에 위임해, 클라이언트가 구체적인 클래스명을 몰라도 객체를 얻도록 함
// 제품 인터페이스
interfaceLogger{ voidlog(String message); }
// 실제 제품들
classConsoleLoggerimplementsLogger{ publicvoidlog(String msg){ System.out.println("콘솔: " + msg); } }
classFileLoggerimplementsLogger{ publicvoidlog(String msg){ /* 파일 기록 로직 */ } }
// 팩토리 (추상 클래스)
abstract classLoggerFactory{
publicabstract LoggercreateLogger(); // 핵심: 생성을 서브클래스에 위임
}
classConsoleLoggerFactoryextendsLoggerFactory{
public LoggercreateLogger(){ return new ConsoleLogger(); }
}
프로토타입 패턴 (Prototype Pattern) : new로 생성하는 비용이 너무 클 때(DB 조회 등), 기존 객체 복사해서 새 객체 생성
classMonsterimplementsCloneable{
private String type;
publicMonster(String type){ this.type = type; }
@Override
public Monsterclone()throws CloneNotSupportedException{
return (Monster) super.clone(); // 메모리 복사 방식
}
}
싱글톤 패턴(Singleton Pattern) : 시스템 전체에서 인스턴스가 딱 하나만 존재해야 할 때(설정 관리자, DB 커넥션 풀 등)
Spring에서의 활용 : Spring 컨테이너(IoC 컨테이너)는 Bean을 기본적으로 싱글톤 범위로 관리한다. 매번 객체를 생성하는 메모리 낭비를 줄이고, 공유 객체를 효율적으로 사용한다.
public classSingleton{
// 1. 유일한 인스턴스를 저장할 정적 변수
private static Singleton instance;
// 2. 생성자를 private으로 선언하여 외부 생성을 차단
privateSingleton(){}
// 3. 외부에서 인스턴스를 가져올 수 있는 유일한 메서드
publicstatic SingletongetInstance(){
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
// Spring 환경에서는 직접 구현할 필요 없이 @Component 등으로 선언하면
// 컨테이너가 알아서 싱글톤으로 관리
패턴명 | 개념 | 실무 사용 예 |
|---|---|---|
컴포지트 | 객체들의 관계를 트리 구조로 구성 | 파일 시스템, UI 컴포넌트 계층 구조 |
플라이웨이트 | 공유를 통해 많은 객체를 효율적으로 지원 | 문자열 풀, 캐시 시스템 |
어댑터 | 호환되지 않는 인터페이스를 함께 동작하도록 변환 | 레거시 시스템 통합, 외부 라이브러리 연동 |
데코레이터 | 객체에 동적으로 책임 추가 | Java I/O 스트림, 웹 요청 필터 |
퍼사드 | 복잡한 서브시스템에 단순화된 인터페이스 제공 | API 게이트웨이, 서비스 레이어 |
프록시 | 다른 객체에 대한 접근을 제어하는 대리자 제공 | Spring AOP, 지연 로딩, 캐싱 |
브리지 | 구현부와 추상층을 분리하여 독립적 변형 가능 | 디바이스 드라이버, 다양한 플랫폼 지원 GUI |
컴포지트 패턴 (Composite Pattern) : 단일 객체와 복합 객체를 동일하게 취급하여 트리 구조 형성 (파일 시스템 등)
interfaceNode{ voidinfo(); }
classFileimplementsNode{
publicvoidinfo(){ System.out.println("파일입니다."); }
}
classFolderimplementsNode{
private List<Node> children = new ArrayList<>();
publicvoidadd(Node node){ children.add(node); }
publicvoidinfo(){
System.out.println("폴더 안의 내용:");
for (Node node : children) node.info(); // 재귀적 호출
}
}
플라이웨이트 패턴 (Flyweight Pattern) : 공통 상태를 공유하여 메모리 사용량 최소화
classTreeType{ // 공유되는 부분 (이름, 색상 등)
private String name, color;
publicTreeType(String name, String color){ ... }
}
classTreeFactory{
private static Map<String, TreeType> types = new HashMap<>();
publicstatic TreeTypegetTreeType(String name, String color){
if (!types.containsKey(name)) types.put(name, new TreeType(name, color));
return types.get(name);
}
}
어댑터 패턴 (Adapter) : 호환되지 않는 인터페이스를 가진 객체들이 협력할 수 있도록 중간에서 맞춰줌
// 구형 프린터 (Legacy)
classLegacyPrinter{
voidoldPrint(){ System.out.println("구형 방식으로 출력합니다."); }
}
// 우리가 기대하는 인터페이스
interfacePrinter{ voidprint(); }
// 어댑터: 구형 프린터를 현대적 인터페이스에 맞게 변환
classPrinterAdapterimplementsPrinter{
private LegacyPrinter legacyPrinter = new LegacyPrinter();
@Override
publicvoidprint(){
legacyPrinter.oldPrint(); // 내부적으로 구형 메서드 호출
}
}
데코레이터 패턴 (Decorator Pattern) : 객체에 동적으로 새로운 책임 추가 (상속을 통한 확장보다 유연)
interfaceCoffee{ StringgetDesc(); }
classEspressoimplementsCoffee{ public StringgetDesc(){ return "에스프레소"; } }
// 데코레이터의 추상 클래스
abstract classCoffeeDecoratorimplementsCoffee{
protected Coffee decoratedCoffee;
publicCoffeeDecorator(Coffee coffee){ this.decoratedCoffee = coffee; }
}
classMilkextendsCoffeeDecorator{
publicMilk(Coffee coffee){ super(coffee); }
public StringgetDesc(){ return decoratedCoffee.getDesc() + " + 우유"; }
}
퍼사드 패턴 (Facade Pattern) : 복잡한 서브 시스템들에 대해 단순화된 하나의 인터페이스 제공
classComputer{
publicvoidstart(){
cpu.freeze();
memory.load();
cpu.execute();
System.out.println("컴퓨터 부팅 완료!");
}
}
프록시 패턴(Proxy Pattern) : 실제 객체에 대한 접근을 제어하거나 부가 기능 수행하는 대리자
Spring에서의 활용 : Spring AOP(Aspect Oriented Programming)의 핵심이다. 트랜잭션 처리(@Transactional), 로깅, 보안 체크 등을 수행할 때 실제 서비스 객체 앞단에 프록시 객체를 두어 부가 기능을 실행한다.
// 1. 공통 인터페이스
interfaceSubject{
voidrequest();
}
// 2. 실제 객체 (핵심 비즈니스 로직)
classRealSubjectimplementsSubject{
publicvoidrequest(){ System.out.println("실제 업무 수행 중..."); }
}
// 3. 프록시 객체 (부가 기능 추가)
classProxySubjectimplementsSubject{
private final RealSubject realSubject = new RealSubject();
publicvoidrequest(){
System.out.println(">> 보안 체크 및 로그 시작"); // 부가 기능
realSubject.request(); // 실제 업무 위임
System.out.println(">> 로그 종료 및 결과 반환"); // 부가 기능
}
}
브리지 패턴 (Bridge Pattern) : 추상적인 부분과 실제 구현 부분을 독립적으로 확장할 수 있도록 분리
// 구현부 (색상)
interfaceColor{ voidapply(); }
classRedimplementsColor{ publicvoidapply(){ System.out.println("빨간색"); } }
// 추상부 (도형) - 구현부를 Has-a 관계로 가짐
abstract classShape{
protected Color color;
publicShape(Color color){ this.color = color; }
abstractvoiddraw();
}
classCircleextendsShape{
publicCircle(Color color){ super(color); }
publicvoiddraw(){ System.out.print("동그라미에 "); color.apply(); }
}
패턴명 | 개념 | 실무 사용 예 |
|---|---|---|
전략 | 알고리즘(행위)을 정의하고 각각을 캡슐화하여 동적으로 교체 가능하게 만듦 | 정렬 알고리즘, 결제 시스템, 압축 방식 |
옵저버 | 객체 상태 변경 시 의존 객체들에게 자동으로 통지 | 이벤트 처리 시스템, MVC 아키텍처, 데이터 바인딩 |
중재자 | 객체 간 상호작용을 캡슐화하는 객체를 정의 | 채팅 시스템, 항공 교통 제어, UI 컨트롤러 |
방문자 | 객체 구조의 요소들을 변경하지 않고 새로운 연산을 추가할 수 있도록 함 | 문서 트리 처리, AST 순회, 보고서 생성 |
이터레이터 | 컬렉션 내부 구조 노출하지 않고 요소에 순차적으로 접근하는 방법 제공 | Java 컬렉션 프레임워크, JDBC ResultSet, DOM NodeList |
상태 | 객체 내부 상태에 따라 행위 변경할 수 있도록 함 | 게임 캐릭터 상태, 주문 처리 흐름, 문서 승인 프로세스 |
인터프리터 | 언어의 문법 표현을 정의하고 해당 언어로 된 문장 해석 | SQL 파서, 정규식 엔진, 수식 계산기 |
메멘토 | 객체 내부 상태 저장하고 이전 상태로 복원할 수 있도록 함 | 트랜잭션 롤백, 실행 취소 기능, 게임 상태 저장 |
커맨드 | 요청을 객체로 캡슐화하여 클라이언트와 수신자 분리 | 트랜잭션 처리, 작업 큐, 메뉴 시스템, 명령어 실행 취소 |
책임 연쇄 | 요청을 처리할 수 있는 객체가 여러 개일 때 그 객체들을 연결하여 책임을 떠넘김 | 예외 처리 체인, 이벤트 버블링, 서블릿 필터 |
템플릿 메서드 | 알고리즘의 구조를 정의하고 일부 단계를 하위 클래스에서 구현하도록 함 | 프레임워크 훅 메서드, JUnit 테스트, 데이터 처리 파이프라인 |
전략 패턴(Strategy Pattern) : 동일 계열 알고리즘 정의, 각각 캡슐화하여 런타임에서 교체 가능
Spring에서의 활용 : Spring의 DI(의존성 주입). 서비스 계층이 인터페이스에만 의존하게 하고, 실제 구현체(전략)는 외부에서 주입받아 사용한다.
// 1. 전략 인터페이스 (알고리즘의 추상화)
interfacePaymentStrategy{
voidpay(int amount);
}
// 2. 구체적인 전략들
classCardPaymentimplementsPaymentStrategy{
publicvoidpay(int amount){ System.out.println("카드 결제: " + amount); }
}
classCashPaymentimplementsPaymentStrategy{
publicvoidpay(int amount){ System.out.println("현금 결제: " + amount); }
}
// 3. 전략을 사용하는 컨텍스트 (Spring의 Service 느낌)
classOrderService{
private PaymentStrategy strategy;
// 의존성 주입(DI)을 통해 전략을 설정
publicvoidsetPaymentStrategy(PaymentStrategy strategy){
this.strategy = strategy;
}
publicvoidprocessOrder(int amount){
strategy.pay(amount);
}
}
옵저버 패턴 (Observer Pattern) : 한 객체 상태 변하면 그 객체 의존하는 다른 객체들에게 자동 통지
interfaceObserver{ voidupdate(String msg); }
classSubject{
private List<Observer> observers = new ArrayList<>();
publicvoidnotifyAll(String msg){ observers.forEach(o -> o.update(msg)); }
}
중재자 패턴 (Mediator Pattern) : 객체 간 복잡한 상호작용을 중재자 객체에 캡슐화하여 객체들이 직접 통신하지 않도록 함
classChatRoom{ // 중재자
publicstaticvoidshowMessage(User user, String message){
System.out.println(user.getName() + ": " + message);
}
}
방문자 패턴 (Visitor Pattern) : 객체 구조 변경하지 않고 새로운 연산 추가
interfaceComputerPart{ voidaccept(ComputerPartVisitor visitor); }
classMouseimplementsComputerPart{
publicvoidaccept(ComputerPartVisitor v){ v.visit(this); }
}
이터레이터 패턴 (Iterator Pattern) : 컬렉션 내부 구조 노출하지 않고 요소들에 순차 접근
interfaceIterator{ booleanhasNext(); Objectnext(); }
classNameRepository{
public String names[] = {"Robert" , "John"};
public IteratorgetIterator(){ return new NameIterator(); }
// 내부적으로 Iterator 구현...
}
상태 패턴 (State Pattern) : 객체 내부 상태에 따라 스스로 행동 변경
interfaceState{ voiddoAction(Context context); }
classStartStateimplementsState{
publicvoiddoAction(Context context){
System.out.println("시작 상태입니다.");
context.setState(this);
}
}
인터프리터 패턴 (Interpreter Pattern) : 특정 언어 문법 정의, 해석하는 처리기 (SQL 파서, 수식 계산기 등)
interfaceExpression{ booleaninterpret(String context); }
classTerminalExpressionimplementsExpression{
private String data;
publicTerminalExpression(String data){ this.data = data; }
publicbooleaninterpret(String context){ return context.contains(data); }
}
메멘토 패턴 (Memento Pattern) : 객체 상태 저장해두었다가 나중에 복구할 수 있게 함 (Undo)
classMemento{
private String state;
publicMemento(String state){ this.state = state; }
public StringgetState(){ return state; }
}
커맨드 패턴 (Command Pattern) : 요청을 객체 형태로 캡슐화, 사용자가 보낸 요청 나중에 이용 or 로그 기록 or Undo
interfaceCommand{ voidexecute(); }
classLightOnCommandimplementsCommand{
private Light light;
publicLightOnCommand(Light light){ this.light = light; }
publicvoidexecute(){ light.turnOn(); }
}
책임 연쇄 패턴 (Chain of Responsibility Pattern) : 요청을 처리할 수 있는 객체들을 체인으로 연결, 요청 처리할 때까지 다음 객체로 전달
abstract classHandler{
protected Handler next;
publicvoidsetNext(Handler next){ this.this.next = next; }
publicabstractvoidhandle(String request);
}
classAuthHandlerextendsHandler{
publicvoidhandle(String req){
if (req.equals("auth")) System.out.println("인증 완료");
else if (next != null) next.handle(req);
}
}
템플릿 메서드 패턴(Template Method Pattern) : 알고리즘의 구조(뼈대)는 부모 클래스에 정의하고, 세부 단계는 자식 클래스에서 구현
Spring에서의 활용 : Spring이 제공하는 다양한 Template 클래스(JdbcTemplate, RestTemplate)의 구조가 된다. 반복되는 작업(DB 연결, 자원 해제 등)은 부모가 처리하고, 핵심 로직(SQL 실행 등)만 하위 클래스나 콜백이 담당한다.
공부는 배울 때 끝나는 게 아니라, 되새기고 활용할 때 완성돼요.
그런 의미에서 오늘 소개한 이야기는 단순한 공부 기록이 아니에요. Spring이라는 거대한 프레임워크를 처음 마주했을 때의 막막함을 기록으로 이겨내고, 디자인 패턴이라는 추상적인 개념을 실무 예시와 연결해 자신의 것으로 만들어가는 과정이었으니까요.
여러분도 오래 기억하고 싶은 내용이 있다면, 배운 내용을 정리하고, 더 오래 기억하는 습관을 만들어 보세요. 작은 차이가 결국 큰 결과를 만들 테니까요!
내가 배운 것을 글로 정리하는 것이 처음에는 어렵게 느껴질 수도 있지만, 멋쟁이사자처럼과 함께 꾸준히 기록하다 보면 스스로 변화하고 있다는 걸 깨닫게 될 거예요.
자 이제 여러분 차례예요. 언제나 여러분의 곁에는 멋쟁이사자처럼이 있으니 고민하지 말고 배움을 기록하고, 성장의 발자취를 남겨보세요!