자바 디자인 패턴 소개

2023. 11. 11. 23:54개발 문서/Java

728x90
반응형

디자인 패턴은 소프트웨어 디자인에서 자주 발생하는 문제에 대한 일반적인 해결책을 제시한 것입니다. 디자인 패턴은 소프트웨어 설계에서 특정한 문제를 해결하기 위한 일종의 템플릿으로, 다양한 상황에서 적용할 수 있는 설계 아이디어를 제공합니다. 여러 개발자들 사이에서 공통적으로 사용되는 패턴들이 있으며, 이를 따르면 코드의 유지보수성과 확장성이 증가할 수 있습니다.

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;
    }
}

2. Factory Method Pattern (팩토리 메소드 패턴):

객체 생성을 서브 클래스에서 처리하도록 분리하여, 객체의 생성 코드를 호출하는 클라이언트 코드와 분리시키는 패턴입니다.

// Creator (생성자) 인터페이스
interface Creator {
    Product factoryMethod();
}

// ConcreteCreator (구체적 생성자) 클래스
class ConcreteCreator implements Creator {
    @Override
    public Product factoryMethod() {
        return new ConcreteProduct();
    }
}

// Product (제품) 인터페이스
interface Product {
    void doSomething();
}

// ConcreteProduct (구체적 제품) 클래스
class ConcreteProduct implements Product {
    @Override
    public void doSomething() {
        System.out.println("Doing something...");
    }
}

3. Observer Pattern (옵서버 패턴):

한 객체의 상태가 바뀌면 그 객체에 의존하는 다른 객체들한테 알림을 전달하는 패턴입니다.

// Observer (옵서버) 인터페이스
interface Observer {
    void update(String message);
}

// ConcreteObserver (구체적 옵서버) 클래스
class ConcreteObserver implements Observer {
    private String name;

    public ConcreteObserver(String name) {
        this.name = name;
    }

    @Override
    public void update(String message) {
        System.out.println(name + " received message: " + message);
    }
}

// Subject (주제) 인터페이스
interface Subject {
    void addObserver(Observer observer);
    void removeObserver(Observer observer);
    void notifyObservers(String message);
}

// ConcreteSubject (구체적 주제) 클래스
class ConcreteSubject implements Subject {
    private List<Observer> observers = new ArrayList<>();

    @Override
    public void addObserver(Observer observer) {
        observers.add(observer);
    }

    @Override
    public void removeObserver(Observer observer) {
        observers.remove(observer);
    }

    @Override
    public void notifyObservers(String message) {
        for (Observer observer : observers) {
            observer.update(message);
        }
    }
}

4. Decorator Pattern (데코레이터 패턴):

객체에 추가적인 기능을 동적으로 부여할 수 있도록 하는 패턴으로, 서브 클래스를 만들지 않고도 기능을 확장할 수 있습니다.

// Component (컴포넌트) 인터페이스
interface Coffee {
    double cost();
}

// ConcreteComponent (구체적 컴포넌트) 클래스
class SimpleCoffee implements Coffee {
    @Override
    public double cost() {
        return 5;
    }
}

// Decorator (데코레이터) 클래스
abstract class CoffeeDecorator implements Coffee {
    protected Coffee decoratedCoffee;

    public CoffeeDecorator(Coffee decoratedCoffee) {
        this.decoratedCoffee = decoratedCoffee;
    }

    @Override
    public double cost() {
        return decoratedCoffee.cost();
    }
}

// ConcreteDecorator (구체적 데코레이터) 클래스
class MilkDecorator extends CoffeeDecorator {
    public MilkDecorator(Coffee decoratedCoffee) {
        super(decoratedCoffee);
    }

    @Override
    public double cost() {
        return super.cost() + 2; // 추가 기능의 비용
    }
}

이외에도 여러 디자인 패턴이 있으며, 상황에 따라 적절한 패턴을 선택하여 사용하는 것이 중요합니다. 패턴을 이해하고 적용함으로써 유지보수성이 높아지고, 소프트웨어 설계가 유연해질 수 있습니다.