The Debugging Chronicles : "코드의 미학"

학생부 프로그램03 예제로 알아보는 MVC 패턴 본문

JAVA/자바 수업 내용

학생부 프로그램03 예제로 알아보는 MVC 패턴

sweetseonah1004 2024. 7. 16. 17:46

MVC(model  view  controller)는

사용자 인터페이스, 데이터 및 논리 제어를 구현하는데 널리 사용되는

소프트웨어 디자인 패턴입니다.

 

소프트웨어의 비즈니스 로직과 화면을 구분하는데 중점을 두고 있다.

 

이러한 "관심사 분리"는 더 나은 업무의 분리와 향상된 관리를 제공합니다.

 

Model : 데이터와 비즈니스 로직을 관리

모델은 앱이 포함해할 데이터가 무엇인지를 정의

데이터의 상태가 변경되면, 모델을 일반적으로 뷰에게 알리며 가끔 컨트롤러에게 알리기도 한다.

 

View : 레이아웃과 화면을 처리

앱의 데이터를 보여주는 방식을 정의

 

Controller : 모델과 뷰로 명령을 전달

앱의 사용자로부터의 입력에 대한 응답으로 모델 및 뷰를 업데이트하는 로직을 포함

 

 

 


>>>view

package view;

import java.util.ArrayList;
import java.util.Scanner;

import service.model.StudentDTO;

public class StudentView {
	static Scanner sc=new Scanner(System.in);

	// 출력 부분
	// 메뉴 출력
	public void printMenu() {
		System.out.println("=== 메 뉴 ===");
		System.out.println("1. 학생추가");
		System.out.println("2. 전체출력");
		System.out.println("3. 번호검색");
		System.out.println("4. 이름검색");
		System.out.println("5. 평균출력");
		System.out.println("6. 점수변경");
		System.out.println("7. 학생삭제");
		System.out.println("0. 프로그램 종료");
		System.out.println("==========");
	}
	// 이름 입력 안내 출력
	public void printNameInfo() {
		System.out.print("추가할 학생의 이름 입력 >> ");
	}
	// 성적 입력 안내 출력
	public void printScoreInfo() {
		System.out.print("추가할 학생의 성적 입력 >> ");
	}
	// 학생 추가 완료 멘트 출력
	public void printAddSuccess() {
		System.out.println("학생 추가 완료!");
	}
	// 전체 목록 출력
	public void printAllList(ArrayList<StudentDTO> datas) {
		System.out.println("=== 전체 목록 ===");
		for(StudentDTO data : datas) {
			System.out.println(data);
		}
		System.out.println("===============");
	}
	
	// 목록이 비어있을 때 출력
	public void printEmpty() {
		System.out.println("출력할 데이터가 없습니다!");
	}
	// 검색할 학생 번호 입력 안내 출력
	public void printNumInfo() {
		System.out.print("검색할 학생의 번호 입력 >> ");
	}
	// 검색 결과 출력
	public void printSearchList(StudentDTO data) {
		if(data==null) {
			System.out.println("검색 결과가 없습니다!");
			return;
		}
		System.out.println("=== 검색 결과 ===");
		System.out.println(data);
		System.out.println("===============");
	}
	// 검색 결과 여러명 출력
		public void printSearchList(ArrayList<StudentDTO> datas) {
			if(datas.size() == 0) {
				System.out.println("검색 결과가 없습니다!");
				return;
			}
			System.out.println("=== 검색 결과 ===");
			for(StudentDTO data : datas) {
				System.out.println(data);
			}
			System.out.println("===============");
		}
	// 삭제할 이름 입력 출력
	public void printDeleteInfo() {
		System.out.println("삭제할 학생의 학번 입력 >> ");
	}
	// 삭제 성공, 실패 출력
	public void printIsDelete(boolean result) {
		if(result) {
			System.out.println("삭제 성공!");	
			return;
		}
		System.out.println("삭제 실패..");
	}
	// 점수 업데이트 성공 출력
	public void printIsUpdate(boolean result) {
		if(result) {
			System.out.println("점수 업데이트 성공!");	
			return;
		}
		System.out.println("점수 업데이트 실패..");
	}
	// 평균 출력
	public void printAvg(double avg) {
    	// 학생이 많아질수록, 성적이 다양해질 수록
        // 즉, 데이터가 많아지면 view에 로직이 있으면 느려진다.
        // 따라서 평균 로직을 백엔드에 위치 시킨다.
		System.out.println("평균은 " + avg + "입니다.");
	}
	// 이름 검색 출력
	public void printNameSearchInfo() {
		System.out.println("검색할 이름을 입력 >> ");
	}
	

