Skip to content

[4기 - 김영주] 1~2주차 과제: 계산기 구현 미션 제출합니다. (5차) #134

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 28 commits into from
Jun 26, 2023
Merged
Show file tree
Hide file tree
Changes from 21 commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
742e7fb
build: 프로젝트 초기 빌드 파일 생성
kylekim2123 Jun 8, 2023
b7358bf
feat: 사용자 입력을 받아 메뉴를 선택하는 기능 추가
kylekim2123 Jun 8, 2023
99c00fd
feat: 프로그램 종료 기능 추가
kylekim2123 Jun 8, 2023
a4a53fa
refactor: 메뉴 입출력을 MainController에서 InputView, OutputView로 이관
kylekim2123 Jun 11, 2023
aacebd7
refactor: 메뉴의 초기값을 null에서 Optional로 변경
kylekim2123 Jun 11, 2023
8c7203b
refactor: try-catch를 MainController에서 App으로 이동
kylekim2123 Jun 11, 2023
9de3ddf
refactor: Optional 관련한 안티패턴 개선
kylekim2123 Jun 12, 2023
ec9a193
feat: 계산식 입력 기능 추가
kylekim2123 Jun 12, 2023
7bc84f5
feat: 중위표현식 계산 기능 추가 (덧셈, 뺄셈, 곱셈, 나눗셈)
kylekim2123 Jun 12, 2023
5f863ae
refactor: 정규식 검사 및 문자열 split 관련 로직을 StringUtils로 이관
kylekim2123 Jun 12, 2023
d60918a
refactor: exception 패키지를 calculator 패키지 하위로 이동
kylekim2123 Jun 12, 2023
366e2d5
refactor: Menu 클래스의 isQuit(), isCalculate()를 인스턴스 메서드로 변경
kylekim2123 Jun 12, 2023
fcefe82
refactor: getOperatorWithSameSymbol()의 반환 방식을 기존 get()에서 orElseThrow(…
kylekim2123 Jun 13, 2023
f87f054
refactor: 피연산자 2개와 연산자 1개를 이용해 계산하는 로직을 메서드로 분리
kylekim2123 Jun 13, 2023
74abb5d
refactor: App에서 MainController, Calculator 인스턴스를 변수로 할당
kylekim2123 Jun 13, 2023
4ee0ce0
feat: 계산식을 별도 저장소에 저장하는 기능 추가
kylekim2123 Jun 13, 2023
f95965c
feat: 전체 계산 내역을 조회하는 기능 추가
kylekim2123 Jun 13, 2023
8282ea6
refactor: run() 메서드에 isRunning 플래그를 추가하여, if문 제거
kylekim2123 Jun 14, 2023
17f04b2
refactor: HistoryReader 클래스 제거 후 직접 HistoryStorage에서 내역 조회
kylekim2123 Jun 14, 2023
afbc5b8
refactor: Expression 클래스를 새로 정의하여, 단위 계산 로직을 이관
kylekim2123 Jun 14, 2023
a72b9eb
style: Calculator의 execute 메서드명을 calculate로 변경
kylekim2123 Jun 14, 2023
ece675e
refactor: Calculator에서 View 호출하는 부분을 분리
kylekim2123 Jun 15, 2023
767e99f
refactor: 후위연산 기능 추가를 위해, 표기식 자체를 상위 인터페이스로 추상화
kylekim2123 Jun 15, 2023
989f7ea
feat: 중위표현식에서 후위표현식으로 변경하는 기능 추가
kylekim2123 Jun 15, 2023
e2efa42
feat: 후위표현식 계산 시 작은 단위의 식을 만드는 기능 추가
kylekim2123 Jun 15, 2023
b2e6326
test: 중위표현식 계산기 통합 테스트 작성
kylekim2123 Jun 15, 2023
a435e9b
test: 후위표현식 계산기 통합 테스트 작성
kylekim2123 Jun 15, 2023
f65b289
docs: README에 프로젝트 명세 작성
kylekim2123 Jun 15, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#
# https://help.github.com/articles/dealing-with-line-endings/
#
# Linux start script should use lf
/gradlew text eol=lf

# These are Windows script files and should use crlf
*.bat text eol=crlf

202 changes: 202 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,202 @@
### Intellij ###
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
.idea

# User-specific stuff
.idea/**/workspace.xml
.idea/**/tasks.xml
.idea/**/usage.statistics.xml
.idea/**/dictionaries
.idea/**/shelf

# AWS User-specific
.idea/**/aws.xml

# Generated files
.idea/**/contentModel.xml

# Sensitive or high-churn files
.idea/**/dataSources/
.idea/**/dataSources.ids
.idea/**/dataSources.local.xml
.idea/**/sqlDataSources.xml
.idea/**/dynamic.xml
.idea/**/uiDesigner.xml
.idea/**/dbnavigator.xml

# Gradle
.idea/**/gradle.xml
.idea/**/libraries

# Gradle and Maven with auto-import
# When using Gradle or Maven with auto-import, you should exclude module files,
# since they will be recreated, and may cause churn. Uncomment if using
# auto-import.
# .idea/artifacts
# .idea/compiler.xml
# .idea/jarRepositories.xml
# .idea/modules.xml
# .idea/*.iml
# .idea/modules
# *.iml
# *.ipr

# CMake
cmake-build-*/

# Mongo Explorer plugin
.idea/**/mongoSettings.xml

# File-based project format
*.iws

# IntelliJ
out/

# mpeltonen/sbt-idea plugin
.idea_modules/

# JIRA plugin
atlassian-ide-plugin.xml

# Cursive Clojure plugin
.idea/replstate.xml

# SonarLint plugin
.idea/sonarlint/

# Crashlytics plugin (for Android Studio and IntelliJ)
com_crashlytics_export_strings.xml
crashlytics.properties
crashlytics-build.properties
fabric.properties

# Editor-based Rest Client
.idea/httpRequests

# Android studio 3.1+ serialized cache file
.idea/caches/build_file_checksums.ser

### Intellij Patch ###
# Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721

# *.iml
# modules.xml
# .idea/misc.xml
# *.ipr

# Sonarlint plugin
# https://plugins.jetbrains.com/plugin/7973-sonarlint
.idea/**/sonarlint/

# SonarQube Plugin
# https://plugins.jetbrains.com/plugin/7238-sonarqube-community-plugin
.idea/**/sonarIssues.xml

# Markdown Navigator plugin
# https://plugins.jetbrains.com/plugin/7896-markdown-navigator-enhanced
.idea/**/markdown-navigator.xml
.idea/**/markdown-navigator-enh.xml
.idea/**/markdown-navigator/

# Cache file creation bug
# See https://youtrack.jetbrains.com/issue/JBR-2257
.idea/$CACHE_FILE$

# CodeStream plugin
# https://plugins.jetbrains.com/plugin/12206-codestream
.idea/codestream.xml

# Azure Toolkit for IntelliJ plugin
# https://plugins.jetbrains.com/plugin/8053-azure-toolkit-for-intellij
.idea/**/azureSettings.xml

### Java ###
# Compiled class file
*.class

# Log file
*.log

# BlueJ files
*.ctxt

# Mobile Tools for Java (J2ME)
.mtj.tmp/

# Package Files #
*.jar
*.war
*.nar
*.ear
*.zip
*.tar.gz
*.rar

# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
hs_err_pid*
replay_pid*

### macOS ###
# General
.DS_Store
.AppleDouble
.LSOverride

# Icon must end with two \r
Icon


# Thumbnails
._*

# Files that might appear in the root of a volume
.DocumentRevisions-V100
.fseventsd
.Spotlight-V100
.TemporaryItems
.Trashes
.VolumeIcon.icns
.com.apple.timemachine.donotpresent

# Directories potentially created on remote AFP share
.AppleDB
.AppleDesktop
Network Trash Folder
Temporary Items
.apdisk

### macOS Patch ###
# iCloud generated files
*.icloud

### Gradle ###
.gradle
**/build/
!src/**/build/

# Ignore Gradle GUI config
gradle-app.setting

# Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored)
!gradle-wrapper.jar

# Avoid ignore Gradle wrappper properties
!gradle-wrapper.properties

# Cache of project
.gradletasknamecache

# Eclipse Gradle plugin generated files
# Eclipse Core
.project
# JDT-specific (Eclipse Java Development Tools)
.classpath

### Gradle Patch ###
# Java heap dump
*.hprof

# Ignore Gradle build output directory
build
42 changes: 42 additions & 0 deletions app/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/*
* This file was generated by the Gradle 'init' task.
*
* This generated file contains a sample Java application project to get you started.
* For more details take a look at the 'Building Java & JVM projects' chapter in the Gradle
* User Manual available at https://docs.gradle.org/8.1.1/userguide/building_java_projects.html
*/

plugins {
// Apply the application plugin to add support for building a CLI application in Java.
id 'application'
}

repositories {
// Use Maven Central for resolving dependencies.
mavenCentral()
}

dependencies {
// Use JUnit Jupiter for testing.
testImplementation 'org.junit.jupiter:junit-jupiter:5.9.1'

// This dependency is used by the application.
implementation 'com.google.guava:guava:31.1-jre'
}

// Apply a specific Java toolchain to ease working on different environments.
java {
toolchain {
languageVersion = JavaLanguageVersion.of(17)
}
}

application {
// Define the main class for the application.
mainClass = 'calculator.App'
}

tasks.named('test') {
// Use JUnit Platform for unit tests.
useJUnitPlatform()
}
25 changes: 25 additions & 0 deletions app/src/main/java/calculator/App.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package calculator;

import static calculator.view.OutputView.printWithLineBreak;
import static calculator.view.OutputView.showQuitMessage;

import calculator.controller.MainController;
import calculator.service.Calculator;
import calculator.storage.HistoryStorage;

public class App {

public static void main(String[] args) {
HistoryStorage historyStorage = new HistoryStorage();
Calculator calculator = new Calculator(historyStorage);
MainController mainController = new MainController(historyStorage, calculator);

try {
mainController.run();
} catch (Exception e) {
printWithLineBreak(e.getMessage());
} finally {
showQuitMessage();
}
}
}
49 changes: 49 additions & 0 deletions app/src/main/java/calculator/controller/MainController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package calculator.controller;

import static calculator.entity.Menu.getSelectedMenu;
import static calculator.view.InputView.inputMenuNumber;
import static calculator.view.OutputView.showAllHistory;
import static calculator.view.OutputView.showMenu;

import calculator.entity.Menu;
import calculator.service.Calculator;
import calculator.storage.HistoryStorage;

public class MainController {

private final HistoryStorage historyStorage;
private final Calculator calculator;

public MainController(HistoryStorage historyStorage, Calculator calculator) {
this.historyStorage = historyStorage;
this.calculator = calculator;
}

public void run() {
boolean isRunning = true;

while (isRunning) {
showMenu();

int menuNumber = inputMenuNumber();
Menu selectedMenu = getSelectedMenu(menuNumber);

isRunning = !selectedMenu.isQuit();

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

! 부정 연산자는 한번 더 생각하게 만드는 느낌이 있습니다. 차라리 isRunning() 메서드로 만드시는 것은 어떻게 생각하시나요?


execute(selectedMenu);
}
}

private void execute(Menu selectedMenu) {
if (selectedMenu.isReadHistory()) {
String[] allHistory = historyStorage.readAllHistory();
showAllHistory(allHistory);

return;
}

if (selectedMenu.isCalculate()) {
calculator.calculate();
}
}
}
18 changes: 18 additions & 0 deletions app/src/main/java/calculator/entity/Expression.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package calculator.entity;

public class Expression {

private final Operator operator;
private final int operand1;
private final int operand2;

public Expression(Operator operator, int operand1, int operand2) {
this.operator = operator;
this.operand1 = operand1;
this.operand2 = operand2;
}

public int evaluate() {
return operator.evaluate(operand1, operand2);
}
}
48 changes: 48 additions & 0 deletions app/src/main/java/calculator/entity/Menu.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package calculator.entity;

import calculator.exception.MenuInputException;
import java.util.Arrays;

public enum Menu {

READ_HISTORY(1, "조회"),
CALCULATE(2, "계산"),
QUIT(3, "종료");

private static final String NOT_EXIST_MENU_MESSAGE = "존재하지 않는 메뉴입니다.";
private final int number;
private final String name;

Menu(int number, String name) {
this.number = number;
this.name = name;
}

public static Menu getSelectedMenu(int selectedMenuNumber) {
return Arrays.stream(Menu.values())
.filter(menu -> selectedMenuNumber == menu.getNumber())
.findFirst()
.orElseThrow(() -> new MenuInputException(NOT_EXIST_MENU_MESSAGE));
}

public boolean isReadHistory() {
return this == Menu.READ_HISTORY;
}

public boolean isCalculate() {
return this == Menu.CALCULATE;
}

public boolean isQuit() {
return this == Menu.QUIT;
}

public int getNumber() {
return number;
}

@Override
public String toString() {
return number + "." + name;
}
}
Loading