최댓값&최소값 함수에 다형성 적용 - 김희정
부등호 조건만 다른 최댓값과 최소값 함수를 동시에 어떻게 구현할까?
문제인식
•
현재 배열의 최댓값을 구하는 getMax함수 구현
•
배열의 최소값을 구하는 함수도 필요
•
함수를 더 추가하지말고 최댓값과 동시에 구현할 수 없을까? >> 다형성 이용
public int getMax(int[] arr){
//loop 구성
int maxValue = arr[0];
for(int i = 0; i < arr.length; i++){
if(arr[i] > maxValue){
maxValue = arr[i];
}
}
return maxValue;
}
Java
복사
과정
1.
if문의 조건문을 boolean변수로 따로 뺀다.
•
최솟값과 최댓값의 차이 : 조건문 부등호 방향(><)
code
2.
Compare interface 구현
•
doSomething(int valueA, int valueB) : 정수 두개를 받아 조건에 맞는지 아닌지 리턴
•
해당 인터페이스 구현체를 통해 조건 설정
code
3.
callback 이용 : doSomething 함수로 조건문 boolean을 반환 받음
code
4.
max(), min() 메소드에서 각 로직에 맞게 doSomething을 구현
code
전체코드
템플릿/콜백 패턴
한가지만 바뀌고 중복일 때 주로 사용
•
템플릿 : 어떤 목적을 위해 미리 만들어둔 모양이 있는 틀
•
콜백 : 호출(call)한 메소드로 다시 가는 것(back)
콜백과정
•
max() → getMaxOrMin → max()
1.
main에 `maxAndMin.max(arr) 실행, max()호출
code
2.
max() 실행 , getMaxOrMin() 호출
code
3.
getMaxOrMin() 실행, 실행 중 compare.doSomething 을 위해 다시 max()로
code
4.
max()에서 Compare를 구현한 doSomething 메소드 로직 실행>> return valueA > valueB
code
5.
다시 getMaxOrMin() 계속 진행
cod
intell J 단축키
•
Alt + 1 : 편집기 → projcet explorer 이동
•
Alt + Insert : package, class 등 새로운 파일 만들기
•
esc : projcet explorer → 편집기 이동
•
Alt + J : 같은 문자를 동시에 드래그.
◦
home : 각 드래그 행의 제일 처음으로
◦
end : 각 드래그 행의 제일 마지막으로
•
Ctrl + Alt + L : 코드 정렬
•
다형성 적용 이전, 읽어온 string을 그대로 저장한 LineReader
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
public class LineReader {
List<String> readLine(String filename) throws IOException {
List<String> result = new ArrayList<>();
BufferedReader br = new BufferedReader(new FileReader(filename));
String str;
while((str= br.readLine())!= null){ // filename을 한 줄씩 읽어옵니다
result.add(str);
}
return result;
}
public static void main(String[] args) throws IOException {
LineReader lr = new LineReader();
String targetFile = "C:\\Users\\wjdtk\\Downloads\\서울시 병의원 위치 정보.csv";
List<String> line = lr.readLine(targetFile); //한 줄씩 읽어서 line에 저장
System.out.println(line.size());
}
}
Java
복사
코드 리팩토링한 이유
•
파일을 읽어오는 클래스인 LineReader는 다양한 곳에서 사용될 수 있다.
•
LineReader의 readLines메소드는 어떤 파일을 파싱하느냐에 따라 반환하는 리스트 타입이 달라질 수 있다.
◦
다양한 종류의 파일을 파싱할때마다 readLines를 반복적으로 작성하는 것은 비효율적이다.
◦
interface를 통해서 파일의 종류에 따라 다양한 List 타입을 반환할 수 있도록 코드를 리팩토링한다.
OPP 구현 순서
다형성의 이해
Parser 인터페이스
public interface Parser<T> {
// parsing할 파일의 자료형에 따라 Object를 다양하게 받기 위해 제네릭 <T>
T parse(String str);
}
Java
복사
interface 구현체 HospitalParser 생성
import Parser.Parser;
import domain.Hospital;
public class HospitalParser implements Parser<Hospital> { // Interface Parser의 구현체
private String getSubdivision(String name) {
String[] subDibisions = {"소아과", "피부과", "성형외과", "정형외과", "산부인과", "관절", "안과", "가정의학과", "비뇨기과", "치과", "내과", "외과", "한의원"};
for(String subDivision : subDibisions){
if(name.contains(subDivision)) {
return subDivision;
}
}
return "";
}
public Hospital parse(String str) {
str= str.replaceAll("\"", "");
String[] splitted = str.split(",");
String name = splitted[10];
String subDivision = getSubdivision(name);
return new Hospital(splitted[0],splitted[1],splitted[2],splitted[6],name, subDivision);
}
}
Java
복사
Hospital 클래스
package domain;
public class Hospital {
private String id;
private String address;
private String category;
private String district;
private String name;
private Integer emergency_room; // emergencyroom은 숫자라서 Integer입니다
private String subDivision;
public Hospital(String id, String address, String category, String emergency_room,
String name, String subDivision) {
this.id = id;
this.address = address;
this.name = name;
this.emergency_room = Integer.parseInt(emergency_room);
this.subDivision = subDivision;
setDistrict(address);
}
public void setDistrict(String str) {
String[] splitted = str.split(" ");
this.district = splitted[0]+" "+splitted[1]; // 서울시 어쩌구~어쩌구 ~ -> "서울시 00구"로 파싱
}
public String getId() {
return id;
}
public String getAddress() {
return address;
}
public String getCategory() {
return category;
}
public String getDistrict() {
return district;
}
public String getName() {
return name;
}
public Integer getEmergency_room() {
return emergency_room;
}
public String getSubDivision() {
return subDivision;
}
}
Java
복사
LineReader 클래스 수정
•
parser을 LineReader생성자에서 초기화
import Parser.Parser; // import Parser
import domain.Hospital;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
public class LineReader<T> {
Parser<T> parser;
private boolean isRemoveColumName = true;
public LineReader(Parser<T> parser, boolean isRemoveColumName) {
this.parser = parser;
this.isRemoveColumName = isRemoveColumName;
}
List<T> readLine(String filename) throws IOException {
List<T> result = new ArrayList<>();
BufferedReader br = new BufferedReader(new FileReader(filename));
String str;
if(isRemoveColumName){
br.readLine();
}
while((str= br.readLine())!= null){
// parse()가 호출되어 실행되면, return할 때 hospital 객체를 생성하고 종료합니다.
// 19xxxx 개의 hospital을 저장하기 위해 main에서 List를 작성할 것이다.
result.add(parser.parse(str));
}
return result;
}
}
Java
복사
Main 클래스
import domain.Hospital;
import java.io.IOException;
import java.util.List;
public class Main {
public static void main(String[] args) throws IOException {
String targetFile = "C:\\Users\\wjdtk\\Downloads\\서울시 병의원 위치 정보.csv";
LineReader<Hospital> hospitalLineReader = new LineReader<Hospital>(new HospitalParser(), true);
List<Hospital> hospitals = hospitalLineReader.readLine(targetFile);
for(Hospital hospital : hospitals){
System.out.printf("%s,%s,%s,%s,%d,%s,%s\n", hospital.getId(),hospital.getAddress(),hospital.getDistrict(),hospital.getCategory(),
hospital.getEmergency_room(),hospital.getName(), hospital.getSubDivision());
}
}
}
Java
복사