	// 입력 부분
	// 메뉴 입력
	public int inputAction() {
		int action=sc.nextInt();
		return action;
	}
	// 이름 입력
	public String inputName() {
		String name;
		while(true){
			name=sc.next();

			System.out.println("정말 " + name +"으로 입력하시겠습니까? (Y/N)");
			String answer = sc.next();

			if(answer.equals("Y")) {
				break;
			}
			this.printNameInfo();
		}
		return name;
	}
	// 점수 입력
	public int inputScore() {
		int score=sc.nextInt();
		return score;
	}
	// 번호 입력
	public int inputNum(int lastPK) {
		int num;
		while(true) {
			num=sc.nextInt();
			if(101 <= num && num <= lastPK) {
				break;
			}
			System.out.println("다시 입력해주세요.");
		}
		return num;
	}
}

 

 

>>> service model 

>>DTO

package service.model;

// MVC 패턴에서 data를 VO, DTO라고 함
// 지금까지 불러왔던 데이터
public class StudentDTO {
	// 멤버 변수
	private int num;
	private String name;
	private int score;
	// 평균 변수를 선언해 준다.
    private double avg;
	public double getAvg() {
		return avg;
	}
	public void setAvg(double avg) {
		this.avg = avg;
	}
	// 게터,세터
	public int getNum() {
		return num;
	}
	public void setNum(int num) {
		this.num = num;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public int getScore() {
		return score;
	}
	public void setScore(int score) {
		this.score = score;
	}
	
	@Override
	public String toString() {
		return "StudentDTO [num=" + num + ", name=" + name + ", score=" + score + "]";
	}
}

 

>> DAO

package service.model;

import java.util.ArrayList;

// MVC 패턴에서 DBMS 파트를 DAO라고 함
// 매니지먼트 시스템
public class StudentDAO {
	// 멤버 변수
	private ArrayList<StudentDTO> datas;
	// 같은 패키지 안에서는 import가 필요없음
	// JAVA x ▷ MySQL, Oracle로 이동될 예정

	// 생성자
	// 미리 3명의 학생을 만들어 놓음
	public StudentDAO() {
		System.out.println("   service.model.StudentDAO StudentDAO() 생성자 시작");
		// 학생 객체를 담을 새로운 datas 배열을 만듦
		datas = new ArrayList<StudentDTO>();

		// 샘플 데이터 or 기존 데이터 생성
		// 학생 객체1을 만듦
		StudentDTO data1=new StudentDTO();
		data1.setNum(101);
		data1.setName("오리아나");
		data1.setScore(50);
		// 생성된 학생1을 datas 배열에 넣어줌
		datas.add(data1);

		// 학생2
		StudentDTO data2=new StudentDTO();
		data2.setNum(102);
		data2.setName("모르가나");
		data2.setScore(89);
		datas.add(data2);

		// 학생3
		StudentDTO data3=new StudentDTO();
		data3.setNum(103);
		data3.setName("티모");
		data3.setScore(67);
		datas.add(data3);
		System.out.println("   service.model.StudentDAO  StudentDAO() 생성자 종료");
	}


