39일차 - java (toString, 생성자특징, 객체지향적 프로그래밍 설계 - Repository, Controller, View, MemberList 등)

Yohan·2024년 4월 16일
0

코딩기록

목록 보기
54/156
post-custom-banner

toString()

  • toString 메서드는 객체가 가지고 있는 정보나 값들을 문자열로 만들어 리턴하는 메서드
    -> 객체의 정보를 출력해줌

toString() 특징

  • 명시하지 않아도 자동으로 적용됨
  • 아래처럼 클래스이름@16진수로_표시된_해시코드 형태의 문자열을 반환
public String toString() {
    return getClass().getName() + "@" + Integer.toHexString(hashCode());
}
  • 하지만 아래 예시처럼 format해준다면 내가 출력하고싶은 형태로 설정 가능!
    public String toString() {
        return String.format("# 이름: %s, 이메일: %s, 나이: %d세, 성별: %s, 가입일: %s"
                , this.memberName, this.email, this.age, this.gender, this.regDate);
    }

생성자 특징


  • 생성자를 하나도 선언하지 않으면 내용이 없는 가장 기본 형태의 생성자를 하나 생성해 주기 때문에 생성자 선언 없이도 객체 생성은 가능!

객체지향적 프로그래밍 설계

  • 역할은 최대한 나누어 분배하여 작성한다.
    -> 역할을 나누고 서로 이어지게 구성되도록 하는 것이 객체지향적 프로그래밍 !

Member

package day06.member;

import java.time.LocalDate;

// 역할: 회원정보 1개를 가지고 있어야 한다.
public class Member {

    int id; // 식별변호
    String email;
    String memberName;
    String password;
    String gender;
    int age;
    LocalDate regDate; // 회원가입일자

    // 생성자: 회원정보가 생성될 때 초기 데이터를 처리
    // -> 객체가 생성될 시점에 호출되는 함수로 객체의 초기화를 담당한다.
    // 시스템이 생성하는 데이터: 회원번호, 회원가입일자
    // 사용자가 제공하는 데이터: 이메일, 패스워드, 이름, 성별, 나이

    // 사용자가 제공해야하는 것은 생성자의 파라미터로 외부에서 입력하게 만듦
    Member(String email, String password, String memberName, String gender, int age) {
        this.id = 1;
        this.regDate = LocalDate.now(); // 현재 시간을 읽어서 처리

        this.email = email;
        this.password = password;
        this.memberName = memberName;
        this.gender = gender;
        this.age = age;
    }

    // toString: 객체의 정보를 출력할 수 있음 (자동호출되므로 따로 호출 필요 X)
    public String toString() {
        return String.format("# 이름: %s, 이메일: %s, 나이: %d세, 성별: %s, 가입일: %s"
                , this.memberName, this.email, this.age, this.gender, this.regDate);
    }

    // 회원의 비밀번호를 수정하는 메서드
    void changePassword(String newPassword) {
        this.password = newPassword;
    }
}

MemberList

  • 배열 필드 정의, 다양한 메서드 정의하여 Repository에는 온전한 기능만 들어갈 수 있게함
package day06.member;

// 역할: MemberRepository에서 배열필드를 정의하지않고 이 곳에 정의하여 가독성과 유지보수성을 올림
//      또한 배열을 다루는 다양한 메서드도 정의해놓았기 때문에
//      MemberRepository에서 간단하게 사용가능!
public class MemberList {

    Member[] mArr;

    MemberList() {
        this.mArr = new Member[0]; // 빈 배열
    }

    // 맨 끝에 추가
    void push(Member newMember) {
        Member[] temp = new Member[mArr.length + 1];
        for (int i = 0; i < mArr.length; i++) {
            temp[i] = mArr[i];
        }
        temp[temp.length - 1] = newMember;
        mArr = temp;
    }
    // 인덱스 찾기
    int findIndex(String email) {
        for (int i = 0; i < mArr.length; i++) {
            if (email.equals(mArr[i].email)) {
                return i;
            }
        }
        return -1;
    }
    // 한 명의 회원 정보 얻기
    Member get(String email) {
        int index = findIndex(email);
        return get(index);
    }
    Member get(int index) {
        return mArr[index];
    }

