본문 바로가기

Java/java 기초

HashMap , TreeMap 상속 을 활용하여 야구선수 관리 시스템 만들기 - 파일 저장 연동

부모클래스 (Batter 과 Pitcher 의 부모 클래스)

기본적인 DTO

package human;

public class Human {
	private int number;
	private String name;
	private int age;
	private double height;

	public Human() {
		// TODO Auto-generated constructor stub
	}

	public int getNumber() {
		return number;
	}

	public void setNumber(int number) {
		this.number = number;
	}

	public String getName() {
		return name;
	}

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

	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		this.age = age;
	}

	public double getHeight() {
		return height;
	}

	public void setHeight(double height) {
		this.height = height;
	}

	@Override
	public String toString() {
		return "Human [number=" + number + ", name=" + name + ", age=" + age + ", height=" + height + "]";
	}

	public Human(int number, String name, int age, double height) {
		super();
		this.number = number;
		this.name = name;
		this.age = age;
		this.height = height;
	}

}

 

자식 클래스 Batter와 Pitcher

toString() 을 단축키를 활용해서 추가하는방식으로 진행헀었는데

super().toString()을 활용하면 좀더 코드를 짧게 만들수 있을듯 싶다.

package human;

public class Batter extends Human{
	int bat;
	int hit;
	double batAvg;
	
	public Batter() {
		// TODO Auto-generated constructor stub
	}
	
	public Batter(int number, String name, int age, double height, int bat, int hit, double batAvg) {
		super(number, name, age, height);
		this.bat = bat;
		this.hit = hit;
		this.batAvg = batAvg;
	}
	
	public int getBat() {
		return bat;
	}
	
	public void setBat(int bat) {
		this.bat = bat;
	}
	
	public int getHit() {
		return hit;
	}
	
	public void setHit(int hit) {
		this.hit = hit;
	}
	
	public double getBatAvg() {
		return batAvg;
	}
	
	public void setBatAvg(double batAvg) {
		this.batAvg = batAvg;
	}

	@Override
	public String toString() {
		return "타자 [번호: " + getNumber()
		+ ", 이름: " + getName() + ", 나이: " + getAge() + ", 키: " + getHeight()+
		", 친 횟수: "+ bat + ", 유효타: " + hit + ", 타율: " + batAvg + "]";
	}
	
	
	
}

 

package human;

public class Pitcher extends Human{
	int win;
	int lose;
	double def;
	
	public Pitcher() {
		// TODO Auto-generated constructor stub
	}
	public Pitcher(int number, String name, int age, double height, int win, int lose, double def) {
		super(number, name, age, height);
		this.win = win;
		this.lose = lose;
		this.def = def;
	}
	
	
	public int getWin() {
		return win;
	}
	public void setWin(int win) {
		this.win = win;
	}
	public int getLose() {
		return lose;
	}
	public void setLose(int lose) {
		this.lose = lose;
	}
	public double getDef() {
		return def;
	}
	public void setDef(double def) {
		this.def = def;
	}
	@Override
	public String toString() {
		return "투수 [번호: " + getNumber()
		+ ", 이름: " + getName() + ", 나이: " + getAge() + ", 키: " + getHeight()+
		", 이긴 횟수: "+ win + ", 진 횟수: " + lose + ", 방어율: " + def + "]";
	}

	
	
}

 

 

package file;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.HashMap;

import human.Batter;
import human.Human;
import human.Pitcher;

public class DataFile {
	private String fileName;
	private File file;

	public DataFile(String fileName) {
		this.fileName = fileName;
		file = new File("c:\\tmp\\" + fileName + ".txt");

	}

