TIL. 배열, 클래스,생성자,메소드를 통한 프로그램 완성, 2차원 배열

hyuko·2023년 1월 9일
0

Java

목록 보기
19/26

배열과 클래스 그리고 생성자 프로그램

  • 클래스를 각각의 이용 용도마다 나누어 생성하여 사용한다.

  • 설계

    • 클래스의 객체를 다루는 User 클래스
    • 그 객체들을 담아서 저장하고 수정하는 UserRepository 클래스
    • UserRepository의 정보를 가지고 비지니스 로직을 담아두는 UserService클래스
    • 실제로 실행을 하는 UserMain 클래스

우리는 구조를 지금 이해하기 힘들지만 DI 를하는 구조로 짜게된다.
DI란? Dependency Injection의 약자로 의존성 주입을 뜻한다.
우리가 만들 프로그램, 웹등은 클래스 끼리 의존을 할 수 밖에 없는데
그 의존하는 것을 해당하는 클래스의 밖에서 주입을 해주는 것을 의존성 주입이라고 한다. 우리는 일단 이러하다라는 개념을 가지고 시작한다.

객체지향의 의존성 주입중에는 생성자 주입과 Setter를 통한 주입이 있다.

  • 생성자 주입: 생성을 할 당시에 주입을 해주는 것.
  • Setter를 통한 주입: 추후에 Setter를 통해 주입해주는 것.

객체의 정보를 담는 User 클래스

  • 이 클래스 같은 경우 붕어빵 틀처럼 여러개를 찍어낼 수 있게 기본 정보를 담는다
// 정보를 담는 객체 - >  Entity 객체
// 실행을 담당하는 객체 (기능을 담당하는 객체) -> 서비스 객체
public class J12_User {
	private String username;	// 사용자이름(아이디, 계정)
	private String password;	// 사용자비밀번호
	private String name;		// 실제이름(성명)
	private String email;		// 이메일
	
	public J12_User() {} 		// ctrl + spacebar
	
	// alt + shift + s -> generated constructor using fields
    // 전체 생성자
	public J12_User(String username, String password, String name, String email) {
		this.username = username;
		this.password = password;
		this.name = name;
		this.email = email;
	}

	// alt + shift + s -> generated Getters and Setters
	public String getUsername() {
		return username;
	}

	public void setUsername(String username) {
		this.username = username;
	}

	public String getPassword() {
		return password;
	}

	public void setPassword(String password) {
		this.password = password;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public String getEmail() {
		return email;
	}

	public void setEmail(String email) {
		this.email = email;
	}

	// alt + shift + s -> generated toString(); 정보에는 클래스명, 변수에 어떤 값이 담겨 있는지 표현해준다. 
	//	이전까지 했던 printInfo 메서드와 비슷한 개념
	
	@Override
	public String toString() {
		return "J12_User [username=" + username + ", password=" + password + ", name=" + name + ", email=" + email
				+ "]";
	}
}

위의 코드를 보면 알 수 있듯이 기본적으로 들어가는 User의 정보들을 정보은닉
하기위해 private로 막아놓고 생성자와 getter, setter를 통해 소통할 수 있게 public을
열어놓은 것을 볼 수 있다.


User 객체를 생성하여 저장하고 수정하는 Repository

  • 여러가지 많은 User라는 객체를 생성할 수 있고 이 정보를 저장하는 로직이 담겨있다.
    이 정보가 저장이 되어 저장된 정보로 service에서 비지니스 로직을 실행할 수 있다.

  • CheckPoint ! 우리는 아직 DB에 대한 개념을 배우지 않았고, 배열만 배웠기에
    이번 repository의 저장 매체는 배열로 저장을 한다.

// 저장소 개념 repository
public class J12_UserRepository {

	private J12_User[] userTable;

	public J12_UserRepository(J12_User[] userTable) {
		this.userTable = userTable;
		
	}
	
	public J12_User[] getUserTable() {
		return userTable;
	}
	
