백엔드에서 자주 사용되는 디자인패턴 -행위 패턴형-

jinhan han·2024년 8월 9일
0

spring과 java 개발

목록 보기
5/6
post-thumbnail

--- 행위 패턴 ----

깃허브 링크 : https://github.com/Jinhan-Han-Jeremy/RealDesignPattern

-------- 전략, 스트레티지(Strategy) --------

행동을 클래스로 캡슐화해서 동적으로 행동을 바꿀 수 있게 하는 패턴

  • 전략 패턴을 사용하는 이유
    • 객체 책임과 행동이 상황에 따라 다양한 기능이 빈번하게 추가/삭제되는 경우.
    • 객체의 결합을 통해 기능이 생성될 수 있는 경우.
    • 객체를 사용하는 코드를 손상시키지 않고 런타임에 객체에 추가 동작을 할당할 수 있어야 하는 경우
    • 상속을 통해 서브클래싱으로 객체의 동작을 확장하는 것이 어색하거나 불가능 할 때

자주 사용되는 경우 : 로깅(Logging), 트랜잭션 관리(Transaction Management), 정보 캐싱(Information Caching), 메소드 접근 제한(Method Access Control), 서비스 기능 확장(Extending Service Methods), 사용자 정의 데코레이터를 사용한 알림 서비스(Custom Decorator for Notification Service
Scenario)

스트레티지(Strategy) 장점

  • 공통 로직이 부모 클래스에 있지 않고 Context 라는 별도의 클래스에 존재하기 때문에 구현체들에 대한 영향도가 적음
  • Context 가 Strategy 라는 인터페이스를 의존하고 있기 때문에 구현체를 갈아끼우기 쉬움

스트레티지(Strategy) 단점

  • 로직이 늘어날 때마다 구현체 클래스가 늘어남
  • Context 와 Strategy 를 한번 조립하면 전략을 변경하기 힘듬

템플릿 메서드(Templage Method)
일정 작업을 처리하는 부분을 서브클래스로 캡슐화해서 전체 수행 구조는 바꾸지 않으면서 특정 단계만 변경해서 수행하는 패턴

전략 패턴이 템플릿 메소드보다 유연하고 좋음
전략 패턴 : 합성(composition)을 통해 해결책을 강구하며, 대부분 인터페이스를 사용 

  • 클라이언트와 객체 간의 결합이 느슨함

템플릿 메서드 패턴 : 상속(inheritance)을 통해 해결책을 제시하며, 주로 추상 클래스나 구체적인 클래스를 사용

  • 두 모듈이 더 밀접하게 결합 (결합도가 높으면 안좋음)

