2022. 8. 23. 17:45ㆍJAVA
2022.08.23/24.화/수
0.개발환경 설정 : adoptopen jdk 11
※Maven : Build Tool
→java 파일이 여러 개이고, 특정 파일에서는 외부 라이브러리에 의존하는
코드들이 있는 경우 컴파일러 혼자서 컴파일 불가능
∴Build Tool 사용
-pom.xml -> package.json과 비슷한 역할(프로젝트의 메타정보 표기), 의존성
1.객체지향 설계(S.O.L.I.D.)
1)SRP - Single Responsibility principle(단일 책임 원칙)
→하나의 클래스나 메서드는 단 하나의 책임(역할)만 가져야 함
2)OCP - Open/Closed Principle(개방/폐쇠 원칙)
3)DIP - Dependency Inversion Principle(의존성 역전 원칙)
2.간단한 은행 계좌의 입출금 내역 조회 프로그램 만들기(SRP 적용)
-프로그램에서 등장하는 몇 가지 도메인 용어
BankTransaction : 하나의 입출금 내역
BankStatementParser : 입출금 내역 데이터 파일 처리기, 데이터 파일을 시스템에서
이해할 수 있는 형태로 파싱(Parsing)해주는 역할
BankStatementAnalyzer : 입출금 내역 분석기, 파싱된 데이터를 분석,
연산 처리, 결과 출력 등의 복수 역할
BankStatementProcessor: 입출금 내역 연산 처리기, 기능 별 동작을 담당하는 역할
-요구사항 check list
- [ ] 입출금 내역을 담고 있는 bank-data-simple.tsv(txt) 파일을 읽고, 총 입출금 내역을 처리한 후, 콘솔로 결과를 조회할 수 있음
- [ ] 특정 월에 발생한 입출금 내역을 조회할 수 있음
1)프로토타입 만들기
package dev.bank;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.LocalDate;
import java.time.Month;
import java.time.format.DateTimeFormatter;
import java.util.List;
import dev.bank.data.BankStatementTSVParser;
/*
관심사
1.입출금 내역 데이터 읽어들임(파일 입출력 부분)
2.주어진 형식(타입)으로 읽어들인 데이터를 파싱(Parsing)
3.입출력 내역 결과 처리 후 출력
*/
public class BankStatementAnalyzerSimple {
//입출금 내역 파일인 bank-data-simple.txt 파일의 경로를 지정
private static final String RESOURCES = "src/main/resources/";
public static void main(String[] args) throws IOException {
//1번째 기능 요구사항, 모든 거래내역의 합 계산하고 콘솔로 결과 조회
final Path path = Paths.get(RESOURCES + "bank-data-simple.txt");
// System.out.println(path);
final List<String> lines = Files.readAllLines(path); //List<String>
double total = 0d;
//for-each 활용하여 반복문으로 총 입출금 내역 조회
for (String line : lines) {
final String[] columns = line.split("\t");
final double amount = Double.parseDouble(columns[1]);
//Integer.parseInt("100")
total += amount;
}
System.out.println("총 사용 금액은 " + total + "입니다.");
//2번째 기능 요구사항, 특정 월에는 몇 건의 입출금 내역이 발생하였는지?
//ex) 1월 입출금 내역 조회
System.out.println("1월 총 사용 금액은 " + findTransactionsInJanuary() + "입니다.");
}
//2번째 기능 요구사항, 1월 일출금 내역 조회 메서드
public static double findTransactionsInJanuary() throws IOException {
final Path path = Paths.get(RESOURCES + "bank-data-simple.txt");
// System.out.println(path);
final List<String> lines = Files.readAllLines(path); //List<String>
//날짜 타입은 LocalDate 타입 사용
final DateTimeFormatter DATE_PATTERN = DateTimeFormatter.ofPattern("dd-MM-yyyy");
double total = 0d;
//반복문 활용, 특정 월에 해당하는 일출금 내역 연산처리
for (String line : lines) {
final String[] columns = line.split("\t");
final LocalDate date = LocalDate.parse(columns[0], DATE_PATTERN);
if(date.getMonth() == Month.JANUARY) {
total += Double.parseDouble(columns[1]);
}
}
return total;
}
}
※응집도(cohesion)
코드의 품질과 관련된 특성, 클래스나 메서드의 책임, 관심사가 서로 강하게 연결, 연관되어 있는 정도
결합도(Coupling)
코드의 품질에 영향을 미치는 또 다른 요인으로 응집도와 같이 짝으로 활용됨
응집도가 클래스, 패키지, 메서드 등의 동작이 서로 얼마나 관련되어 있는지에 대한 척도라면,
결합도는 한 기능이나 클래스가 다른 클래스에 얼마나 의존(dependent)하고 있는지를 나타냄
따라서 결합도란 특정 클래스를 구현하는데에 얼마나 많은 클래스들을 의존하고 있는지로 가늠할 수 있음
많이 의존할 수록 변경에 용이하지 않고, 유연성이 떨어짐
-응집도 향상시키고, 결합도 느슨하게 만들기
1)main
package dev.bank;
import java.io.IOException;
import dev.bank.data.BankStatementCSVParser;
import dev.bank.data.BankStatementParser;
public class MainApplication {
public static void main(String[] args) {
final BankStatementAnalyzer analyzer = new BankStatementAnalyzer();
final BankStatementParser parser = new BankStatementCSVParser();
try {
analyzer.analyze("bank-data-simple.csv", parser);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
2)BankStatementAnalyzer 클래스
package dev.bank;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.Month;
import java.util.List;
import dev.bank.data.BankStatementParser;
import dev.bank.domain.BankTransaction;
import dev.bank.service.BankStatementProcessor;
public class BankStatementAnalyzer {
private static final String RESOURCES = "src/main/resources/";
public void analyze(String fileName, BankStatementParser parser) throws IOException {
final Path path = Paths.get(RESOURCES + fileName);
final List<String> lines = Files.readAllLines(path); // List<String>
List<BankTransaction> bankTransactions = parser.parseLinesFrom(lines);
BankStatementProcessor processor = new BankStatementProcessor(bankTransactions);
collectSummary(processor);
}
private static void collectSummary(BankStatementProcessor processor) {
System.out.println("총 입출금 내역은 : " + processor.calculateTotalAmount());
System.out.println("1월 총 입출금 내역 리스트는 : " + processor.calculateTotalInMonth(Month.JANUARY));
System.out.println("Salary 카테고리의 내역은 : " + processor.calculateTotalByCategory("Salary"));
}
}
3)BankTransaction(도메인 객체, 가공된 객체)
package dev.bank.domain;
import java.time.LocalDate;
//하나의 일출금 내역
public class BankTransaction {
private LocalDate date; //입출금 날짜
private double amount; //입출금 금액
private String description; //거래처
public BankTransaction(LocalDate date, double amount, String description) {
this.date = date;
this.amount = amount;
this.description = description;
}
public LocalDate getDate() {
return date;
}
public double getAmount() {
return amount;
}
public String getDescription() {
return description;
}
@Override
public String toString() {
return "BankTransaction [date=" + date + ", amount=" + amount + ", description=" + description + "]";
}
}
4)BankStatementParser 인터페이스/클래스(파일 -> BankTransaction로 Parse)
package dev.bank.data;
import java.util.List;
import dev.bank.domain.BankTransaction;
public interface BankStatementParser {
BankTransaction parseFrom(String line);
List<BankTransaction> parseLinesFrom(List<String> lines);
}
package dev.bank.data;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import dev.bank.domain.BankTransaction;
//다른 문제 구현에도 파싱 로직을 활용할 수 있도록
//TSV 파싱로직을 새로운 클래스로 분리
public class BankStatementTSVParser implements BankStatementParser {
final DateTimeFormatter DATE_PATTERN = DateTimeFormatter.ofPattern("dd-MM-yyyy");
public BankTransaction parseFrom(final String line) {
String[] columns = line.split("\t");
final LocalDate date = LocalDate.parse(columns[0], DATE_PATTERN);
final double amount = Double.parseDouble(columns[1]);
final String description = columns[2];
return new BankTransaction(date, amount, description);
}
//lines를 인수로 받아서 한줄 씩 파싱 후, 리스트에 추가
public List<BankTransaction> parseLinesFrom(List<String> lines) {
List<BankTransaction> list = new ArrayList<BankTransaction>();
for (String line : lines) {
list.add(parseFrom(line));
}
return list;
}
}
package dev.bank.data;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import dev.bank.domain.BankTransaction;
//CSV파일에 대한 파싱 요구사항에 따른 새로운 csv parser 구현
public class BankStatementCSVParser implements BankStatementParser {
final DateTimeFormatter DATE_PATTERN = DateTimeFormatter.ofPattern("dd-MM-yyyy");
public BankTransaction parseFrom(final String line) {
String[] columns = line.split(",");
final LocalDate date = LocalDate.parse(columns[0], DATE_PATTERN);
final double amount = Double.parseDouble(columns[1]);
final String description = columns[2];
return new BankTransaction(date, amount, description);
}
//lines를 인수로 받아서 한줄 씩 파싱 후, 리스트에 추가
public List<BankTransaction> parseLinesFrom(List<String> lines) {
List<BankTransaction> list = new ArrayList<BankTransaction>();
for (String line : lines) {
list.add(parseFrom(line));
}
return list;
}
}
5)BankStatementProcessor클래스 - Service(비즈니스 로직)
package dev.bank.service;
import java.time.Month;
import java.util.ArrayList;
import java.util.List;
import dev.bank.domain.BankTransaction;
//입출금 관련 도메인(비즈니스) 로직을 처리하는 클래스
public class BankStatementProcessor {
//Processor 클래스에서 List<BankTransaction>를 필드로 가지고 있도록
private final List<BankTransaction> bankTransactions;
//생성자를 통해서 bankTransactions 초기화
public BankStatementProcessor(List<BankTransaction> bankTransactions) {
this.bankTransactions = bankTransactions;
}
// 전체 입출금 내역을 조회하는 메서드
public double calculateTotalAmount() {
double total = 0d;
for (BankTransaction bankTransaction : bankTransactions) {
total += bankTransaction.getAmount();
}
return total;
}
// 특정 월의 거래 내역 리스트를 조회하는 메서드
public List<BankTransaction> calculateTotalInMonth(Month month) {
final List<BankTransaction> bankTransactionsInMonth = new ArrayList<>();
for (BankTransaction bankTransaction : bankTransactions) {
if(bankTransaction.getDate().getMonth() == month) {
bankTransactionsInMonth.add(bankTransaction);
}
}
return bankTransactionsInMonth;
}
//거래처(category) 별 총 일출금 금액을 조회할 수 있는 조회할 수 있는 메서드(새롭게 추가)
public double calculateTotalByCategory(String category) {
double total = 0d;
for (BankTransaction bankTransaction : bankTransactions) {
if(category.equals(bankTransaction.getDescription())) {
total += bankTransaction.getAmount();
}
}
return total;
}
}
'JAVA' 카테고리의 다른 글
24.Java Spring/IoC/DI/객체지향설계원칙 (0) | 2022.08.29 |
---|---|
23.Java JPA (0) | 2022.08.25 |
21.파일 업로드 (0) | 2022.08.11 |
20.Web화면 재사용/EL/JSTL (0) | 2022.08.10 |
19.mybatis Web/필터/세션관리 (0) | 2022.08.09 |