    // user 객체 정보를 저장하는 기능
	public void saveUser(J12_User user) {
		extendArrayOne();
		userTable[userTable.length - 1] = user;
	}
	
	
	private void extendArray(int length) {
		J12_User[] newArray = new J12_User[userTable.length + length];
		trasferDataToNewArray(userTable, newArray);
		userTable = newArray;
	}
	
    // 배열의 크기를 한칸 늘려 주는 기능
	private void extendArrayOne() {
		J12_User[] newArray = new J12_User[userTable.length + 1];
		trasferDataToNewArray(userTable, newArray);
		userTable = newArray;
	}
	
    // 기존의 배열에 있던 정보를 새로운 배열이 생성이 될 때 주입을 해주는 기능
	private void trasferDataToNewArray(J12_User[] oldArray, J12_User[] newArray) {
		for(int i = 0; i < oldArray.length; i++) {
			newArray[i] = oldArray[i];
		}
	}
	
    // 객체정보중 username 의 정보를 비교해서 찾는 기능
    // 반환값이 J12_User로 user객체를 반환한다.
	public J12_User findUserByUsername(String username) {
		J12_User user = null;
		
		for(J12_User u : userTable) {
			if(u == null) {
				continue;
			}
			if(u.getUsername().equals(username)) {
				user = u;
				break;
			}
		}
		
		return user;
	}
	
}

배열은 길이가 고정이 되서 선언이 되게되면 바꾸기가 힘들다 .
그래서 우리는 얼마나 정보가 들어갈지 모르고 정보가 들어올 때 마다
배열의 길이를 한칸씩 늘려 이전 정보는 그대로 들고가면서 새로운 정보만
늘어난 배열의 칸에 넣어주는 작업을 하기위해 위와 같은 코드를 짜게되었다.


저장된 정보를 통해 비지니스 로직을 담당하는 Service 클래스

  • service 클래스에서는 우리가 프로그램에서 실행하고 실행됬을 때 작동하는 여러가지
    작동들을 코드를 통해 작업하는 곳이다.

  • 우리가 프로그램을 통해 유저의 정보를 입력을 통해 받는 행위, 저장하는 행위,
    전체 등록 회원을 보여주는 행위, 사용자의 이름을 비교하여 그 사용자의 정보만 보여주는 행위,
    원하는 사용자의 이름을 입력 후 수정하는 행위등의 기능을 넣을 예정이다

  • 위에 말한 각각의 행위들은 메소드로 정의가 될 수 있고 우리는 이렇게 최대한 기능에 따라
    메소드를 나누어 작업을 해볼 것이다.


// 서비스 클래스 (기능 , 로직등)
public class J12_UserService {
	
	private Scanner scanner;
    // 우리는 repository의 정보를 써야하기에 전역에 선언해준다.
	private J12_UserRepository repository;
	
	// 하지만 결합을 낮추기 위해 생성자 주입을 하기위해서 
    // 서비스가 생성이 될 때 repository를 메인 함수에서 받아온다.
	public J12_UserService(J12_UserRepository repository) {
		scanner = new Scanner(System.in);
		this.repository = repository;
		
	}
	
    // 실행하는 메소드
    // 그야말로 실행만하는 함수이다.
	public void run() {
		boolean loopFlag = true;
		char select = '\0';
		
		while(loopFlag) {
			showMainMenu();
			select = inputSelect("메인");
			loopFlag = mainMenu(select);
		}
	}
	