전략 패턴 예제) 텍스트를 입력 받고 서치하는 인터페이스와 오브젝트 구성
1. public interface SearchStrategy { : 검색 기능을 하는 인터페이스 구성

// SearchStrategy 인터페이스: 다양한 검색 전략을 위한 공통 인터페이스 정의
public interface SearchStrategy {
    // 텍스트에서 패턴을 검색하는 메서드
    // 검색된 패턴의 시작 인덱스를 반환, 패턴이 없으면 -1 반환
    int search(String text, String pattern);
}

전략 패턴 예제) 알고리즘 서비스를 구성하는 클래스
2. public class RegexSearch implements SearchStrategy { : RegexSearch기능을 하는 함수 생성 및 @Override

import java.util.regex.Matcher;
import java.util.regex.Pattern;
// RegexSearch 클래스: 정규 표현식을 이용한 검색 전략 구현
public class RegexSearch implements SearchStrategy {
    @Override
    public int search(String text, String pattern) {
        // Pattern과 Matcher 클래스를 사용하여 정규 표현식 검색 수행
        Pattern p = Pattern.compile(pattern);
        Matcher m = p.matcher(text);
        if (m.find()) {
            // 패턴이 발견되면 시작 인덱스 반환
            return m.start();
        }
        // 패턴이 발견되지 않으면 -1 반환
        return -1;
    }
}
  1. public class SimpleSearch implements SearchStrategy { : SimpleSearch기능을 하는 인터페이스 구성
// SimpleSearch 클래스: 단순 문자열 검색 전략 구현
public class SimpleSearch implements SearchStrategy {
    @Override
    public int search(String text, String pattern) {
        // Java의 indexOf 메서드를 사용하여 단순 검색 수행
        return text.indexOf(pattern);
    }
}

전략 패턴 예제) 인터페이스 타입을 선택하는 클래스 구성
4. public class TextEditor { : 어떤 Search기능을 할당할지 지정해주는 클래스 구성
5. public void setSearchStrategy(SearchStrategy searchStrategy) { : setter 역할로 searchStrategy 알고리즘 선택
6. public int performSearch(String text, String pattern) { : 서치를 실행

// TextEditor 클래스: 검색 전략을 사용하는 텍스트 편집기
public class TextEditor {
    // 현재 검색 전략을 저장하는 필드
    private SearchStrategy searchStrategy;
    // 검색 전략을 설정하는 메서드
    public void setSearchStrategy(SearchStrategy searchStrategy) {
        this.searchStrategy = searchStrategy;
    }
    // 설정된 검색 전략을 사용하여 텍스트에서 패턴을 검색하는 메서드
    public int performSearch(String text, String pattern) {
        if (searchStrategy == null) {
            // 검색 전략이 설정되지 않은 경우 예외 발생
            throw new IllegalStateException("Search strategy not set");
        }
        // 설정된 검색 전략을 사용하여 검색 수행
        return searchStrategy.search(text, pattern);
    }
}

전략 패턴 예제) 메인 클래스 구성

import StrategyPattern.RegexSearch;
import StrategyPattern.SimpleSearch;
import StrategyPattern.TextEditor;
public class MainByStrategy {
    // 메인 메서드: 예제 실행
    public static void main(String[] args) {
        TextEditor editor = new TextEditor();
        // 예제 텍스트
        String text = "Hello, this is a simple text editor.";
        // 단순 검색 전략 사용
        editor.setSearchStrategy(new SimpleSearch());
        int index = editor.performSearch(text, "simple");
        System.out.println("Simple Search: 'simple' found at index " + index);
        // 정규 표현식 검색 전략 사용
        editor.setSearchStrategy(new RegexSearch());
        index = editor.performSearch(text, "\\bsimple\\b");
        System.out.println("Regex Search: '\\bsimple\\b' found at index " + index);
    }
}

전체적 구조 :

  • 전략 인터페이스{서치 기능(서비스 기능 담당)}
  • 서치 알고리즘 클래스들 implements 전략 인터페이스{ @Override 서치 기능(서비스 기능 담당)}
  • 서비스 조율 클래스{알고리즘 기능 선택 함수(전략 인터페이스), 데이터를 받고 서비스를 시행하는 함수(입력 텍스트, 패턴화된 찾으려는 텍스트) }


-------- 옵저버(Observer) --------

객체의 상태 변화를 관찰하는 관찰자(옵저버) 목록을 객체에 등록해 상태가 변할 때마다 메서드 등을 통해 객체가 직접 옵서버에게 통지하게 하는 디자인 패턴

  • 옵저버 패턴을 사용하는 이유
    • 앱이 한정된 시간, 특정한 케이스에만 다른 객체를 관찰해야 하는 경우
    • 대상 객체의 상태가 변경될 때마다 다른 객체의 동작을 트리거해야 할때
    • 한 객체의 상태가 변경되면 다른 객체도 변경해야 할때. 그런데 어떤 객체들이 변경되어야 하는지 몰라도 될 때

자주 사용되는 경우 : 이벤트 기반 아키텍처 (Event-Driven Architecture), 실시간 데이터 업데이트 (Real-Time Data Update), 모니터링 시스템 (Monitoring System), 데이터베이스 변경 감지 (Database Change Notification), 사용자 인터페이스 (User Interface), 알림 시스템 (Notification System)

옵저버(Observer) 장점

  • Subject의 상태 변경을 주기적으로 조회하지 않고 자동으로 감지 가능.
  • 발행자의 코드를 변경하지 않고도 새 구독자 클래스를 도입할 수 있어 개방 폐쇄 원칙(OCP)Visit Website 준수.
  • 런타임 시점에서에 발행자와 구독 알림 관계를 맺는게 가능.
  • 상태를 변경하는 객체(Subject)와 변경을 감지하는 객체(Observer)의 관계를 느슨하게 유지 가능. (느슨한 결합)

옵저버(Observer) 단점

  • 구독자는 알림 순서를 제어할수 없고, 무작위 순서로 알림을 받음
    • 하드 코딩으로 구현할수는 있겠지만, 복잡성과 결합성만 높아지기 때문에 추천되지는 않는 방법.
  • 옵저버 패턴을 자주 구성하면 구조와 동작을 알아보기 힘들어져 코드 복잡도가 증가.
  • 다수의 옵저버 객체를 등록 이후 해지하지 않는다면 메모리 누수가 발생 가능.

옵저버 예제) 유저의 날씨 조회 기록 관리
1. interface Observer { : 다른 클래스의 기록을 조회 가능하도록 하는 인터페이스.

package Observer;
interface Observer {
    void display(WeatherAPI api);
}

2.public class KoreanUser implements Observer { : 유저들의 날씨 조희 기록 클래스.
3.public void display(WeatherAPI api) { : 유저들의 날씨 조희 기록 형식 출력.

package Observer;
public class KoreanUser implements Observer {
    String name;
    public KoreanUser(String name) {
        this.name = name;
    }
    public void display(WeatherAPI api) {
        System.out.printf("%s님이 현재 날씨 상태를 조회함 : %.2f°C %.2fg/m3 %.2fhPa\n", name, api.temp, api.humidity, api.pressure);
    }
}

옵저버 예제) 유저의 날씨 조회 기록 관리
4. interface Subject { : 객체들 관리 인터페이스

package Observer;
interface Subject {
    void registerObserver(Observer o); // 구독 추가
    void removeObserver(Observer o); // 구독 삭제
    void notifyObservers(); // Subject 객체의 상태 변경시 이를 모든 옵저버에게 알림
}

5. public class WeatherAPI implements Subject{ : 서브젝트 인터페이스 상속, 그리고 날씨 생성 및 유저 관리 서비스를 포함하는 클래스
6. public void measurementsChanged() { : 날씨 생성 기능
7. @Override public void registerObserver(Observer o) { : 옵저버로 구독자 등록
8. public void notifyObservers() { : 구독자 액티비티 기록 알림

package Observer;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
public class WeatherAPI implements Subject{
    float temp; // 온도
    float humidity; // 습도
    float pressure; // 기압
    // 구독자들을 담아 관리하는 리스트
    List<Observer> subscribers = new ArrayList<>();
    public void measurementsChanged() {
        // 현재의 온습도 데이터를 랜덤값으로 얻는 것으로 비유하였다.
        temp = new Random().nextFloat() * 100;
        humidity = new Random().nextFloat() * 100;
        pressure = new Random().nextFloat() * 100;
        notifyObservers(); // 온습도 값이 변화하면 바로 옵저버들에게 발행
    }
    @Override
    public void registerObserver(Observer o) {
        subscribers.add(o);
    }
    @Override
    public void removeObserver(Observer o) {
        subscribers.remove(o);
    }
    // 이벤트 전파
    @Override
    public void notifyObservers() {
        for(Observer o: subscribers) {
            o.display(this); // 자신의 객체를 매개변수로 줘서 현재 자신의 상태를 구독자에게 알림
        }
    }
}

전체적 구조 :

  • 옵저버 인터페이스 {기능}
  • 기본 클래스 implements 옵저버 {생성자(변수들), 기능}
  • 2번째 기본 인터페이스{기능들}
  • 2번째 기본 클래스 implements 인터페이스{기본 클래스들을 관리하고 다루는 함수들}


참조 :
https://inpa.tistory.com/entry/GOF-%F0%9F%92%A0-%EC%B6%94%EC%83%81-%ED%8C%A9%ED%86%A0%EB%A6%ACAbstract-Factory-%ED%8C%A8%ED%84%B4-%EC%A0%9C%EB%8C%80%EB%A1%9C-%EB%B0%B0%EC%9B%8C%EB%B3%B4%EC%9E%90#%EC%B6%94%EC%83%81_%ED%8C%A9%ED%86%A0%EB%A6%AC_%ED%8C%A8%ED%84%B4_%ED%8A%B9%EC%A7%95

https://innovation123.tistory.com/9#%EC%8B%B1%EA%B8%80%ED%86%A4%EC%9D%98%20%EB%AC%B8%EC%A0%9C%20%ED%95%B4%EA%B2%B0%20-%20statelsess-1

https://inpa.tistory.com/entry/GOF-💠-템플릿-메소드Template-Method-패턴-제대로-배워보자

https://dev-coco.tistory.com/177

https://appleg1226.tistory.com/category/Study?page=2

https://blog.naver.com/jvioonpe/220247760303

profile
개발자+분석가+BusinessStrategist

0개의 댓글