    // 맨 끝 제거
    Member pop() {
        // 맨 끝 회원 백업
        Member lastMember = mArr[mArr.length - 1];
        Member[] temp = new Member[mArr.length - 1];
        for (int i = 0; i < temp.length; i++) {
            temp[i] = mArr[i];
        }
        mArr = temp;
        return lastMember;
    }

    // 회원 정보 삭제
    Member remove(int index) {
        // 삭제 대상 백업
        Member removedMember = mArr[index];
        for (int i = index; i < mArr.length - 1; i++) {
            mArr[i] = mArr[i + 1];
        }
        pop();
        return removedMember;
    }
    Member remove(Member deleteMember) {
        int index = findIndex(deleteMember.email);
        return remove(index);
    }

    // 배열에 저장된 요소 수 리턴
    int size() {
        return mArr.length;
    }

    // 배열 리턴
    Member[] getMembers() {
        return mArr;
    }

}

Repository - 데이터 관리 (데이터 저장소)

package day06.member;

// 역할: 회원 배열을 관리하는 역할 - 회원 데이터 저장소
public class MemberRepository {

    // 필드
//    static Member[] members; // 현재 관리되는 회원 배열
//    static Member[] restoreList; // 삭제된 회원들이 모일 배열

    MemberList members;
    MemberList restoreList;

    // 생성자
    MemberRepository() {
//        this.members = new Member[3];
//        members[0] = new Member("abc@def.com", "1234", "콩순이", "여성", 50); 
//        members[1] = new Member("ghi@def.com", "5432", "팥돌이", "남성", 40);
//        members[2] = new Member("xyz@def.com", "7890", "팥죽이", "여성", 30);

        this.members = new MemberList();
        // push의 파라미터로 Member타입의 `객체`가 들어올 수 있기 때문에 Member클래스에서 만들었던 생성자가 들어갈 수 있음 (생성자는 객체 생성 역할 이기 때문에)
        members.push(new Member("abc@def.com", "1234", "콩순이", "여성", 50)); 
        members.push(new Member("ghi@def.com", "5432", "팥돌이", "남성", 40));
        members.push(new Member("xyz@def.com", "7890", "팥죽이", "여성", 30));

        this.restoreList = new MemberList();
    }

    // 메서드


    /**
     * 생성된 회원정보를 회원 배열에 끝에 추가하는 기능
     * @param newMember - 사용자의 입력으로 전달된 회원 정보 객체
     */
    void addNewMember(Member newMember) {

        // 배열에 데이터를 추가하는 로직
//        Member[] temp = new Member[members.length + 1];
//        for (int i = 0; i < members.length; i++) {
//            temp[i] = members[i];
//        }
//        temp[temp.length - 1] = newMember;
//        members = temp;

        members.push(newMember);
    }

    /**
     * 이메일 중복을 확인하는 기능
     * @param targetEmail - 검사할 사용자의 입력 이메일 값
     * @return - 이메일이 이미 존재한다면 true,
     *           존재하지 않는 사용가능한 이메일이면 false
     * @author - 코딩킹
     * @since 2024.04.16
     */
    boolean isDuplicateEmail(String targetEmail) {
        // 이메일을 통해 회원을 찾았다면 이미 존재한다는 것이므로 (= 중복) true
        return findMemberByEmail(targetEmail) != null;
    }

    /**
     * 이메일을 통해 회원의 모든 정보(객체)를 가져오는 메서드
     * @param inputEmail - 사용자가 입력한 이메일값
     * @return - 해당 이메일을 통해 찾아낸 회원 객체,
     *           만약 찾지 못하면 null을 리턴
     */
    public Member findMemberByEmail(String inputEmail) {
//        for (Member m : members) {
//            if (inputEmail.equals(m.email)) {
//                return m;
//            }
//        }
//        return null;

        return members.get(inputEmail);
    }

//    int findIndex(String email) {
//        for (int i = 0; i < members.length; i++) {
//            if (email.equals(members[i].email)) {
//                return i;
//            }
//        }
//        return -1;
//    }