	public void createFile() {
		try {
			if (file.createNewFile()) {
				System.out.println("파일 생성 성공!");
			} else {
				System.out.println("파일 생성 실패");
			}
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	public void writeFile(String datas[]) {
		try {
			PrintWriter pw = new PrintWriter(new BufferedWriter(new FileWriter(file)));

			for (int i = 0; i < datas.length; i++) {
				pw.println(datas[i]);
			}
			pw.close();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

	}

	public HashMap<Integer, Human> readFile() {
		HashMap<Integer, Human> map = new HashMap<Integer, Human>();
		try {
			if (checkBeforeReadFile(file)) {
				BufferedReader br = new BufferedReader(new FileReader(file));

				String str = "";
				Human human = null;

				while ((str = br.readLine()) != null) {

					String split[] = str.split("-");

					// 투수
					if (Integer.parseInt(split[0]) < 2000) {
						human = new Pitcher(Integer.parseInt(split[0]), split[1], Integer.parseInt(split[2]),
								Double.parseDouble(split[3]), Integer.parseInt(split[4]), Integer.parseInt(split[5]),
								Double.parseDouble(split[6]));
					}
					// 타자
					else {
						human = new Batter(Integer.parseInt(split[0]), split[1], Integer.parseInt(split[2]),
								Double.parseDouble(split[3]), Integer.parseInt(split[4]), Integer.parseInt(split[5]),
								Double.parseDouble(split[6]));
					}
					map.put(human.getNumber(), human);
				}

			} else {
				System.out.println("파일이 없거나 읽을 수 없습니다");
			}
		} catch (Exception e) {
			e.printStackTrace();
		}

		return map;
	}

	// 파일이 있으며 읽을 수 있는 파일인지 확인용 메소드
	public boolean checkBeforeReadFile(File f) {
		if (f.exists()) {
			if (f.isFile() && f.canRead()) {
				return true;
			}
		}
		return false;
	}

}

 

파일 시스템

 

File 쪽은 직접 외워서 사용하기보단 그때 그때 찾아가면서 활용하는게 낫겟다는 생각이 들었다.

writeFile쪽에서는 String 배열 값을 파라미터로 받아서 

해당 값을 기준으로 pw에 작성해주고 pw.close()로 마무리한다.

 

 

readFile쪽은 HashMap 을 아에 리턴해주는 방식으로 

파일이 존재할 경우 파일의 값을 읽어서 각각 "-" 를 활용해서 split으로 나눠준다

그후 각각 파싱해서 각각의 생성자에 넣어준후

HashMap에 값을 넣은 후 리턴해준다.

 

package dao;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Scanner;
import java.util.TreeMap;

import file.DataFile;
import human.Batter;
import human.Human;
import human.Pitcher;

public class HumanDao {
	HashMap<Integer, Human> member = new HashMap<Integer, Human>();
	Scanner scanner = new Scanner(System.in);
	DataFile df;

	public HumanDao() {
		df = new DataFile("baseball");
		df.createFile();
		
		member = df.readFile();
		
	
	}

	public void insert() {
		System.out.println("입력할 선수의 정보를 입력하세요");
		System.out.println("1. 투수 2. 타자");
		int choice = scanner.nextInt();
		int pitcherNumber = 0;
		int batterNumber = 1000;

		Human human = null;
		if (choice == 1) {
			pitcherNumber = pitcherNumber + 1;
			System.out.println(pitcherNumber);
			human = new Pitcher();
			human.setNumber(pitcherNumber);
			System.out.print("이름: ");
			human.setName(scanner.next());
			System.out.print("나이: ");
			human.setAge(scanner.nextInt());
			System.out.print("키: ");
			human.setHeight(scanner.nextDouble());
			System.out.print("이긴 횟수: ");
			((Pitcher) human).setWin(scanner.nextInt());
			System.out.print("진 횟수: ");
			((Pitcher) human).setLose(scanner.nextInt());
			System.out.print("방어율: ");
			((Pitcher) human).setDef(scanner.nextDouble());
			member.put(pitcherNumber, human);

		} else if (choice == 2) {
			batterNumber = batterNumber + 1;
			human = new Batter();
			human.setNumber(batterNumber);
			System.out.print("이름: ");
			human.setName(scanner.next());
			System.out.print("나이: ");
			human.setAge(scanner.nextInt());
			System.out.print("키: ");
			human.setHeight(scanner.nextDouble());
			System.out.print("친 횟수: ");
			((Batter) human).setBat(scanner.nextInt());
			System.out.print("유효타: ");
			((Batter) human).setHit(scanner.nextInt());
			System.out.print("타율: ");
			((Batter) human).setBatAvg(scanner.nextDouble());
			member.put(batterNumber, human);

		} else {
			System.out.println("다시 실행하세요 ");
			return;
		}

		printAll();
	}

	public void delete() {
		System.out.println("삭제 할 선수의 이름을 입력해주세요.");
		String name = scanner.next();
		int keyNumber = search(name);
		if (keyNumber == -1) {
			System.out.println("해당 선수를 찾을 수 없습니다");
		} else {
			member.remove(keyNumber);
			System.out.println("삭제가 완료되었습니다.");
		}
	}

	public int search(String name) {
		Iterator<Integer> iterator = member.keySet().iterator();
		int keyNumber = -1;
		while (iterator.hasNext()) {
			int key = iterator.next();
			if (member.get(key).getName().equals(name)) {
				keyNumber = key;
				break;
			}
		}

		return keyNumber;
	}

	public void select() {
		System.out.println("검색 할 선수의 이름을 입력해 주세요.");
		String name = scanner.next();
		int keyNumber = search(name);
		if (keyNumber == -1) {
			System.out.println("해당 선수를 찾을 수 없습니다");
		} else {
			System.out.println("검색한 선수의 정보 입니다.");
			System.out.println(member.get(keyNumber).toString());
		}
	}
	
	
	public void update() {
		System.out.println("정보를 변경할 선수의 이름을 입력해 주세요");
		String name = scanner.next();
		int keyNumber = search(name);
		if (keyNumber == -1) {
			System.out.println("해당 선수를 찾을 수 없습니다");
		} else {
			// 진 횟수가 없을때 (타자 일때)
			if (member.get(keyNumber) instanceof Pitcher) {
				System.out.println("투수의 정보를 변경합니다");

				System.out.println("이긴 횟수");
				((Pitcher) member.get(keyNumber)).setWin(scanner.nextInt());
				System.out.println("진 횟수");
				((Pitcher) member.get(keyNumber)).setLose(scanner.nextInt());
				System.out.println("방어율");
				((Pitcher) member.get(keyNumber)).setDef(scanner.nextDouble());
			} else if (member.get(keyNumber) instanceof Batter) {
				System.out.println("타자의 정보를 변경합니다");

				System.out.println("친 횟수");
				((Batter) member.get(keyNumber)).setBat(scanner.nextInt());
				System.out.println("유효타");
				((Batter) member.get(keyNumber)).setHit(scanner.nextInt());
				System.out.println("타율");
				((Batter) member.get(keyNumber)).setBatAvg(scanner.nextDouble());

			}
		}
	}

	public void printAll() {
		Iterator<Integer> iterator = member.keySet().iterator();
		while (iterator.hasNext()) {
			int key = iterator.next();
			Human value = member.get(key);
			System.out.println("key : " + key + "value : " + value.toString());
		}
	}

	public void sort() {
		System.out.println("1. 투수  2. 타자");
		int choice = scanner.nextInt();

		TreeMap<Double, Human> tree = new TreeMap<Double, Human>();

		Iterator<Integer> iterator = member.keySet().iterator();

		while (iterator.hasNext()) {
			int key = iterator.next();
			if (member.get(key) instanceof Pitcher) {
				double def = ((Pitcher) member.get(key)).getDef();
				
				for (int i = 0; i < member.size(); i++) {
					if(tree.containsKey(def)) {
						def = def + 0.0001;
					}
				}

				tree.put(def, member.get(key));
			} else if (member.get(key) instanceof Batter) {
				double batAvg = ((Batter) member.get(key)).getBatAvg();
				for (int i = 0; i < member.size(); i++) {
					if(tree.containsKey(batAvg)) {
						batAvg = batAvg + 0.0001;
					}
				}
				tree.put(batAvg, member.get(key));

			}
		}

		Iterator<Double> iter = tree.descendingKeySet().iterator();

		while (iter.hasNext()) {
			double key = iter.next();

			if (choice == 1) {
				if (tree.get(key).getNumber() < 1000) {
					System.out.println(tree.get(key).toString());
				}
			}

			else if (choice == 2) {
				if (tree.get(key).getNumber() > 1000) {
					System.out.println(tree.get(key).toString());
				}
			}
			System.out.println(key);

		}

	}
	
	public void saveData() {
		String[] datas = new String[member.size()];
		Iterator<Integer> iterator = member.keySet().iterator();

		Human human;
		int i = 0;
		while(iterator.hasNext()) {
			int key = iterator.next();
			human = member.get(key);
			datas[i] = human.getNumber() + "-" + human.getName() + "-" +human.getAge() + "-" + human.getHeight() + "-";
			if(human instanceof Pitcher) {
				datas[i] = datas[i] + ((Pitcher)human).getWin() + "-" +((Pitcher)human).getLose() + "-" + ((Pitcher)human).getDef();
				
			} else if (human instanceof Batter) {
				datas[i] = datas[i] + ((Batter)human).getBat() + "-" +((Batter)human).getHit() + "-" + ((Batter)human).getBatAvg();
			}
			i ++;
		}
		df.writeFile(datas);
	}	
	
	
}

생성자에는 파일을 생성및

member 의 값을 DataFile class의 readFile로 받아온다

 

1. 입력

입력부분에서는 투수와 타자의 식별 아이디를 0과 1000으로 나눠 구분했으며 

((Pitcher) human).setWin(scanner.netInt) 등 Human으로 값을 관리하기 때문에 

Pitcher나 Batter의 인스턴스인 경우 각각 값을 다르게 저장할 수 있도록하였다.

 

2. 삭제 

삭제를 위해 먼저 검색 기능을 구현했다.

HashMap은 Iterator을 활용하기 때문에 이터레이터를 활용해서  key값을 받은후 

해당 key값의 이름을 받아서 입력한 이름과 같으면 해당 키값을 반환하는 방식으로 진행하였다.

 

3. 검색

구현한 검색 기능을 활용하여 해당 선수의 정보를 member.get(keyNumber).toString 을 활용하여 출력 하도록 하였다.

 

4. 업데이트

 

업데이트 부분에서는 고민을하다 instanceof를 활용하기로 하였다.

Pitcher의 instance인 경우, Batter의 instance인 경우를 지정해서 해당 값들만 변경 될 수 있도록 하였다.

 

5. 정렬

 

TreeMap을 새로 생성 한 후 키값을 방어율, 타율인 (Double) 로 키값을 지정하였다.

하지만 중복의 키값이 발생 할 수 있기떄문에 키값이 같을 경우 

member(HashMap)의 사이즈 만큼 for문을 활용하여 각각의 키값에 0.0001을 더해주는 방식으로 진행헀다.

키값에는 값이 추가되지만 직접 불러오는 데이터는 키값과 영향이 없기에 일종의 편법? 개념으로 활용하였다.

그후 해당 tree에 값을 주입했다.

 

또한 투수와 타자 별로 정렬 하여  볼 수 있도록 하였는데

getNumber(바뀌지않는 인덱스값) 을 활용하여 1000보다 작은 경우 투수의 정보가 출력이 되고

1000보다 큰 경우 타자의 정보가 출력되게 하였다.

 

6. 파일에 저장

dataFIle에서 생성한 메소드 writeFile 에 값을 넣기위해 datas[]를 생성한다.

배열의 정보엔 각각 값을 get으로 일일히 배운 후 파싱을 위한 용도인 "-"를 넣어준다.

그 후 해당 값을 writeFile에 넣어서 저장시켜준다

 

 

 

 

파일 저장값