    // 프로그램이 멈추면 작동하는 메소드
	public void stop() {
		for(int i = 0; i < 10; i++) {
			try {
				Thread.sleep(500);
				System.out.println("프로그램 종료중....(" + (i + 1) + "/10)");
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		System.out.println("프로그램 종료");
	}
	
    // 우리가 입력받을 값에 대한 메소드
	private char inputSelect(String menuName) {
		System.out.print(menuName + "메뉴 선택: ");
		char select = scanner.next().charAt(0);
		scanner.nextLine();
		return select;
	}
    
    
	// 단순히 보여지는 콘솔 메인화면
	private void showMainMenu() {
		System.out.println("========<< 메인메뉴 >>========");
		System.out.println("1. 회원 전체 조회");
		System.out.println("2. 회원 등록");
		System.out.println("3. 사용자이름으로 회원 조회");
		System.out.println("4. 회원 정보 수정");
		System.out.println("==============================");
		System.out.println("q. 프로그램 종료");
		System.out.println();
	}
	
    // 회원 전체조회에 관한 메소드
	private void showUsers() {
		J12_User[] users = repository.getUserTable();
		
		System.out.println("========<< 회원 전체 조회 >>========");
		
		for(J12_User user : users) {
			System.out.println(user.toString());
		}
		
		System.out.println("====================================");
	}
	
	// 회원 저장에 관한 메소드
	private void registerUser() {
		String username = null;
		String password = null;
		String name = null;
		String email = null;
		
		System.out.println("========<< 회원 등록 >>========");
		System.out.print("사용자 이름: ");
		username = scanner.nextLine();
		
		System.out.print("사용자 비번: ");
		password = scanner.nextLine();
		
		System.out.print("사용자 성명: ");
		name = scanner.nextLine();
		
		System.out.print("사용자 메일: ");
		email = scanner.nextLine();
				
		System.out.println("===============================");
		
        // 이것 또한 생성자를 이용한 주입
		J12_User user = new J12_User(username, password, name, email);
		repository.saveUser(user);
	}
	
    // 내가 입력한 정보의 user만 조회하는 기능
	private void showUser() {
		J12_User user = null;
		
		System.out.println("============<<회원 조회>>============");
		user = verifyUsername();
		
//		System.out.println("사용자이름 입력: ");
//		username = scanner.nextLine();
//		
//		user = repository.findUserByUsername(username);
		
		if(user == null) {
			System.out.println("존재하지 않는 사용자이름입니다.");
			return;
		}
		
		System.out.println(user.toString());
		System.out.println("====================================");
	}
	
    // username 을 비교하여 user값을 반환해주는 메소드
	private J12_User verifyUsername() {
		String username = null;
		System.out.println("사용자이름: ");
		username = scanner.nextLine();
		return repository.findUserByUsername(username);
	}
	
    // 메인 화면에 대한 실질적인 선택로직
	private boolean mainMenu(char select) {
		boolean flag = true;
		
		if(isExit(select)) {
			flag = false;
			
		}else {
			if(select == '1') {
				showUsers();
			}else if(select == '2') {
				registerUser();
			}else if(select == '3') {
				showUser();
			}else if(select == '4') {
				updateUser();
			}else {
				System.out.println(getSelectedErrorMessage());
			}
		}
		System.out.println();
		
		return flag;
	}
	
    // 유저의 정보를 수정하는 기능
	private void updateUser() {
		J12_User user = verifyUsername();
		
		if(user == null) {
			System.out.println("존재하지 않는 사용자 이름입니다.");
			return;
		}
		
		boolean updateLoopFlag = true;
		char select = '\0';
		
		while(updateLoopFlag) {
			
			showUpdateMenu(user);
			select = inputSelect("수정");
			updateLoopFlag = updateMain(user, select);
			
			
		}
	}
	
	private void showUpdateMenu(J12_User user) {
		System.out.println("==========<< 수정 메뉴 >>===========");
		System.out.println("사용자이름 : " + user.getUsername());
		System.out.println("====================================");
		System.out.println("1. 비밀번호 변경");
		System.out.println("2. 이름 변경");
		System.out.println("3. 이메일 변경");
		System.out.println("====================================");
		System.out.println("b. 뒤로가기");
		System.out.println();
	}
	
	private boolean updateMain(J12_User user, char select) {
		
		boolean flag = true;
		
		if(isBack(select)) {
			flag = false;
			
		}else if(select == '1') {
			updatePassword(user);
		}else if(select == '2') {
			updateName(user);
		}else if(select == '3') {
			updateEmail(user);
		}else {
			System.out.println(getSelectedErrorMessage());
		}
		return flag;
	}

	
	private void updatePassword(J12_User user) {
		String oldPassword = null; 
		String newPassword = null; 
		String newPasswordCheck = null;
		
		System.out.println("============<<비번 변경>>============");
		
		System.out.println("기존의 비밀번호를 입력하세요");
		oldPassword = scanner.nextLine();
		
		if(!compareVeriable(user.getPassword(), oldPassword)) {
			System.out.println("비밀번호 서로 일치하지 않습니다");
			return;
		}
		
		System.out.print("새로운 비밀번호를 입력하세요: ");
		newPassword = scanner.nextLine();
		System.out.print("새로운 비밀번호를 확인해주세요: ");
		newPasswordCheck = scanner.nextLine();
		
		if(!compareVeriable(newPassword, newPasswordCheck)) {
			System.out.println("비밀번호가 일치하지 않습니다.");
			return;
		}
		
		user.setPassword(newPassword);
		System.out.println("비밀번호 변경 완료");
	}
	
	
	
	private void updateName(J12_User user) {
		String oldName = null; 
		String newName = null; 
		String confirmName = null;
		
		System.out.println("============<<이름 변경>>============");
		
		System.out.println("기존의 이름을 입력하세요");
		oldName = scanner.nextLine();
		
		if(!compareVeriable(user.getName(), oldName)) {
			System.out.println("이름이 서로 일치하지 않습니다");
			return;
		}
		
		System.out.print("새로운 이름을 입력하세요: ");
		newName = scanner.nextLine();
		System.out.print("새로운 이름을 확인해주세요: ");
		confirmName = scanner.nextLine();
		
		if(compareVeriable(newName, confirmName)) {
			System.out.println("이름이 일치하지 않습니다.");
			return;
		}
		
		user.setName(newName);
		System.out.println("이름 변경 완료");
	}
	
	private void updateEmail(J12_User user) {
		String oldEmail = null; 
		String newEmail = null; 
		String confirmEmail = null;
		
		System.out.println("============<<메일 변경>>============");
		
		System.out.println("기존의 이메일을 입력하세요");
		oldEmail = scanner.nextLine();
		
		if(!compareVeriable(user.getEmail(), oldEmail)) {
			System.out.println("이메일이 서로 일치하지 않습니다");
			return;
		}
		
		System.out.print("새로운 이메일을 입력하세요: ");
		newEmail = scanner.nextLine();
		System.out.print("새로운 이메일을 확인해주세요: ");
		confirmEmail = scanner.nextLine();
		
		if(compareVeriable(newEmail, confirmEmail)) {
			System.out.println("이메일이 일치하지 않습니다.");
			return;
		}
		
		user.setEmail(newEmail);
		System.out.println("이메일 변경 완료");
	}
	
	private boolean compareVeriable(String preVeriable, String nextVeriable) {
		return preVeriable.equals(nextVeriable);
	}
	
	private boolean isBack(char select) {
		return select == 'b' || select == 'B';
	}
	
	
	private boolean isExit(char select) {
		return select == 'q' || select == 'Q';
	}
	
	private String getSelectedErrorMessage() {
		return "###<<< 잘못된 입력입니다, 다시 입력하세요. >>>###";
	}
}

최대한 공통적으로 사용하는 부분은 아무리 짧아도 메소드로 빼서 활용을 하고,
최대한 전역변수는 사용하지 않으면서 코드를 작성한다.


2차원 배열

  • 오늘 2차원 배열은 아주 간단히 구조만 볼 예정이다.

  • 2차원 배열이란?

    배열을 가지고 있는 배열이다.

  • 2차원 배열의 선언


int[][] nums = new int[2][3];

 // or
 
int[][] nums2 = new int[][]{{1,2,3}, {4,5,6}}

주의점: 보통 int[] num = new int[1]; 이라는 배열이 있고 배열에 배열이 있다는
개념을 가지고 보면 순서대로 위의 코드를 해석해서 2칸의 배열을 가지고 있는 3칸의 배열로
오해하기 쉽다.
2차원 배열을 생각할 때는 바깥의 배열의 크기는 안에 있는 배열의 크기를 의미하고,
안에 있는 크기는 밖의 배열의 크기라고 생각해야 한다. 자주 혼동할 수 있으니
확실히 개념을 세워 두자!!


profile
백엔드 개발자 준비중

0개의 댓글