Java - MVC(gradle) 1

김정현·2024년 5월 30일
0

포트폴리오

목록 보기
2/8



Menu 열거형은 전체가 공유하는 글로벌 하위 탭에 상수로 존재함. (페이지는 항상 존재해야함)

화면 변화와 관련된 클래스들

1. Controller 인터페이스

public interface Controller {
    void show(); // 서비스(Model)와 뷰를 연결
    void run();  // 메뉴에서 선택하는 기능 
}

2. AbstractController (global)에 존재 전 범위에서 사용함(공통적인 기능)

  • Controller 인터페이스 기능들을 구현함

public abstract class AbstractController implements Controller {

    protected Scanner sc;

    public AbstractController() {
        sc = new Scanner(System.in);
    }

    /**
     * 상단 공통 출력 부분
     */
    public void common() {
        System.out.println("학생관리 프로그램 Ver1.0");
        System.out.println(Templates.getInstance().doubleLine());
    }

    /**
     * 입력 항목
     *  - 문자: q, exit, quit - 종료
     *  - 숫자: 메뉴 항목
     */
    public void prompt() {		//메뉴를 선택함. (메뉴는 계속해서 선택하기에 글로벌에서 구현)
        System.out.print("메뉴 선택: ");
        String menu = sc.nextLine();
        if (menu.equals("q") || menu.equals("quit") || menu.equals("exit")) {
            System.out.println("종료 합니다.");
            System.exit(0); // 0 - 정상 종료, 1 - 비정상 종료
        }

        try {
            int m = Integer.parseInt(menu);
            change(m); // 메뉴 변경
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("메뉴는 숫자로 입력하세요.");
        }
    }

    /**
     * 입력과 검증을 함께 진행
     *
     * @param message : 항목 메세지
     * @param predicate : 판별식
     * @return
     */
    protected String promptWithValidation(String message, Predicate<String> predicate) {
        String str = null;
        do {
            System.out.print(message);
            str = sc.nextLine();
        } while(!predicate.test(str));

        return str;
    }

    /**
     * 템플릿 메서드 패턴 : 특정 절차가 고정되어 있는 경우
     *
     */
    @Override
    public final void run() {			//화면에서 정상적으로 작동시에 출력되는 순서대로 종합. 
        common();		//공통적으로 모든화면에서 보여줘야하는 것
        show();		//화면을 보여줌
        prompt();		//메뉴 선택과 관련
    }

    private void change(int menuNo) {		//화면 변경시에 사용할 메서드
        Menu menu = null;
        switch(menuNo) {
            case 1: menu = Menu.JOIN; break; // 회원가입
            case 2: menu = Menu.LOGIN; break; // 로그인
            default: menu = Menu.MAIN; // 메인 메뉴
        }

        // 메뉴 컨트롤러 변경 처리 - Router
        MainRouter.getInstance().change(menu);
    }
}

다형성으로 이루어짐..

(인터페이스로 구현이지만 편의상 부모라 칭하겠음)

이 메서드에서

memlocator는 다형성을 사용해서

ControllerLocator자료형의 MemberControllerLocator 기능을 가진 객체를 생성함.


MemberControllerLocator의 부모인 ControllerLocator 인터페이스는

위 사진의 find라는 이름을 가진 메서드는 Controller 자료형의 객체를 반환하며 menu 열거형을 매개변수로 가진다.


find의 자료형인 Controller 인터페이스는

show()와 run() 메서드를 정의하고 있다.


한편, AbstractController는 Controller의 run 메서드를 구현하고 있다. (AbstractController가 자식임)

package org.choongang.global;

import org.choongang.global.constants.Menu;
import org.choongang.main.MainRouter;
import org.choongang.template.Templates;

import java.util.Scanner;
import java.util.function.Predicate;

public abstract class AbstractController implements Controller {

  ...
  
    @Override
    public final void run() {
        common();
        show();
        prompt();
    }

   ...
   public void prompt() {
        System.out.print("메뉴 선택: ");
        String menu = sc.nextLine();
        if (menu.equals("q") || menu.equals("quit") || menu.equals("exit")) {
            System.out.println("종료 합니다.");
            System.exit(0); // 0 - 정상 종료, 1 - 비정상 종료
        }

        try {
            int m = Integer.parseInt(menu);
            change(m); // 메뉴 변경
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("메뉴는 숫자로 입력하세요.");
        }
    }
    ...
}

이제 다시 memlocator의 기능을 수행하는 MemberControllerLocator로 돌아와본다.

public class MemberControllerLocator implements ControllerLocator {

    ...


    @Override
    public Controller find(Menu menu) {
        Controller controller = controllers.get(menu);
        if (controller != null) {
            return controller;
        }

        switch(menu) {
            case JOIN: controller = new JoinController(); break;
            default: controller = new LoginController();
        }

        controllers.put(menu, controller);

        return controller;
    }
}

해당 클래스에서 ControllerLocator의 find 메서드에서 객체를 생성하게끔 구현해놨다. (JoinController, LoginController 객체를 생성하게끔)


여기서 JoinController를 보면

public class JoinController extends AbstractController {

...

    public void show() {
        Templates.getInstance().render(Menu.JOIN);
    }

public void prompt() {
        String userId = promptWithValidation("아이디(6자리 이상): ", s -> s.length() >= 6);

        String userPw = promptWithValid ....

...

}

AbstractController를 상속받고 있다.

JoinController가 자식이 되므로 해당 자료형을 사용한다면 AbstractController의 구현된 메서드들을 사용할 수 있게된다. (자식은 부모 클래스의 메서드를 사용 가능 및 재정의도 가능하다.)

예) JoinController에서 AbstractController의 prompt메서드를 재정의하여 사용하고 있다.


다시 원래 처음 으로 돌아오면

위 과정을 거쳐 controller는 memlocator.find 메서드를 통해 Join, LoginController 객체를 가질 수 있었고

해당 객체에서는 AbstractController를 상속받고 있기에 run메서드를 통해 화면을 구현하는 과정을 일련적으로 진행할 수 있었다.


show 메서드는

컨트롤러에서 구현했다.

0개의 댓글