CS 지식

디자인 패턴(Design Patterns)

이제하네 2024. 6. 20. 00:46

1. 디자인 패턴이란?

디자인 패턴은 특정 상황에서 자주 나타나는 문제를 해결하기 위한 일련의 방법론입니다. 소프트웨어 설계의 모범 사례를 기반으로 하며, 코드의 재사용성을 높이고 유지보수를 용이하게 합니다. 디자인 패턴은 세 가지 주요 카테고리로 나뉩니다:

  • 생성 패턴 (Creational Patterns)
    • 추상 팩토리 패턴: 동일한 주제의 다른 팩토리를 묶어 준다.
    • 빌더 패턴: 생성(construction)과 표기(representation)를 분리해 복잡한 객체를 생성한다.
    • 팩토리 메서드 패턴: 생성할 객체의 클래스를 국한하지 않고 객체를 생성한다.
    • 프로토타입 패턴: 기존 객체를 복제함으로써 객체를 생성한다.
    • 싱글턴 패턴: 한 클래스에 한 객체만 존재하도록 제한한다.
  • 구조 패턴 (Structural Patterns)
    • 어댑터 패턴: 인터페이스가 호환되지 않는 클래스들을 함께 이용할 수 있도록, 타 클래스의 인터페이스를 기존 인터페이스에 덧씌운다.
    • 브리지 패턴: 추상화와 구현을 분리해 둘을 각각 따로 발전시킬 수 있다.
    • 합성 패턴: 0개, 1개 혹은 그 이상의 객체를 묶어 하나의 객체로 이용할 수 있다.
    • 데코레이터 패턴: 기존 객체의 매서드에 새로운 행동을 추가하거나 오버라이드 할 수 있다.
    • 파사드 패턴: 많은 분량의 코드에 접근할 수 있는 단순한 인터페이스를 제공한다.
    • 플라이웨이트 패턴: 다수의 유사한 객체를 생성·조작하는 비용을 절감할 수 있다.
    • 프록시 패턴: 접근 조절, 비용 절감, 복잡도 감소를 위해 접근이 힘든 객체에 대한 대역을 제공한다.
  • 행위 패턴 (Behavioral Patterns)
    • 책임연쇄 패턴(Chain of responsibility): 책임들이 연결되어 있어 내가 책임을 못 질 것 같으면 다음 책임자에게 자동으로 넘어가는 구조
    • 커맨드 패턴(Command Pattern: 위의 명령어를 각각 구현하는 것보다는 위 그림처럼 하나의 추상 클래스에 메서드를 하나 만들고 각 명령이 들어오면 그에 맞는 서브 클래스가 선택되어 실행하는 것
    • 해석자 패턴 (Interpreter Pattern): 문법 규칙을 클래스화한 구조를 갖는SQL 언어나 통신 프로토콜 같은 것을 개발할 때 사용
    • 반복자 패턴 (Iterator Pattern): 반복이 필요한 자료구조를 모두 동일한 인터페이스를 통해 접근할 수 있도록 메서드를 이용해 자료구조를 활용할 수 있도록 해준다.
    • 옵저버 패턴: 어떤 클래스에 변화가 일어났을 때, 이를 감지하여 다른 클래스에 통보해주는 것
    • 전략 패턴 (Strategy Pattern): 알고리즘 군을 정의하고 각각 하나의 클래스로 캡슐화한 다음, 필요할 때 서로 교환해서 사용할 수 있게 해준다.
    • 템플릿 메서드 패턴 (Template method pattern): §상위 클래스에서는 추상적으로 표현하고 그 구체적인 내용은 하위 클래스에서 결정되는 디자인 패턴
    • 방문자 패턴 (visitor Pattern): 각 클래스의 데이터 구조로부터 처리 기능을 분리하여 별도의 visitor 클래스로 만들어놓고 해당 클래스의 메서드가 각 클래스를 돌아다니며 특정 작업을 수행하도록 하는 것
    • 중재자 패턴 (Mediator Pattern): 클래스간의 복잡한 상호작용을 캡슐화하여 한 클래스에 위임해서 처리 하는 디자인 패턴
    • 상태 패턴 (State Pattern): 동일한 동작을 객체의 상태에 따라 다르게 처리해야 할 때 사용하는 디자인 패턴
    • 기념품 패턴 (Memento Pattern): Ctrl + z 와 같은 undo 기능 개발할 때 유용한 디자인패턴. 클래스 설계 관점에서 객체의 정보를 저장

2. 생성 패턴 (Creational Patterns)

생성 패턴은 객체 생성 메커니즘을 다루며, 객체 생성 과정을 캡슐화하여 코드의 유연성과 재사용성을 높입니다. 대표적인 생성 패턴에는 다음과 같은 것들이 있습니다:

싱글톤 패턴 (Singleton Pattern)

싱글톤 패턴은 특정 클래스의 인스턴스가 하나만 생성되도록 보장합니다. 이는 주로 설정 클래스나 데이터베이스 연결 클래스 등에 사용됩니다.

public class Singleton {
    private static Singleton instance;

    private Singleton() {
        
    }

    public static Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}

// 사용 예
public class Main {
    public static void main(String[] args) {
        Singleton singleton1 = Singleton.getInstance();
        Singleton singleton2 = Singleton.getInstance();
        System.out.println(singleton1 == singleton2);  // true
    }
}
 

팩토리 패턴 (Factory Pattern)

팩토리 패턴은 객체 생성 로직을 별도의 팩토리 클래스에서 관리하여 클라이언트 코드와 객체 생성 로직을 분리합니다.

interface Animal {
    void speak();
}

class Dog implements Animal {
    @Override
    public void speak() {
        System.out.println("Bark");
    }
}

class Cat implements Animal {
    @Override
    public void speak() {
        System.out.println("Meow");
    }
}

class AnimalFactory {
    public static Animal createAnimal(String animalType) {
        if (animalType.equalsIgnoreCase("dog")) {
            return new Dog();
        } else if (animalType.equalsIgnoreCase("cat")) {
            return new Cat();
        }
        return null;
    }
}

// 사용 예
public class Main {
    public static void main(String[] args) {
        Animal dog = AnimalFactory.createAnimal("dog");
        dog.speak();  // Bark

        Animal cat = AnimalFactory.createAnimal("cat");
        cat.speak();  // Meow
    }
}

3. 구조 패턴 (Structural Patterns)

구조 패턴은 클래스나 객체를 조합하여 더 큰 구조를 형성하는 방법을 다룹니다. 이 패턴은 다양한 객체가 협력하는 방식을 정의하여 시스템의 구조를 개선합니다. 대표적인 구조 패턴에는 다음과 같은 것들이 있습니다:

어댑터 패턴 (Adapter Pattern)

어댑터 패턴은 호환성이 없는 인터페이스를 가진 클래스를 함께 사용할 수 있도록 변환해줍니다.

interface Target {
    void request();
}

class Adaptee {
    public void specificRequest() {
        System.out.println("Specific request");
    }
}

class Adapter implements Target {
    private Adaptee adaptee;

    public Adapter(Adaptee adaptee) {
        this.adaptee = adaptee;
    }

    @Override
    public void request() {
        adaptee.specificRequest();
    }
}

// 사용 예
public class Main {
    public static void main(String[] args) {
        Adaptee adaptee = new Adaptee();
        Target target = new Adapter(adaptee);
        target.request();  // Specific request
    }
}

4. 행위 패턴 (Behavioral Patterns)

행위 패턴은 객체 간의 상호 작용과 책임 분배를 다룹니다. 이 패턴은 객체 간의 소통 방식을 정의하여 시스템의 복잡성을 줄입니다. 대표적인 행위 패턴에는 다음과 같은 것들이 있습니다:

전략 패턴 (Strategy Pattern)

전략 패턴은 알고리즘군을 정의하고, 각 알고리즘을 캡슐화하여 상호 교체 가능하게 만듭니다. 클라이언트는 독립적으로 알고리즘을 변경할 수 있습니다.

interface Strategy {
    int doOperation(int num1, int num2);
}

class OperationAdd implements Strategy {
    @Override
    public int doOperation(int num1, int num2) {
        return num1 + num2;
    }
}

class OperationSubtract implements Strategy {
    @Override
    public int doOperation(int num1, int num2) {
        return num1 - num2;
    }
}

class Context {
    private Strategy strategy;

    public Context(Strategy strategy) {
        this.strategy = strategy;
    }

    public int executeStrategy(int num1, int num2) {
        return strategy.doOperation(num1, num2);
    }
}

// 사용 예
public class Main {
    public static void main(String[] args) {
        Context context = new Context(new OperationAdd());
        System.out.println("10 + 5 = " + context.executeStrategy(10, 5));

        context = new Context(new OperationSubtract());
        System.out.println("10 - 5 = " + context.executeStrategy(10, 5));
    }
}
 

디자인 패턴은 소프트웨어 개발에서 자주 발생하는 문제를 해결하기 위한 강력한 도구입니다. 다양한 패턴을 이해하고 적절하게 활용함으로써 코드의 재사용성, 유지보수성, 확장성을 크게 향상시킬 수 있습니다.

'CS 지식' 카테고리의 다른 글

HTTP 메서드 와 상태 코드  (0) 2024.07.24
세션 ,토큰 , 쿠키  (0) 2024.07.15
OAuth  (0) 2024.07.10
RESTful API: 개념과 구현  (0) 2024.07.04
API (Application Programming Interface)  (0) 2024.07.04