	// 함수
	// CUD는 output이 boolean
	// 데이터의 처리가 성공했는지 실패했는지 알아야하기 때문에
	public boolean insert(int num, String name, int score) {
		System.out.println("   service.model.StudentDAO insert() 생성자 시작");
		// DBMS에 data를 추가 == AL에 DTO 추가
		// 객체를 생성, 멤버변수 값들을 넣어줌
		StudentDTO data = new StudentDTO();
		data.setNum(num);
		data.setName(name);
		data.setScore(score);
		// 데이터를 넣어줌 학생부 목록에 넣어줌
		datas.add(data);
		System.out.println("   service.model.StudentDAO insert() 생성자 종료");
		return true;
	}
	public boolean update(int num, int score) {
		// 삭제하려는 학번을 받아옴
		// 배열은 현재 배열을 사용
		// 해당 학번의 학생을 찾아봄
		System.out.println("   service.model.StudentDAO update() 생성자 시작");
		for(int i = 0 ; i < datas.size(); i++) {
			if(datas.get(i).getNum() != num) {
				continue;
			}
			datas.get(i).setScore(score);
			System.out.println("   service.model.StudentDAO update() 성공");
			return true;
		}
		System.out.println("   service.model.StudentDAO update() 실패");
		return false;
	}
	public boolean delete(int num) {
		// 삭제하려는 학번을 받아옴
		// 배열은 현재 배열을 사용 
		// 해당 학번의 학생을 찾아봄
		System.out.println("   service.model.StudentDAO delete() 생성자 시작");
		for(int i = 0 ; i < datas.size(); i++) {
			if(datas.get(i).getNum() != num) {
				continue;
			}
			datas.remove(i);
			System.out.println("   service.model.StudentDAO delete() 성공");
			return true;
		}
		System.out.println("   service.model.StudentDAO delete() 실패");
		return false;
	}

	// R : output인 여러개인 경우 AL, 하나인 경우 DTO
	// 전체 출력
	public ArrayList<StudentDTO> selectAll(){
		// 데이터 전체 목록을 넘기면 됨
		System.out.println("   service.model.StudentDAO selectAll()");
		return this.datas;

		/*ArrayList<StudentDTO> datas = new ArrayList<StudentDTO>();

			return datas;
			// null이 반환되는 경우는 없다.
			// 다만, .size(0가 0일 수는 있다.*/
	}
	// 이름 검색
	public ArrayList<StudentDTO> selectAll(String name){
		System.out.println("   service.model.StudentDAO selectAll() 시작");
		ArrayList<StudentDTO> al = new ArrayList<StudentDTO>();

		for(StudentDTO data : this.datas) {
			if(data.getName().contains(name)) {
				al.add(data);
			}
		}
		System.out.println("   service.model.StudentDAO selectAll() 종료");
		return al;
	}
	// 한 명만 출력
	// 학번을 인자로 받음
	public StudentDTO selectOne(int num){
		System.out.println("   service.model.StudentDAO selectOne() 생성자 시작");
		// datas(학생부) 전체를 확인하여 일치하는 학번이 있는지 검사 
		for(StudentDTO data : this.datas) {
			// 만약 일치한다면
			if(data.getNum() == num) {
				System.out.println("   service.model.StudentDAO selectOne() 데이터 일치");
				// 일치하는 데이터를 반환
				return data;
			}
		}
		System.out.println("   service.model.StudentDAO selectOne() 데이터 불일치");
		// 없다면 공백을 반환
		return null;
	}
	// 평균값을 계산
	public StudentDTO avg() {
   	    System.out.println("   service.model.StudentDAO  selectOne() 시작 : 평균");
    	int sum = 0;
        for(StudentDTO data:datas){
        	sum += data.getScore();
        }
        double avg = sum*1.0 / datas.size();
        // 함수의 반환타입이 객체이기 때문에 객체를 담기 위해 객체를 생성
        StudnetDTO dto = new StudentDTO();
        dto.setAvg(avg);
        System.out.println("   service.model.StudentDAO  selectOne() 종료 : 평균");
        return dto;        
	}

}

 

>>>service controller

package service.controller;

import java.util.ArrayList;

import service.model.StudentDTO;
import service.model.StudentDAO;
import view.StudentView;

public class StudentController {
	// 멤버변수
	private StudentDAO model;	// 학생부
	private StudentView view;	// 출력할 것들 목록
	private int PK; 			// 학번을 넣어줄 정수 변수

