Q. 전화번호 관리 프로그램 08단계 문제
프로그램이 종료되면 프로그램의 실행 중에 입력된 데이터를 파일에 저장하고,
프로그램이 다시 실행되면 파일에 저장된 데이터를 프로그램 상으로 복원하는 기능을 추가하자.
그래서 한번 저장된 데이터는 프로그램 상에서 계속 유지되도록 하자.
몇 번이건 프로그램을 재실행해도 말이다.
단, 파일로의 데이터 입출력은 인스턴스 단위로 진행을 하자.
즉, ObjectInputStrem 클래스와 ObjectOutputStream 클래스 기반으로
스트림을 생성해서 데이터를 입출력하자는 뜻이다.
도움 한마디!
본 프로젝트에서 파일에 저장되어야 할 인스턴스의 자료형은
다음과 같이 총 세가지이다.
- PhoneInfo class
- PhoneUnivInfo class
- PhoneCompanyInfo class
그런데 거의 모든 상황에서 PhoneInfo형 참조변수로 인스턴스를 참조하고 있다.
그렇다면 다음과 같은 방식으로 파일에 인스턴스를 저장하면 과연 무엇이 저장되겠는가?
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("Personal.ser"));
PhoneInfo info1 = new PhoneUnivInfo(...);
out.writeObject(info1);
PhoneInfo info1 = new PhoneComapnyInfo(...);
out.writeObject(info2);
ObjectOutputStream 기반으로 인스턴스를 저장하기 위해서는
writeObject 메소드를 호출하면서 참조변수를 전달해야 한다.
그런데 여기서 중요한 것은 참조변수의 자료형이 아니라, 참조변수가 실제로 참조하는 인스턴스의 자료형이다.
즉, 위의 코드에서 info1과 info2는 모두 PhoneInfo형 참조변수이지만,
실제 참조하는 대상이 각각 PhoneUnivInfo 인스턴스와 PhoneCompanyInfo 인스턴스이기 때문에
실제로 저장되는 대상은 PhoneUnivInfo 인스턴스와 PhoneCompanyInfo 인스턴스이다.
A. 강사님의 답 - HashSet 저장 ver (아래의 PhoneInfo ver보다 훨씬 간결하다)
public interface Menu {
int INSERT_PHONE_INFO=1; // 상수로 준 이유 : 가독성을 높이기 위해서
int SEARCH_PHONE_INFO=2;
int DELETE_PHONE_INFO=3;
int SHOW_ALL_PHONE_INFO=4;
int QUIT_PHONE_INFO=5;
}
public class MenuChoiceException extends Exception {
public MenuChoiceException(int menu)
{
super(menu + "에 해당하는 선택은 존재하지 않습니다.\n" +
"메뉴 선택을 처음부터 다시 진행합니다.");
}
}
import java.io.Serializable;
public class PhoneInfo implements Serializable{
private String name;
private String phoneNumber;
public PhoneInfo(String name, String phoneNumber) {
this.name = name;
this.phoneNumber = phoneNumber;
}
public String getName() {
return name;
}
public String getPhoneNumber() {
return phoneNumber;
}
public void printCurrentState()
{
System.out.println("이름 : " + name);
System.out.println("전화번호 : " + phoneNumber);
}
@Override
public boolean equals(Object obj) {
return phoneNumber.equals(((PhoneInfo)obj).phoneNumber);
}
@Override
public int hashCode() {
return phoneNumber.hashCode();
}
}
public class PhoneUnivInfo extends PhoneInfo {
private String major;
private int year;
public PhoneUnivInfo(String name, String phoneNumber, String major, int year) {
super(name, phoneNumber);
this.major = major;
this.year = year;
}
@Override
public void printCurrentState() {
super.printCurrentState();
System.out.println("전공 : " + major);
System.out.println("학년 : " + year);
}
}
public class PhoneCompanyInfo extends PhoneInfo {
private String company;
public PhoneCompanyInfo(String name, String phoneNumber, String company) {
super(name, phoneNumber);
this.company = company;
}
@Override
public void printCurrentState() {
super.printCurrentState();
System.out.println("회사 : " + company);
}
}
import java.util.Scanner;
public class PhoneBookUI {
private PhoneBook pb;
public static Scanner sc = new Scanner(System.in);
public PhoneBookUI()
{
this.pb = PhoneBook.getPhoneBook();
}
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("선택 : ");
}
public void inputMenu()
{
System.out.println("데이터 입력을 시작합니다.");
System.out.println("1. 일반, 2. 대학, 3. 회사");
System.out.print("선택 >>");
}
public void inputPhoneInfo(int menu)
{
String name, phoneNumber, major, company;
int year=0;
boolean result;
PhoneInfo phoneInfo = null;
System.out.println("데이터 입력을 시작합니다.");
System.out.println("이름 : ");
name = sc.nextLine();
System.out.println("전화번호 : ");
phoneNumber = sc.nextLine();
if(menu == 1) // 추가
phoneInfo = new PhoneInfo(name, phoneNumber);
else if(menu == 2)
{
System.out.println("전공 : ");
major = sc.nextLine();
System.out.println("학년 : ");
year = sc.nextInt();
phoneInfo = new PhoneUnivInfo(name, phoneNumber, major, year);
}
else if(menu==3)
{
System.out.println("회사 : ");
company = sc.nextLine();
phoneInfo = new PhoneCompanyInfo(name, phoneNumber, company);
}
result = pb.insertPhoneInfo(phoneInfo);
if(result == false)
System.out.println("이미 등록된 데이터 입니다.");
else System.out.println("데이터 입력이 완료되었습니다.");
}
public void searchPhoneInfoByName()
{
String name;
System.out.println("검색하시고자 하는 이름을 입력해 주세요.");
name = sc.nextLine();
System.out.println("사용자 검색을 시작합니다.");
if( !pb.searchPhoneInfoByName(name)) System.out.println("찾으시는 사용자가 없습니다.");
}
public void deletePhoneInfoByPhoneNumber()
{
String phoneNumber;
System.out.println("삭제하시고자 하는 전화번호를 입력해 주세요.");
phoneNumber = sc.nextLine();
boolean result = pb.deletePhoneInfoByPhoneNumber(phoneNumber);
if(result) System.out.println("삭제가 완료되었습니다.");
else System.out.println("삭제하시고자 하는 전화번호 정보가 없습니다.");
}
public void printAllPhoneInfo()
{
System.out.println("모든 사용자 정보를 출력합니다.");
pb.printAllPhoneInfo();
}
public void quitProgram()
{
System.out.println("프로그램을 종료합니다.");
pb.quitProgram();
sc.close();
}
}
import java.util.Scanner;
public class PhoneMain{
public static void main(String[] args) {
int menu=0;
PhoneBookUI pbUI = new PhoneBookUI();
Scanner sc = PhoneBookUI.sc;
while(true)
{
pbUI.printMenu();
try
{
menu = sc.nextInt();
sc.nextLine();
if(menu<Menu.INSERT_PHONE_INFO || menu > Menu.QUIT_PHONE_INFO)
{
throw new MenuChoiceException(menu);
}
switch(menu)
{
case Menu.INSERT_PHONE_INFO:
pbUI.inputMenu();
menu = sc.nextInt();
sc.nextLine();
if(menu<1 || menu > 3)
{
throw new MenuChoiceException(menu);
}
pbUI.inputPhoneInfo(menu);
break;
case Menu.SEARCH_PHONE_INFO:
pbUI.searchPhoneInfoByName();
break;
case Menu.DELETE_PHONE_INFO:
pbUI.deletePhoneInfoByPhoneNumber();
break;
case Menu.SHOW_ALL_PHONE_INFO:
pbUI.printAllPhoneInfo();
break;
case Menu.QUIT_PHONE_INFO:
pbUI.quitProgram();
return;
}
}
catch(MenuChoiceException e)
{
System.out.println(e.getMessage());
}
}
}
}
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.HashSet;
import java.util.Iterator;
public class PhoneBook {
private static PhoneBook pb;
private HashSet<PhoneInfo> set;
private Iterator<PhoneInfo> itr;
private ObjectInputStream objInStream;
private ObjectOutputStream objOutStream;
private PhoneBook() // 생성되자마자 바로 loadData를 가지고 오기 위해서
{
loadData();
}
public void loadData()
{
try {
objInStream = new ObjectInputStream(new FileInputStream("phoneInfo.data"));
// 직렬화 : 객체 정보를 어떠한 형태로 변환시키는 것
} catch (FileNotFoundException e) {
set = new HashSet<PhoneInfo>(); // 새 인스턴스를 만드는 것, NullPointException 방지 위함
} catch (IOException e) {
e.printStackTrace(); // 에러 발생한 위치를 순차적으로 보여주는 것
}
try {
if(objInStream != null)
set = (HashSet<PhoneInfo>)objInStream.readObject(); // 객체를 읽어오는 것
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
try {
if(objInStream != null)
objInStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
public static PhoneBook getPhoneBook()
{
if(pb==null)
pb = new PhoneBook();
return pb;
}
public boolean insertPhoneInfo(PhoneInfo phoneInfo)
{
return set.add(phoneInfo);
}
public boolean searchPhoneInfoByName(String name)
{
PhoneInfo pInfo = null;
itr = set.iterator();
boolean result = false;
while(itr.hasNext())
{
pInfo = itr.next();
if(pInfo.getName().equals(name))
{
pInfo.printCurrentState();
result = true;
}
}
return result;
}
public boolean deletePhoneInfoByPhoneNumber(String phoneNumber)
{
PhoneInfo pInfo = null;
itr = set.iterator();
while(itr.hasNext())
{
pInfo = itr.next();
if(pInfo.getPhoneNumber().equals(phoneNumber))
{
itr.remove();
return true;
}
}
return false;
}
public void printAllPhoneInfo()
{
itr = set.iterator();
while(itr.hasNext())
{
itr.next().printCurrentState();
}
}
public void quitProgram() {
if(set.size() == 0) return;
try {
objOutStream = new ObjectOutputStream(new FileOutputStream("phoneInfo.data"));
} catch (FileNotFoundException e1) {
e1.printStackTrace();
} catch (IOException e1) {
e1.printStackTrace();
}
try {
objOutStream.writeObject(set); // 객체를 저장하는 것
} catch (IOException e1) {
e1.printStackTrace();
}
try {
objOutStream.close();
} catch (IOException e1) {
System.out.println("파일 닫기 오류");
e1.printStackTrace();
}
}
}
A. 강사님의 답 - PhoneInfo 저장 ver
public interface Menu {
int INSERT_PHONE_INFO=1; // 상수로 준 이유 : 가독성을 높이기 위해서
int SEARCH_PHONE_INFO=2;
int DELETE_PHONE_INFO=3;
int SHOW_ALL_PHONE_INFO=4;
int QUIT_PHONE_INFO=5;
}
public class MenuChoiceException extends Exception {
public MenuChoiceException(int menu)
{
super(menu + "에 해당하는 선택은 존재하지 않습니다.\n" +
"메뉴 선택을 처음부터 다시 진행합니다.");
}
}
import java.io.Serializable;
public class PhoneInfo implements Serializable{
private String name;
private String phoneNumber;
public PhoneInfo(String name, String phoneNumber) {
this.name = name;
this.phoneNumber = phoneNumber;
}
public String getName() {
return name;
}
public String getPhoneNumber() {
return phoneNumber;
}
public void printCurrentState()
{
System.out.println("이름 : " + name);
System.out.println("전화번호 : " + phoneNumber);
}
@Override
public boolean equals(Object obj) {
return phoneNumber.equals(((PhoneInfo)obj).phoneNumber);
}
@Override
public int hashCode() {
return phoneNumber.hashCode();
}
}
public class PhoneUnivInfo extends PhoneInfo {
private String major;
private int year;
public PhoneUnivInfo(String name, String phoneNumber, String major, int year) {
super(name, phoneNumber);
this.major = major;
this.year = year;
}
@Override
public void printCurrentState() {
super.printCurrentState();
System.out.println("전공 : " + major);
System.out.println("학년 : " + year);
}
}
public class PhoneCompanyInfo extends PhoneInfo {
private String company;
public PhoneCompanyInfo(String name, String phoneNumber, String company) {
super(name, phoneNumber);
this.company = company;
}
@Override
public void printCurrentState() {
super.printCurrentState();
System.out.println("회사 : " + company);
}
}
import java.util.Scanner;
public class PhoneBookUI {
private PhoneBook pb;
public static Scanner sc = new Scanner(System.in);
public PhoneBookUI()
{
this.pb = PhoneBook.getPhoneBook();
}
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("선택 : ");
}
public void inputMenu()
{
System.out.println("데이터 입력을 시작합니다.");
System.out.println("1. 일반, 2. 대학, 3. 회사");
System.out.print("선택 >>");
}
public void inputPhoneInfo(int menu)
{
String name, phoneNumber, major, company;
int year=0;
boolean result;
PhoneInfo phoneInfo = null;
System.out.println("데이터 입력을 시작합니다.");
System.out.println("이름 : ");
name = sc.nextLine();
System.out.println("전화번호 : ");
phoneNumber = sc.nextLine();
if(menu == 1) // 추가
phoneInfo = new PhoneInfo(name, phoneNumber);
else if(menu == 2)
{
System.out.println("전공 : ");
major = sc.nextLine();
System.out.println("학년 : ");
year = sc.nextInt();
phoneInfo = new PhoneUnivInfo(name, phoneNumber, major, year);
}
else if(menu==3)
{
System.out.println("회사 : ");
company = sc.nextLine();
phoneInfo = new PhoneCompanyInfo(name, phoneNumber, company);
}
result = pb.insertPhoneInfo(phoneInfo);
if(result == false)
System.out.println("이미 등록된 데이터 입니다.");
else System.out.println("데이터 입력이 완료되었습니다.");
}
public void searchPhoneInfoByName()
{
String name;
System.out.println("검색하시고자 하는 이름을 입력해 주세요.");
name = sc.nextLine();
System.out.println("사용자 검색을 시작합니다.");
if( !pb.searchPhoneInfoByName(name)) System.out.println("찾으시는 사용자가 없습니다.");
}
public void deletePhoneInfoByPhoneNumber()
{
String phoneNumber;
System.out.println("삭제하시고자 하는 전화번호를 입력해 주세요.");
phoneNumber = sc.nextLine();
boolean result = pb.deletePhoneInfoByPhoneNumber(phoneNumber);
if(result) System.out.println("삭제가 완료되었습니다.");
else System.out.println("삭제하시고자 하는 전화번호 정보가 없습니다.");
}
public void printAllPhoneInfo()
{
System.out.println("모든 사용자 정보를 출력합니다.");
pb.printAllPhoneInfo();
}
public void quitProgram()
{
System.out.println("프로그램을 종료합니다.");
pb.quitProgram();
sc.close();
}
}
import java.util.Scanner;
public class PhoneMain{
public static void main(String[] args) {
int menu=0;
PhoneBookUI pbUI = new PhoneBookUI();
Scanner sc = PhoneBookUI.sc;
while(true)
{
pbUI.printMenu();
try
{
menu = sc.nextInt();
sc.nextLine();
if(menu<Menu.INSERT_PHONE_INFO || menu > Menu.QUIT_PHONE_INFO)
{
throw new MenuChoiceException(menu);
}
switch(menu)
{
case Menu.INSERT_PHONE_INFO:
pbUI.inputMenu();
menu = sc.nextInt();
sc.nextLine();
if(menu<1 || menu > 3)
{
throw new MenuChoiceException(menu);
}
pbUI.inputPhoneInfo(menu);
break;
case Menu.SEARCH_PHONE_INFO:
pbUI.searchPhoneInfoByName();
break;
case Menu.DELETE_PHONE_INFO:
pbUI.deletePhoneInfoByPhoneNumber();
break;
case Menu.SHOW_ALL_PHONE_INFO:
pbUI.printAllPhoneInfo();
break;
case Menu.QUIT_PHONE_INFO:
pbUI.quitProgram();
return;
}
}
catch(MenuChoiceException e)
{
System.out.println(e.getMessage());
}
}
}
}
import java.io.EOFException;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.HashSet;
import java.util.Iterator;
public class PhoneBook {
private static PhoneBook pb;
private HashSet<PhoneInfo> set;
private Iterator<PhoneInfo> itr;
private ObjectInputStream objInStream;
private ObjectOutputStream objOutStream;
private PhoneBook()
{
loadData();
}
public void loadData()
{
set = new HashSet<PhoneInfo>();
try {
objInStream = new ObjectInputStream(new FileInputStream("phoneInfo.data"));
} catch (FileNotFoundException e) {
System.out.println("등록된 데이터가 없습니다.");
} catch (IOException e) {
e.printStackTrace();
}
try {
if(objInStream != null)
{
PhoneInfo phoneInfo = (PhoneInfo)objInStream.readObject();
while(phoneInfo != null)
{
insertPhoneInfo(phoneInfo);
try {
phoneInfo = (PhoneInfo)objInStream.readObject();
}
catch(EOFException e)
{
break;
}
}
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
try {
if(objInStream != null)
objInStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
public static PhoneBook getPhoneBook()
{
if(pb==null)
pb = new PhoneBook();
return pb;
}
public boolean insertPhoneInfo(PhoneInfo phoneInfo)
{
return set.add(phoneInfo);
}
public boolean searchPhoneInfoByName(String name)
{
PhoneInfo pInfo = null;
itr = set.iterator();
boolean result = false;
while(itr.hasNext())
{
pInfo = itr.next();
if(pInfo.getName().equals(name))
{
pInfo.printCurrentState();
result = true;
}
}
return result;
}
public boolean deletePhoneInfoByPhoneNumber(String phoneNumber)
{
PhoneInfo pInfo = null;
itr = set.iterator();
while(itr.hasNext())
{
pInfo = itr.next();
if(pInfo.getPhoneNumber().equals(phoneNumber))
{
itr.remove();
return true;
}
}
return false;
}
public void printAllPhoneInfo()
{
itr = set.iterator();
while(itr.hasNext())
{
itr.next().printCurrentState();
}
}
public void quitProgram() {
if(set.size() == 0) return;
try {
objOutStream = new ObjectOutputStream(new FileOutputStream("phoneInfo.data"));
} catch (FileNotFoundException e1) {
e1.printStackTrace();
} catch (IOException e1) {
e1.printStackTrace();
}
try {
itr = set.iterator();
while(itr.hasNext())
objOutStream.writeObject(itr.next());
} catch (IOException e1) {
e1.printStackTrace();
}
try {
objOutStream.close();
} catch (IOException e1) {
System.out.println("파일 닫기 오류");
e1.printStackTrace();
}
}
}
- 해당 문제 핵심 내용
objInStream = new ObjectInputStream(new FileInputStream("PhoneInfo.data"));
set = (HashSet<PhoneInfo>)objInStream.readObject();
objInStream = new ObjectOutputStream(new FileOutputStream("PhoneInfo.data"));
objOutStream.writeObject(set);
// Tip : 데이터의 규모가 작고 간단한 경우 파일 입출력 정도로 가능하지만,
데이터의 규모가 커지게 되면 데이터베이스를 사용하게 된다.
ex) 게임 순위 저장 등
'SW > Java' 카테고리의 다른 글
[필기정리]Day28 - 쓰레드 문제(중심내용) (0) | 2020.07.17 |
---|---|
[필기정리]Day27 - 쓰레드 이론 및 문제 (0) | 2020.07.16 |
[필기정리] Day25 - IO 모델 셀프 핵심정리 (0) | 2020.07.14 |
[필기정리]Day25 - I/O모델 문제 (0) | 2020.07.14 |
[필기정리]Day24 - I/O 모델 (0) | 2020.07.13 |