memostack
article thumbnail
블로그를 이전하였습니다. 2023년 11월부터 https://bluemiv.tistory.com/에서 블로그를 운영하려고 합니다. 앞으로 해당 블로그의 댓글은 읽지 못할 수 도 있으니 양해바랍니다.
반응형

Template Method Pattern

템플릿 메소드 패턴은 일정한 구조의 프로세스를 가진 경우, 사용하기 좋은 디자인 패턴

  • 코드의 중복을 줄일 수 있고 유지보수하기에도 편리함.

 

일정한 구조의 프로세스?

  1. 특정 알고리즘이 A -> B -> C 와 같이 항상 A 작업을 수행하고, B작업, C작업을 수행한다면, 각 작업들을 메소드로 구현한다.
  2. A -> B -> C 순으로 실행되도록 실행 메소드를 구현한다. (아래 수도코드 참고)
func doA:
    // A 로직 수행

func doB:
    // B 로직 수행

func doC:
    // C 로직 수행
    
func doSomething:
    doA
    doB
    doC

 

예제

요구사항

계정 로그인을 한다.

로그인의 동작 순서는 아래와 같다.

  1. 사용자의 아이디, 비밀번호 복호화
  2. 유효한 아이디와 비밀번호인지 확인
  3. 권한 확인
  4. 접속

Template Method 작성

public abstract class ConnectionManager {
    protected abstract Map<String, String> decodedUerInfo(Map<String, String> rawUserInfo);
    protected abstract boolean authentication(String username, String password);
    protected abstract int authorization(String username);
    protected abstract Object getConnection(String username, int authority);

    public Object requestConnection(Map<String, String> rawUserInfo) {
        // 1. 암호화 된 유저 정보를 복호화한다.
        final Map<String, String> userInfo = decodedUerInfo(rawUserInfo);
        final String username = userInfo.get("username");
        final String password = userInfo.get("password");

        // 2. 아이디와 패스워드를 인증한다.
        if (!authentication(username, password)) {
            throw new RuntimeException("인증 실패!");
        }

        // 3. 권한을 확인한다.
        final int authority = authorization(username);

        // 4. 서비스에 접속한다.
        return getConnection(username, authority);
    }
}
  • '계정 접속'을 위한 4단계를 추상 메소드로 만든다.
    • 이때, 4단계에 대한 각 작업은 protected 권한을 주어 상속 받은 객체에서만 구현할 수 있도록 한다.
  • requestConnection() 메소드를 통해 위 4단계를 차례대로 수행한다.

 

세부 기능 구현

public class DefaultConnection extends ConnectionManager {
    @Override
    protected Map<String, String> decodedUerInfo(Map<String, String> rawUserInfo) {
        System.out.println("유저 정보 복호화");
        final Map<String, String> encodedUserInfo = rawUserInfo; // 복호화를 했다고 가정
        return encodedUserInfo;
    }

    @Override
    protected boolean authentication(String username, String password) {
        System.out.println("유저 정보 인증 확인");
        if("hong".equals(username)) {
            return true;
        }
        return false;
    }

    @Override
    protected int authorization(String username) {
        System.out.println("권한 정보 확인");

        // DB에서 권한을 가져온다.
        int authority = 0;
        if("hong".equals(username)) {
            authority = 1;
        }

        // 권한에 따른 작업 수행
        switch (authority) {
            case 0:
                System.out.println("- 권한: 일반 사용자");
                break;
            case 1:
                System.out.println("- 권한: 관리자");
                break;
            case 2:
                System.out.println("- 권한: 슈퍼 관리자");
                break;
            default:
                throw new RuntimeException("올바르지 않은 권한!");
        }
        return authority;
    }

    @Override
    protected Object getConnection(String username, int authority) {
        System.out.println(username + " 접속!");
        final Object connectionObj = new Object();
        return connectionObj; // Connection 객체 반환
    }
}
  • 위에서 만든 추상 클래스의 추상 메소드('접속'을 위한 4단계)를 구현한다.
    • 위 예제는 단순히 '템플릿 메소드 패턴'에 대한 내용을 소개하기 위한 용도로, 상세 내용은 구현하지 않음

 

Main 클래스 구현

public class Main {

    public static void main(String[] args) {
        final ConnectionManager cm = new DefaultConnection();

        final Map<String, String> userInfo = new HashMap<>();
        userInfo.put("username", "hong");
        userInfo.put("password", "12341234");

        final Object connectionObj = cm.requestConnection(userInfo);
    }
}
유저 정보 복호화
유저 정보 인증 확인
권한 정보 확인
- 권한: 관리자
접속!
  • requestConnection() 메소드 하나를 호출하면 4단계를 모두 수행함.

 

응용

만약 휴면계정일때는 본인 확인이 필요하여 접속을 거부해야한다면?

public class DefaultConnection extends ConnectionManager {
    // ...

    @Override
    protected int authorization(String username) {
        System.out.println("권한 정보 확인");

        // DB에서 권한을 가져온다.
        int authority = 0;
        if("hong".equals(username)) {
            authority = 1;
        }

        // 권한에 따른 작업 수행
        switch (authority) {
            case -1: // 휴면 계정에 대한 처리 추가
                System.out.println("- 권한: 휴면 계정");
                break;
            case 0:
                System.out.println("- 권한: 일반 사용자");
                break;
            case 1:
                System.out.println("- 권한: 관리자");
                break;
            case 2:
                System.out.println("- 권한: 슈퍼 관리자");
                break;
            default:
                throw new RuntimeException("올바르지 않은 권한!");
        }
        return authority;
    }
    
    // ...
}
  • 단순히 4단계 중 관련 기능 메소드만 수정하면 됨.

 

클래스 다이어그램

클래스 다이어그램

 

반응형
블로그를 이전하였습니다. 2023년 11월부터 https://bluemiv.tistory.com/에서 블로그를 운영하려고 합니다. 앞으로 해당 블로그의 댓글은 읽지 못할 수 도 있으니 양해바랍니다.
profile

memostack

@bluemiv_mm

포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!