    // 배열에서 회원정보 삭제 (복구 리스트에 담기)
    public void removeMember(String inputEmail) {

//        int index = findIndex(inputEmail);
        int index = members.findIndex(inputEmail);

        if (index == -1) return;
//        for (int i = index; i < members.length - 1; i++) {
//            members[i] = members[i + 1];
//        }
//
//        Member[] temp = new Member[members.length - 1];
//        for (int i = 0; i < temp.length; i++) {
//            temp[i] = members[i];
//        }
//        members = temp;

        Member deletedMember = members.remove(index);
        restoreList.push(deletedMember);
    }
}

View - 데이터 관리를 위한 입력, 출력

package day06.member;

import day06.util.SimpleInput;

// 역할: 회원 데이터 관리를 위해 "입력 출력"을 담당함
public class MemberView {

    // 객체의 협력
    MemberRepository mr;
    SimpleInput si;

    MemberView() {
        this.mr = new MemberRepository();
        this.si = new SimpleInput();
    }

    void showMembers() {
        System.out.printf("========= 현재 회원 목록 (총 %d명) ==========\n", mr.members.size());
        for (Member m : mr.members.getMembers()) {
            System.out.println(m);
        }
    }

    // 회원정보 생성을 위해 입력을 처리
    void inputNewMember() {
        String email = null;
        while (true) {
            email = si.input("- 이메일: ");
            // 이메일이 중복되는지 확인
            // 중복되지 않는 이메일이라면 while문 탈출
            if (!mr.isDuplicateEmail(email)) {
                break;
            }
            System.out.println("중복된 이메일입니다.");
        }

        String name = si.input("- 이름: ");
        String password = si.input("- 패스워드: ");
        String gender = si.input("- 성별: ");
        int age = Integer.parseInt(si.input("- 나이: "));

        // 입력데이터를 기반으로 한명의 회원 객체를 생성
        Member newMember = new Member(email, password, name, gender, age);

        // 위임 - 관심사의 분리
        mr.addNewMember(newMember);
    }

    // 사용자에게 보여줄 전체 메뉴 화면 출력
    String showProgramMenu() {
        System.out.println("\n##### 회원 관리 시스템 #####");
        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("=============================");

        String menuNumber = si.input("- 메뉴 번호: ");
        return menuNumber;
    }

    // 프로그램 종료를 판단하는 입출력
    boolean exitProgram() {
        String exit = si.input("- 프로그램을 종료합니까? [y/n]\n>> ");
        if (exit.equals("y")) {
            System.out.println("프로그램을 종료합니다!");
            return true;
        }
        else {
            System.out.println("프로그램 종료를 취소합니다.");
            return false;
        }
    }

    // 이메일 입력받고 찾은 회원정보를 출력
    public void getMember() {
        String inputEmail = si.input("# 조회하실 회원의 이메일을 입력하세요.\n>> ");

        // 이메일이 일치하는 회원이 있는지 조회
        Member foundMember = mr.findMemberByEmail(inputEmail);

        if (foundMember != null) {
            System.out.println("============= 조회 결과 ============");
            System.out.println("# 이름: " + foundMember.memberName);
            System.out.println("# 비밀번호: " + foundMember.password);
            System.out.println("# 성별: " + foundMember.gender);
            System.out.println("# 나이: " + foundMember.age);
            System.out.println();
        } else {
            System.out.println("\n# 해당 회원은 존재하지 않습니다.");
        }
    }

