자바 Java
17. Java 디자인 패턴 – 싱글톤, 팩토리, 전략 패턴 등
안녕하세요! 태마입니다.
Java 기초 강좌입니다.
강좌의 경우
1. 주제 간단 정리
2. 상세 주제 정리
으로 이루어져 있습니다.
자바 Java
포스팅 시작하겠습니다 :)
1. 주제 간단 정리
1. 디자인 패턴(Design Pattern) 개념
디자인 패턴은 소프트웨어 설계 시 발생할 수 있는 문제에 대한 해결책을 일반화하여 제공하는 재사용 가능한 솔루션입니다.
✔ 디자인 패턴은 다양한 상황에 맞는 해결책을 제공하고, 코드의 재사용성을 높이며, 유지보수를 용이하게 만듭니다.
✔ 디자인 패턴은 문제의 유형과 해결 방법을 구체화한 것입니다.
📌 디자인 패턴의 주요 장점
✔ 재사용성 : 패턴을 사용하면 이미 검증된 해결책을 반복적으로 활용
✔ 유지보수 용이성 : 일관된 설계 방식을 통해 코드 수정과 확장이 쉬움
✔ 표준화된 해결책 : 여러 개발자들이 이해할 수 있는 표준화된 방법 제공
2. 디자인 패턴의 분류
디자인 패턴은 세 가지 주요 카테고리로 나눌 수 있습니다.
- 생성 패턴(Creational Patterns) : 객체 생성에 관한 패턴
- 구조 패턴(Structural Patterns) : 클래스와 객체의 구조에 관한 패턴
- 행위 패턴(Behavioral Patterns) : 객체 간 상호작용과 책임에 관한 패턴
📌 생성 패턴은 객체 생성 방법을 최적화하고, 구조 패턴은 객체 간 관계를 최적화하며, 행위 패턴은 객체 간의 상호작용을 최적화하는 데 사용됩니다.
3. 디자인 패턴 사용 시 주의점
디자인 패턴은 매우 유용하지만, 무분별한 사용은 복잡성을 증가시킬 수 있습니다.
✔ 패턴을 사용하기 전에 문제의 성격과 어떤 패턴이 적합한지 잘 판단해야 합니다.
✔ 단순한 문제에 복잡한 패턴을 적용하면 오히려 유지보수성이 떨어질 수 있습니다.
📌 디자인 패턴은 항상 필요한 경우에만 사용하는 것이 좋습니다.
2. 상세 주제 정리
1. 싱글톤 패턴(Singleton Pattern)
싱글톤 패턴은 애플리케이션에서 단 하나의 인스턴스만 존재하도록 보장하는 패턴입니다.
✔ 주로 애플리케이션의 설정 정보나 로그 처리, 데이터베이스 연결을 위한 객체에 사용됩니다.
✔ 인스턴스를 한 번만 생성하고, 이후에는 생성된 인스턴스를 재사용합니다.
✅ 싱글톤 패턴 구현 예제
public class Singleton {
private static Singleton instance;
private Singleton() {} // 생성자를 private로 선언하여 외부에서 인스턴스를 생성할 수 없도록 함.
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
📌 getInstance() 메서드는 인스턴스가 없을 때만 생성하며, 동일 인스턴스를 재사용.
2. 팩토리 패턴(Factory Pattern)
팩토리 패턴은 객체를 생성하는 인터페이스를 제공하고, 그 구현을 서브클래스에서 맡는 패턴입니다.
✔ 팩토리 패턴은 객체 생성 로직을 클라이언트 코드와 분리하여, 객체 생성을 보다 유연하고 확장 가능하게 만듭니다.
✔ 팩토리 메서드를 사용하면 객체의 생성 과정을 숨기고 클라이언트가 이를 사용할 수 있도록 합니다.
✅ 팩토리 패턴 구현 예제
// 제품 인터페이스
interface Product {
void create();
}
// 구체적인 제품 클래스
class ConcreteProductA implements Product {
public void create() {
System.out.println("Product A created.");
}
}
class ConcreteProductB implements Product {
public void create() {
System.out.println("Product B created.");
}
}
// 팩토리 클래스
class ProductFactory {
public Product createProduct(String type) {
if ("A".equals(type)) {
return new ConcreteProductA();
} else if ("B".equals(type)) {
return new ConcreteProductB();
}
return null;
}
}
📌 팩토리 클래스는 객체의 생성 로직을 숨기고, 클라이언트 코드에서 직접 객체를 생성하지 않도록 함.
3. 전략 패턴(Strategy Pattern)
전략 패턴은 동적으로 알고리즘을 교체할 수 있도록 하는 패턴입니다.
✔ 다양한 알고리즘을 인터페이스로 정의하고, 실행 시 동적으로 선택하여 사용할 수 있게 합니다.
✔ 알고리즘을 클래스별로 캡슐화하고, 클라이언트가 사용할 알고리즘을 동적으로 선택할 수 있도록 만듭니다.
✅ 전략 패턴 구현 예제
// 전략 인터페이스
interface Strategy {
int execute(int a, int b);
}
// 구체적인 전략 클래스
class AddStrategy implements Strategy {
public int execute(int a, int b) {
return a + b;
}
}
class SubtractStrategy implements Strategy {
public int execute(int a, int b) {
return a - b;
}
}
// 컨텍스트 클래스
class Calculator {
private Strategy strategy;
public Calculator(Strategy strategy) {
this.strategy = strategy;
}
public int calculate(int a, int b) {
return strategy.execute(a, b);
}
}
📌 전략 패턴은 동적으로 알고리즘을 교체할 수 있게 하여, 코드의 유연성을 높임.
4. 데코레이터 패턴(Decorator Pattern)
데코레이터 패턴은 기존 객체의 기능을 확장할 수 있는 패턴입니다.
✔ 객체를 감싸는(wrapper) 형태로 기능을 추가하며, 원본 객체의 인터페이스를 변경하지 않고도 기능을 동적으로 확장할 수 있습니다.
✅ 데코레이터 패턴 구현 예제
// 기본 인터페이스
interface Coffee {
double cost();
}
// 구체적인 객체
class SimpleCoffee implements Coffee {
public double cost() {
return 5;
}
}
// 데코레이터 클래스
class MilkDecorator implements Coffee {
private Coffee coffee;
public MilkDecorator(Coffee coffee) {
this.coffee = coffee;
}
public double cost() {
return coffee.cost() + 2; // 우유 추가 비용
}
}
class SugarDecorator implements Coffee {
private Coffee coffee;
public SugarDecorator(Coffee coffee) {
this.coffee = coffee;
}
public double cost() {
return coffee.cost() + 1; // 설탕 추가 비용
}
}
📌 데코레이터 패턴을 사용하면 객체의 기능을 유연하게 확장할 수 있음.
5. 옵저버 패턴(Observer Pattern)
옵저버 패턴은 객체의 상태 변화에 따라 여러 객체가 자동으로 갱신되는 패턴입니다.
✔ 주체(Subject) 객체의 상태가 변할 때마다 종속된(Observer) 객체들에게 알림을 주어, 자동으로 상태가 갱신되도록 합니다.
✔ 이벤트 기반 시스템에서 많이 사용되며, UI 업데이트나 이벤트 처리에 유용합니다.
✅ 옵저버 패턴 구현 예제
import java.util.*;
// 옵저버 인터페이스
interface Observer {
void update(String message);
}
// 주체 클래스
class Subject {
private List<Observer> observers = new ArrayList<>();
public void addObserver(Observer observer) {
observers.add(observer);
}
public void notifyObservers(String message) {
for (Observer observer : observers) {
observer.update(message);
}
}
}
// 구체적인 옵저버 클래스
class ConcreteObserver implements Observer {
private String name;
public ConcreteObserver(String name) {
this.name = name;
}
public void update(String message) {
System.out.println(name + " received: " + message);
}
}
📌 옵저버 패턴은 주체 객체의 상태 변화에 따라 여러 객체가 자동으로 갱신되도록 함.
✅ 지금까지 주요 Java 디자인 패턴에 대해 배웠어요!
👉 "이제 테스트 및 TDD 개념에 대해 배우고 싶다면?"
✅ 다음 회차에서 JUnit, Mockito, TDD에 대해 다뤄봅시다!
'IT Developer > Java' 카테고리의 다른 글
Java 기초 <20. Java와 Spring을 함께 사용할 때 유용한 팁 (Spring Boot 연계)> (0) | 2025.03.21 |
---|---|
Java 기초 <19. 클린 코드 및 리팩토링 – SOLID 원칙 적용> (2) | 2025.03.20 |
Java 기초 <18. Java에서의 네트워크 프로그래밍> (0) | 2025.03.19 |
Java 기초 <16. Java 성능 최적화 및 메모리 관리 (Heap, Stack, GC 튜닝)> (2) | 2025.03.17 |
Java 기초 <15. Java의 리플렉션(Reflection)과 애노테이션(Annotation) 활용> (1) | 2025.03.16 |
Java 기초 <14. JVM 내부 구조 및 GC 원리 (G1 GC, ZGC, Shenandoah)> (1) | 2025.03.15 |
Java 기초 <13. Java 18~현재 최신 트렌드 – Virtual Threads, GraalVM, CRaC> (1) | 2025.03.14 |
Java 기초 <12. Java 5~17 주요 기능 변화 (제네릭, 스트림, 람다, 레코드 등)> (1) | 2025.03.13 |