저번 글과 이어지는 글 입니다
프로그램 흐름
1. 사용자의 입력을 받아 생성 / 검색 / 수정 / 삭제 / 출력 을 수행한다
2. 생성에는 회원 생성하기
3. 검색에는 아이디/이름/이메일 로 검색하기
4. 수정에는 비밀번호 / 이름 / 이메일 수정하기
5. 삭제에는 특정 회원 삭제하기 / 모든 회원 삭제하기
6. 종료

전체적인 패키지 구조입니다

MVC 패턴이 무엇인지 부터 보고 가겠습니다

MVC 패턴?
MVC 패턴은 소프트웨어 구조를 깔끔하게 나누어 유지보수·확장성을 높이는 아키텍처 패턴이다
M → Model (데이터)
V → View (화면)
C → Controller (흐름 / 로직제어)
이 글에서는 Service 와 Repository 도 함께 만들어 사용해보았습니다.
흐름 : [View] → [Controller] → [Service] → [ Repository ] → [ Model ]
메인
import member.view.MemberMenu;
public class Main {
public static void main(String[] args) {
// TODO Auto-generated method stub
new MemberMenu();
}
}
설명
- 실제 실행하는 Main 에서 view 에 해당되는 Menu 객체를 생성해 메서드를 시작한다.
메뉴 (view)
// 메인 메뉴 출력문구와 사용자 입력 문구
class UI {
void printMenu(boolean max) {
System.out.println( max ? "1. 새 회원 등록" : "회원 수가 모두 꽉 찼기 때문에 일부 메뉴만 오픈됩니다");
System.out.println("2. 회원 검색");
System.out.println("3. 회원 정보 수정");
System.out.println("4. 회원 삭제");
System.out.println("5. 모두 출력");
System.out.println("9. 끝내기");
printUserInput();
}
void printUserInput() {
System.out.print("#사용자 : ");
}
void printUserInput(String text) {
System.out.println();
System.out.print("#" + text + " :");
}
}
// 메인 메뉴 클래스
public class MemberMenu implements Search, Update, Delete {
Scanner sc = new Scanner(System.in);
MemberController mc = new MemberController();
UI show = new UI();
public MemberMenu() {
boolean max; // 회원 count
boolean isRunning = true; // 메인 메뉴 9번으로 탈출
while (isRunning) {
max = mc.existMemberNum() != 10; // 반복마다 회원 수 체크
show.printMenu(max);
try {
switch (sc.nextInt()) {
case 1:
if (!max) {
System.out.println("회원 수가 모두 꽉 찼기 때문에 일부 메뉴만 오픈됩니다");
break;
}
insertMember();
break;
case 2:
new SearchMember(this).run(sc);
break;
case 3:
new UpdateMember(this).run(sc);
break;
case 4:
new DeleteMember(this).run(sc);
break;
case 5:
printAll();
break;
case 9:
System.out.println("프로그램을 종료합니다");
isRunning = false;
break;
default:
System.out.println("잘못 입력하셨습니다. 다시 입력해주세요.");
}
// InputMismatchException => Int 가 아닌 다른 타입의 입력값이 들어오면 에러
} catch (InputMismatchException e) {
System.out.println("잘못된 입력입니다.");
System.err.println("에러코드 :" + e);
sc.next(); // 버퍼 안 비워주면 무한 에러
}
}
}
설명
- 정의해둔 interface implements
- 스캐너 생성 , 컨트롤러 객체 생성 , UI 객체생성 (출력문구 모음)
- 9를 입력받지 않으면 계속 반복
- switch 문으로 각 입력에 맞는 메서드 실행
- InputMismatchException 예외처리
각 케이스 별 설명
코드가 menu -> Controller -> service -> repo 까지 이어지는 경우가 있어
코드 혹은 사진으로만 대체하는 경우가 있습니다 .
사진 설명과 함께 눈으로 흐름만 읽어주세요
흐름 : [View] → [Controller] → [Service] → [ Repository ] → [ Model ]
menu - case 1
void insertMember() {
String id;
char gender;
System.out.println("===== 정보입력 =====");
while (true) { //재입력받기
show.printUserInput("아이디");
id = sc.next();
if (mc.checkId(id)) {
System.out.println("중복된 아이디입니다.");
continue;
}
break;
}
show.printUserInput("비밀번호");
String pw = sc.next();
show.printUserInput("이름");
String name = sc.next();
show.printUserInput("이메일");
String email = sc.next();
while (true) {//재입력받기
show.printUserInput("성별 m(M) / f(F)");
gender = sc.next().charAt(0);
if (mc.checkGender(gender)) {
break;
}
System.out.println("잘못된 성별 m(M) / f(F) 로만 입력해주세요");
}
show.printUserInput("나이");
int age = sc.nextInt();
System.out.println(mc.insertMember(id, name, pw, email, gender, age) ?
"회원 등록 완료":
"등록 오류");
}
설명
- 회원 생성을 위한 id,pw,name,email,gender,age 입력 받기
- id 는 컨트롤러에게 중복 검사를 받고 true를 받을때까지 반복
- gender는 컨트롤러에게 유효성검사를 받고 true를 받을때까지 반복


- 입력을 다 받고 컨트롤러에게 값을 전달 , 회원생성 후 결과를 출력
public boolean insertMember(String id, String name ,String password, String email, char gender, int age) {
try {
mRepo.addArr(id, name, password, email, gender, age);
//전달받은 값을 실제 데이터 저장/관리하는 repo 메서드로 넘겨준다
return true;
} catch (Exception e) {
return false;
}
}

menu - case 2 (전 글에서 다뤘기에 로직만 다루겠습니다)
new SearchMember(this).run(sc);
템플릿 메서드로 Search 클래스에서 호출되는 메서드

아이디 / 이름 / 이메일을 입력받아 컨트롤러에게 전달 하고
결과값을 출력한다 .
이름과 이메일은 문자열 타입의 ArrayList로 받아 반복문을 이용하여 출력한

ID 확인은 ID가 존재한다면 그 ID의 회원 정보를 RETURN
NAME, EMAIL 확인은 똑같이 name, email 이 존재한다면 그 존재를 ArrayList에 받아 반환
package member.service;
import java.util.ArrayList;
import member.member.Member;
public class SearchService {
Member[] members;
public SearchService(Member[] members) {
this.members = members;
}
public String SearchId (String id, String info) {
for(Member m : members) {
if(m == null) {break;}
if(id.equals(m.getId())) {
info = m.inform();
}
}
return info;
}
public ArrayList<String> searchName (String name) {
ArrayList<String> searchResults = new ArrayList<>();
for(Member m : members) {
if(m == null) {break;}
if(name.equals(m.getName())) {
searchResults.add(m.inform());
}
}
return searchResults;
}
public ArrayList<String> searchEmail (String email) {
ArrayList<String> searchResults = new ArrayList<>();
for(Member m : members) {
if(m == null) {break;}
if(email.equals(m.getEmail())) {
searchResults.add(m.inform());
}
}
return searchResults;
}
}
Search - Service (실제 로직)
m이 null 이라면 끝내고 (이게 중요함 , 이게 없을 때 null 오류가 계속해서 떠서 골치아팠음)
그렇지 않다면 model에서 가져오는 각각의 데이터 값과 같은 값이 존재한다면
그에 맞는 info를 리턴해주는 로직이다
menu - case 3 (전 글에서 다뤘기에 로직만 다루겠습니다)
new UpdateMember(this).run(sc);


package member.service;
import member.member.Member;
public class UpdateService {
Member[] members;
public UpdateService(Member[] members) {
this.members = members;
}
public boolean updatePassword(String id , String password) {
for(Member m : members) {
if(m == null) {break;}
if(id.equals(m.getId())) {
m.setPassword(password);
return true;
}
}
return false;
}
public boolean updateName(String id , String name) {
for(Member m : members) {
if(m == null) {break;}
if(id.equals(m.getId())) {
m.setName(name);
return true;
}
}
return false;
}
public boolean updateEmail(String id, String email) {
for(Member m : members) {
if(m == null) {break;}
if(id.equals(m.getId())) {
m.setEmail(email);
return true;
}
}
return false;
}
}
update - service

m이 null 이라면 끝내고
그렇지 않다면 model에서 가져오는 각각의 데이터 값과 같은 값이 존재한다면
model 에서 제공하는 get/set 메서드를 이용해서
입력받은 값으로 변경한다.
menu - case 4 (전 글에서 다뤘기에 로직만 다루겠습니다)
new DeleteMember(this).run(sc);


package member.service;
import member.member.Member;
import member.repo.MemberRepo;
public class DeleteService {
MemberRepo repo;
public DeleteService(MemberRepo repo) {
this.repo = repo;
}
public boolean delete(String id) {
Member[] arr = repo.getArr();
for (int i = 0; i < arr.length; i++) {
if (arr[i] == null) {
break;
}
if (id.equals(arr[i].getId())) {
for (int j = i; j < arr.length-1; j++) {
repo.updateArr(j);
}
repo.updateArrEnd();
return true;
}
}
return false;
}
public boolean deleteAll() {
repo.delAllArr();
return true;
}
}
delete - service (로직)

menu - case 5



package member.service;
import java.util.ArrayList;
import member.member.Member;
public class PrintService {
ArrayList<String> arr = new ArrayList<>();
PrintService () {}
public PrintService (Member[] members) {
arr.clear();
for(Member m : members) {
if(m == null) {break;}
arr.add(m.inform());
}
}
public ArrayList<String> getPrintAll() {
return arr;
}
}

전체 총 정리
- mvc 패턴을 사용해 구조를 깔끔하게 나누어 유지보수·확장성을 높인다
- 템플릿 메서드 패턴을 적용하면서 중복되던 메뉴 처리 코드가 사라졌다
- 제네릭 , 인터페이스에 대한 개념을 알게 되었다
- 컨트롤러에서 직접 데이터에 접근하기보다는 데이터를 관리하는 repo 를 만들어서 관리하는 게 더 좋다
- 코드가 조금 길고 파일이 많아져도 구조를 잡고 나눠서 하는 것이
유지보수와 확장에 도움이 된다 - 10번은 돌려보며 적용했지만 그래도 어렵다