    // 수정 대상의 이메일을 입력받고 조회에 성공하면 패스워드를 수정
    public void updatePassword() {
        String inputEmail = si.input("# 수정하실 회원의 이메일을 입력하세요.\n>> ");

        // 이메일이 일치하는 회원이 있는지 조회
        Member foundMember = mr.findMemberByEmail(inputEmail);

        if (foundMember != null) {

            // 기존 비밀번호를 입력해주세요

            // 비번 수정
            System.out.printf("# %s님의 비밀번호를 변경합니다.\n", foundMember.memberName);
            String newPassword = si.input("# 새 비밀번호: ");

            // 회원정보 실제로 수정
//            foundMember.password = newPassword;
            foundMember.changePassword(newPassword);

            System.out.println("# 비밀번호 변경이 완료되었습니다.");
        } else {
            System.out.println("\n# 해당 회원은 존재하지 않습니다.");
        }
    }

    public void deleteMember() {
        String inputEmail = si.input("# 삭제하실 회원의 이메일을 입력하세요.\n>> ");

        // 이메일이 일치하는 회원이 있는지 조회
        Member foundMember = mr.findMemberByEmail(inputEmail);

        if (foundMember != null) {
            // 삭제 진행
            // 패스워드 검사
            String inputPw = si.input("# 비밀번호를 입력: ");
            if (inputPw.equals(foundMember.password)) {
                mr.removeMember(inputEmail);
                System.out.println("# 회원 탈퇴가 처리되었습니다. 복구하시려면 복구메뉴를 이용하세요.");
            } else {
                System.out.println("\n# 비밀번호가 일치하지 않습니다. 탈퇴를 취소합니다.");
            }
        } else {
            System.out.println("\n# 해당 회원은 존재하지 않습니다.");
        }

    }
}

Controller - 분기

package day06.member;

import day06.util.SimpleInput;

// 역할: 사용자의 메뉴 입력을 분기하는 역할
public class MemberController {

    MemberView mv;
    SimpleInput si;

    MemberController() {
        this.mv = new MemberView();
        this.si = new SimpleInput();
    }

    // 메뉴 입력 분기에 따라 할 일을 나눠주는 기능
    void run() {

        while (true) {
            String menuNum = mv.showProgramMenu();

            switch (menuNum) {
                case "1":
                    mv.inputNewMember();
                    break;
                case "2":
                    // 이메일을 입력받아서 회원을 개별조회 해주는 코드
                    mv.getMember();
                    break;
                case "3":
                    mv.showMembers();
                    break;
                case "4":
                    mv.updatePassword();
                    break;
                case "5":
                    mv.deleteMember();
                    break;
                case "6":
//                    mv.restoreMember();
                    break;
                case "7":
                    boolean flag = mv.exitProgram();
                    if (flag) return; // true면 종료
            } // end switch
            si.stopInput();
        } // end while
    }
}

SimpleInput - 스캐너 입력을 간소화

package day06.util;

import java.util.Scanner;

// 역할: 스캐너 입력을 간소화해주는 객체
public class SimpleInput {

    Scanner sc = new Scanner(System.in);

    // 문자열 입력을 처리
    public String input(String message) {
        System.out.print(message);
        return sc.nextLine();
    }

    // 엔터를 누르기 전까지 멈춰 있는 기능
    public void stopInput() {
        System.out.println("\n=========== 엔터를 누르면 계속 … ============");
        sc.nextLine();
    }
}

Main - 실행

package day06.member;

import day06.util.SimpleInput;

import java.util.Scanner;

public class Main {

    public static void main(String[] args) {

        MemberController mc = new MemberController();

        mc.run();
    }
}

정리

  1. MemberList에 private Member[] mArr; 로 Member 배열로 필드를 등록함으로써 Member 객체만 포함될 수 있게했음
  2. MemberRepository에서는 MemberList members; MemberList restoreList; MemberList 타입을 참조하는 필드를 등록
    this.members = new MemberList(); this.restoreList = new MemberList(); MemberList 객체를 생성함으로써 MemberList 클래스를 통해 배열을 관리, 조작할 수 있음 (MemberList 필드, 메서드 사용)
profile
백엔드 개발자
post-custom-banner

0개의 댓글