Design Pattern

Template Method

Jungsoomin :) 2020. 11. 23. 23:32

공통적인 프로세스를 묶어주는 방법이다.  일정한 프로세스의 요구사항을 구현하는 방법이다. 

유지보수와 확장성에서 이득을 보게 된다.

 

  • 구현 로직의 일정한 단계를 거친다.
  • 구현 로직의 변경 가능성이 크다.
  1. 로직을 여러 단계 나눈다.
  2. 나눈 단계를 메서드로 선언한다.
  3. 나눈 단계를 수행하는 템플릿 메서드를 만든다.
  4. 하위 클래스에서 메소드를 구현한다.

가장 중요한 점은 단계를 나눈다는 것이고, 또 기존 프로세스 메서드를 외부에 노출시키지 않는 것이다.

프로세스의 단계를 추상화해놓은 메서드들과 하나로 엮은 템플릿 메서드, 프로세스를 구현하는 구현 클래스

보안, 인증, 인가, 접속 단계를 추상화 / 이를 진행하는 템플릿 메서드 선언

public abstract class AbstractProcessConnection {
    // 프로세스 메서드는 공개되지 아니한다.

    //보안
    protected abstract String[] doSecurity(String encodedStr);
    // 인증
    protected abstract boolean authentication(String username, String password);
    // 인가
    protected abstract int authorization(String username, String password);
    // 접속
    protected abstract String connection(int info);

    // 템플릿 메서드는 프로세스 메서드들을 실행시키는 메서드이다.
    public String requestConnection(String userinfo){
        String[] decodedStrArr = doSecurity(userinfo);
        boolean authenticationResult = authentication(decodedStrArr[0], decodedStrArr[1]);

        int authorizationResult = 0;
        if(authenticationResult){
            authorizationResult = authorization(decodedStrArr[0],decodedStrArr[1]);
        } else {
            new RuntimeException("인증 실패");
        }
        return connection(authorizationResult);
    }
}

프로세스를 구현하는 구현 클래스

public class DefaultProcessConnection extends AbstractProcessConnection {


    @Override
    protected String[] doSecurity(String encodedStr) {
        System.out.println("보안 작업 시작, 디코딩 할 String : "+encodedStr);
        try {
            String decode = URLDecoder.decode(encodedStr, "UTF-8");
            return decode.split("&");

        } catch(Exception e){
            e.printStackTrace();
        }
        return null;
    }

    @Override
    protected boolean authentication(String username, String password) {
        System.out.println("인증 작업 시작 : "+username +" / "+password);
        return (username != null && password != null) ? true : false ;
    }

    @Override
    protected int authorization(String username, String password) {
        int result = 0;
        switch (username) {
            case "ADMIN":
                result = 1;
                break;
            case "MANAGER":
                result = 2;
                break;
            case "USER":
                result=  3;
                break;
            default:
                result = 0;
                break;
        }
        System.out.println("인가 결과 : "+result);
        return result;
    }

    @Override
    protected String connection(int info) {
        String role = null;
        switch (info) {
            case 1:
                role = "ADMIN";
                break;
            case 2:
                break;
            case 3:
                role = "USER";
                break;
            default:
                role = "NONE";
                break;
        }
        String result = "커넥션 완료, 권한 정보 : " +role+ "/ 접속 시간 : "+new Date().toString() + "/ 사용 중인 스레드 : "+Thread.currentThread().getName();
        return result;
    }
}

// 메인 메서드
public class Main {
    public static void main(String[] args) throws UnsupportedEncodingException {
        String encodedInfo = URLEncoder.encode("ADMIN&SOOMIN", "UTF-8");

        DefaultProcessConnection defaultProcessConnection = new DefaultProcessConnection();
        String result = defaultProcessConnection.requestConnection(encodedInfo);

        System.out.println(result);
    }
}

// 로그
보안 작업 시작, 디코딩 할 String : ADMIN%26SOOMIN
인증 작업 시작 : ADMIN / SOOMIN
인가 결과 : 1
커넥션 완료, 권한 정보 : ADMIN/ 접속 시간 : Mon Nov 23 23:12:11 KST 2020/ 사용 중인 스레드 : main

만약 밤 10시 이후 접속을 제한해야하는 요구 사항이 생겼다면 확장하거나 유지보수를 해야한다.

 

확장해야 한다면 추상 클래스를 상속하는 새로운 클래스를 작성하면 되나, 기존 코드를 보수 했다.

public class DefaultProcessConnection extends AbstractProcessConnection {


    @Override
    protected String[] doSecurity(String encodedStr) {
        System.out.println("보안 작업 시작, 디코딩 할 String : "+encodedStr);
        try {
            String decode = URLDecoder.decode(encodedStr, "UTF-8");

            // 추가 로직
            int now = new Date().getHours();
            if(now > 22) {
                return new String[]{"Blocked","None"};
            }

            return decode.split("&");

        } catch(Exception e){
            e.printStackTrace();
        }
        return null;
    }

    @Override
    protected boolean authentication(String username, String password) {
        System.out.println("인증 작업 시작 : "+username +" / "+password);
        return (username != null && password != null) ? true : false ;
    }

    @Override
    protected int authorization(String username, String password) {
        int result = 0;
        switch (username) {
            case "ADMIN":
                result = 1;
                break;
            case "MANAGER":
                result = 2;
                break;
            case "USER":
                result=  3;
                break;
            //추가
            case "Blocked":
                result = -1;
                break;
            default:
                result = 0;
                break;
        }
        System.out.println("인가 결과 : "+result);
        return result;
    }

    @Override
    protected String connection(int info) {
        String role = null;
        switch (info) {
            case 1:
                role = "ADMIN";
                break;
            case 2:
                break;
            case 3:
                role = "USER";
                break;
            //추가
            case -1:
                role = "Blocked";
                break;
            default:
                role = "NONE";
                break;
        }
        String result = null;
        //추가
        if("Blocked".equals(role)){
            result = "커넥션 블로킹, 권한 정보 : "+role+ " / 접속시도 시간 : "+new Date().toString() ;
            return result;
        }
        result = "커넥션 완료, 권한 정보 : " +role+ "/ 접속 시간 : "+new Date().toString() + "/ 사용 중인 스레드 : "+Thread.currentThread().getName();
        return result;
    }
}

//
public class Main {
    public static void main(String[] args) throws UnsupportedEncodingException {
        String encodedInfo = URLEncoder.encode("ADMIN&SOOMIN", "UTF-8");

        DefaultProcessConnection defaultProcessConnection = new DefaultProcessConnection();
        String result = defaultProcessConnection.requestConnection(encodedInfo);

        System.out.println(result);
    }
}

//로그
보안 작업 시작, 디코딩 할 String : ADMIN%26SOOMIN
인증 작업 시작 : Blocked / None
인가 결과 : -1
커넥션 블로킹, 권한 정보 : Blocked / 접속시도 시간 : Mon Nov 23 23:31:06 KST 2020

'Design Pattern' 카테고리의 다른 글

Prototype  (0) 2020.11.29
SingleTon Pattern  (0) 2020.11.24
Factory Method  (0) 2020.11.24
Adapter  (0) 2020.11.23
Strategy  (0) 2020.11.23