	// 생성자
	public StudentController() {
		this.model=new StudentDAO();
		this.view=new StudentView();
		this.PK=104;		// 샘플 데이터가 이미 3명이 있기 때문에 104번부터 선택
	}

	// 사용자(Client)에게 [M과 V를 조합해서] 서비스를 제공하는 역할
	public void start() {
		while (true) {
			// 메뉴 출력
			view.printMenu();
			// 메뉴 선택값을 반환받음
			int action=view.inputAction();

			if(action == 1) {		// 학생 추가
				view.printNameInfo();				// 이름을 입력받으라는 멘트
				String name=view.inputName();		// 입력을 받음
				view.printScoreInfo();				// 점수를 입력받으라는 멘트
				int score=view.inputScore();		// 점수를 입력받음

				// 값을 입력받고 제대로 입력받았는지 확인하는 값을 반환
				boolean flag=model.insert(PK++, name, score);
				if(flag) {	// 만약 성공했다면
					view.printAddSuccess();	// 성공 멘트
				}	
				else {
					// 실패했습니다.
					System.out.println("실패했습니다.");
				}
			}
			else if(action == 2){	// 전체 출력
				// 학생부에 있는 데이터를 전부 반환받아(selectAll) 새로운 배열 datas에 넣어줌
				// <StudentDTO>은 배열 타입
				ArrayList<StudentDTO> datas=model.selectAll();
				view.printAllList(datas);	// 전부 출력
			}
			else if(action == 3){	// 번호 검색
				view.printNumInfo();		// 번호를 입력하라는 멘트
				int num = view.inputNum(PK);	// 번호를 입력받음

				// 입력받은 번호를 인자로 검색(출력) 실행
				// view에서 출력
				// DAO에서 인자를 받아 값을 반환
				view.printSearchList(model.selectOne(num));
			}
			else if(action == 4){	// 이름 겁색
				// 이름 입력 안내 (view)
				view.printNameSearchInfo();
				// 이름 입력 받음, 입력값 확인 (view)
				String name = view.inputName();

				// 입력값이 포함된 이름이 있나 확인 (model)
				ArrayList<StudentDTO> al = model.selectAll(name);
				// 출력(view)
				view.printAllList(al);
			}
			else if(action == 5){	// 평균 출력
                    /*
                    방법 1. selectOne - DAO에서 평균값을 구하고 값을 가져오기
                    StudentDTO data = model.selectOne();
                    double avg = data.getAvg();
                    */
                    // 방법 2. selectAll - controller 에서 데이터를 직접가공
                    ArrayList<StudentDTO> datas = model.selectAll();
                    int sum=0;
                    for(StudentDTO data:datas){
                        sum += data.getScore();
                    }
                    double avg = sum*1.0/datas.size();

                    view.print14(avg);
			}
			else if(action == 6){	// 점수 변경
				// 학번을 입력하라는 안내(view)
				view.printNumInfo();
				// 학번을 입력받음(view)
				int num = view.inputNum(PK);

				// 변경할 점수 입력 안내(view)
				view.printScoreInfo();
				// 변경할 점수를 입력받음(view)
				int score = view.inputScore();

				// 학번에 맞는 학생을 찾아서 점수 변경 (model)
				model.update(num, score);
			}
			else if(action == 7){	// 학생 삭제
				// 학번을 입력하라는 안내
				view.printDeleteInfo();
				// 학번을 입력받음
				int num = view.inputNum(PK);

				// 학생을 찾아서 삭제 시도
				boolean flag = model.delete(num);

				// 삭제 성공 실패 출력(view)
				view.printIsDelete(flag);
			}
			else if(action == 0){
				break;
			}

		}
	}
}

 

>>client

package client;

import service.controller.StudentController;

public class Client02 {
	public static void main(String[] args) {
		
		// 학생부 프로그램
		StudentController app = new StudentController();
		app.start();
	}

}