- 
                Notifications
    You must be signed in to change notification settings 
- Fork 155
[4기 - 강병곤] 1~2주차 과제 : 계산기 구현 미션 제출합니다. #189
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
base: Curry4182
Are you sure you want to change the base?
Changes from 8 commits
ea304be
              610619a
              bf3f864
              218140d
              bbd270b
              4b4de21
              de08a26
              8a8d6c2
              9c15fa9
              3c3a5e2
              File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
| Original file line number | Diff line number | Diff line change | 
|---|---|---|
| @@ -1,31 +1,27 @@ | ||
| package calcproject; | ||
|  | ||
| import java.util.HashMap; | ||
| import java.util.Map; | ||
| import java.util.Scanner; | ||
|  | ||
| import calcproject.di.container.CalcManagerDependencyInjectionContainer; | ||
| import calcproject.engine.CalcExpressionTokenizer; | ||
| import calcproject.engine.Calculator; | ||
| import calcproject.models.CalcResultRecordModel; | ||
| import calcproject.repository.CalcResultRecordRepository; | ||
| import calcproject.repository.MemoryCalcResultRecordRepository; | ||
| import calcproject.factory.CalcManagerViewFactory; | ||
| import calcproject.factory.CalcResultRecordRepositoryFactory; | ||
| import calcproject.factory.ConsoleViewCalcManagerViewFactory; | ||
| import calcproject.factory.InMemoryCalcResultRecordRepositoryFacotry; | ||
| import calcproject.service.CalcManager; | ||
| import calcproject.view.console.CalcConsoleView; | ||
|  | ||
| public class Main { | ||
| public static void main(String[] args) { | ||
| Map<Integer, CalcResultRecordModel> calcMap = new HashMap<>(); | ||
| int startIdx = 0; | ||
| CalcResultRecordRepository calcResultRecordRepository = | ||
| new MemoryCalcResultRecordRepository(calcMap, startIdx); | ||
| Scanner scanner = new Scanner(System.in); | ||
| CalcConsoleView calcConsoleView = new CalcConsoleView(scanner); | ||
| CalcExpressionTokenizer calcExpressionTokenizer = new CalcExpressionTokenizer(); | ||
| Calculator calculator = new Calculator(calcExpressionTokenizer); | ||
|  | ||
| CalcManager calcManager = new CalcManager(calcResultRecordRepository, calcConsoleView, calcConsoleView, | ||
| calculator); | ||
| CalcManagerViewFactory calcManagerViewFactory = new ConsoleViewCalcManagerViewFactory(); | ||
| CalcResultRecordRepositoryFactory calcResultRecordRepositoryFactory = new InMemoryCalcResultRecordRepositoryFacotry(); | ||
|  | ||
| CalcManagerDependencyInjectionContainer calcManagerDependencyInjectionContainer = | ||
| new CalcManagerDependencyInjectionContainer(calcResultRecordRepositoryFactory, calcManagerViewFactory, | ||
| calculator); | ||
|  | ||
| CalcManager calcManager = calcManagerDependencyInjectionContainer.createCalcManager(); | ||
| calcManager.startCalcManager(); | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change | 
|---|---|---|
| @@ -0,0 +1,46 @@ | ||
| package calcproject.di.container; | ||
|  | ||
| import calcproject.engine.Calculator; | ||
| import calcproject.factory.CalcManagerViewFactory; | ||
| import calcproject.factory.CalcResultRecordRepositoryFactory; | ||
| import calcproject.repository.CalcResultRecordRepository; | ||
| import calcproject.service.CalcManager; | ||
| import calcproject.view.CalcInput; | ||
| import calcproject.view.CalcOutput; | ||
|  | ||
| public class CalcManagerDependencyInjectionContainer { | ||
| There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. DependencyInjectionContainer라는 네이밍은 너무 스프링 기술에 치중되어 있는 느낌이 드는데요, | ||
|  | ||
| private CalcResultRecordRepositoryFactory calcResultRecordRepositoryFactory; | ||
|  | ||
| private CalcManagerViewFactory calcManagerViewFactory; | ||
|  | ||
| private Calculator calculator; | ||
|  | ||
| public CalcManagerDependencyInjectionContainer( | ||
| CalcResultRecordRepositoryFactory calcResultRecordRepositoryFactory, | ||
| CalcManagerViewFactory calcManagerViewFactory, Calculator calculator) { | ||
| this.calcResultRecordRepositoryFactory = calcResultRecordRepositoryFactory; | ||
| this.calcManagerViewFactory = calcManagerViewFactory; | ||
| this.calculator = calculator; | ||
| } | ||
|  | ||
| public CalcManager createCalcManager() { | ||
| CalcResultRecordRepository calcResultRecordRepository = | ||
| calcResultRecordRepositoryFactory.createCalcResultRecordRepository(); | ||
|  | ||
| CalcInput calcInput = | ||
| calcManagerViewFactory.createCalcInput(); | ||
|  | ||
| CalcOutput calcOutput = | ||
| calcManagerViewFactory.createCalcOutput(); | ||
|  | ||
| CalcManager calcManager = new CalcManager( | ||
| calcResultRecordRepository, | ||
| calcInput, | ||
| calcOutput, | ||
| this.calculator | ||
| ); | ||
|  | ||
| return calcManager; | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change | 
|---|---|---|
| @@ -1,9 +1,36 @@ | ||
| package calcproject.engine; | ||
|  | ||
| import java.util.ArrayList; | ||
| import java.util.List; | ||
|  | ||
| public class CalcExpressionTokenizer { | ||
| public List<String> tokenizeExpression(String expression) { | ||
| return null; | ||
| List<String> tokens = new ArrayList<>(); | ||
| StringBuilder sb = new StringBuilder(); | ||
|  | ||
| for (int i = 0; i < expression.length(); i++) { | ||
| char ch = expression.charAt(i); | ||
|  | ||
| if (ch == ' ') { | ||
| continue; | ||
| } | ||
|  | ||
| if (Character.isDigit(ch)) { | ||
| sb.append(ch); | ||
| } else { | ||
| String numberString = sb.toString(); | ||
| tokens.add(numberString); | ||
| sb.setLength(0); | ||
|  | ||
| tokens.add(Character.toString(ch)); | ||
| } | ||
| There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. if (isOperator) 를 만들어서 else를 사용하지 않는 건 어떠신가요? | ||
| } | ||
|  | ||
| if (sb.length() > 0) { | ||
| String numberString = sb.toString(); | ||
| tokens.add(numberString); | ||
| 
      Comment on lines
    
      +24
     to 
      +25
    
   There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 반복되는 코드가 나오는 것 같은데 공통 메서드로 추출하는 건 어떠신가요? | ||
| } | ||
|  | ||
| return tokens; | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change | 
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| package calcproject.engine; | ||
|  | ||
| public interface Calculable { | ||
| public double calculate(double num1, double num2); | ||
| } | 
| Original file line number | Diff line number | Diff line change | 
|---|---|---|
| @@ -1,6 +1,8 @@ | ||
| package calcproject.engine; | ||
|  | ||
| import java.util.ArrayList; | ||
| import java.util.List; | ||
| import java.util.Stack; | ||
|  | ||
| public class Calculator { | ||
| private CalcExpressionTokenizer calcExpressionTokenizer; | ||
|  | @@ -9,8 +11,75 @@ public Calculator(CalcExpressionTokenizer calcExpressionTokenizer) { | |
| this.calcExpressionTokenizer = calcExpressionTokenizer; | ||
| } | ||
|  | ||
| private boolean isNumber(String token) { | ||
| for (int i = 0; i < token.length(); i++) { | ||
| if (!Character.isDigit(token.charAt(i))) | ||
| return false; | ||
| } | ||
| return true; | ||
| } | ||
|  | ||
| public List<String> tokensToPostfixNotation(List<String> tokens) { | ||
| Stack<String> stack = new Stack<>(); | ||
| List<String> postFixNotationTokens = new ArrayList<>(); | ||
| for (String currentToken : tokens) { | ||
| if (isNumber(currentToken)) { | ||
| postFixNotationTokens.add(currentToken); | ||
| continue; | ||
| } | ||
|  | ||
| while (!stack.empty()) { | ||
| Operator currentOperator = Operator.opValueOf(currentToken); | ||
| Operator stackPeekOPerator = Operator.opValueOf(stack.peek()); | ||
|  | ||
| if (stackPeekOPerator == Operator.UnSupportedOp) { | ||
| return null; | ||
| } | ||
| There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. List을 반환값으로 가지고 있는데 null을 반환하는 이유가 있을까요? | ||
|  | ||
| if (currentOperator.getPriority() > stackPeekOPerator.getPriority()) { | ||
| break; | ||
| } | ||
|  | ||
| postFixNotationTokens.add(stack.pop()); | ||
| } | ||
|  | ||
| stack.add(currentToken); | ||
| } | ||
|  | ||
| while (!stack.empty()) { | ||
| postFixNotationTokens.add(stack.pop()); | ||
| } | ||
|  | ||
| return postFixNotationTokens; | ||
| } | ||
|  | ||
| public double calculatePostfixNotation(List<String> postFixNotationTokens) { | ||
| Stack<Double> stack = new Stack<>(); | ||
|  | ||
| for (int i = 0; i < postFixNotationTokens.size(); i++) { | ||
| String token = postFixNotationTokens.get(i); | ||
|          | ||
|  | ||
| if (isNumber(token)) { | ||
| double num = Double.valueOf(token); | ||
| stack.push(num); | ||
| } else { | ||
| Operator operator = Operator.opValueOf(token); | ||
|  | ||
| double operand2 = stack.pop(); | ||
| double operand1 = stack.pop(); | ||
| 
      Comment on lines
    
      +67
     to 
      +68
    
   There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. stack이 비어있다면 어떻게 되나요? | ||
| double result = operator.calculate(operand1, operand2); | ||
| stack.push(result); | ||
| } | ||
| } | ||
|  | ||
| return stack.pop(); | ||
| } | ||
|  | ||
| public double calculateExpression(String expression) { | ||
| List<String> tokens = calcExpressionTokenizer.tokenizeExpression(expression); | ||
| return Double.NaN; | ||
| List<String> postfixTokens = tokensToPostfixNotation(tokens); | ||
| double calcResult = calculatePostfixNotation(tokens); | ||
|  | ||
| return calcResult; | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change | 
|---|---|---|
| @@ -0,0 +1,44 @@ | ||
| package calcproject.engine; | ||
|  | ||
| import java.util.Arrays; | ||
|  | ||
| public enum Operator { | ||
| Plus("+", 0, (a, b) -> a + b), | ||
| Minus("-", 0, (a, b) -> a - b), | ||
| Multiply("*", 1, (a, b) -> a * b), | ||
| Divide("/", 1, (a, b) -> a / b), | ||
| UnSupportedOp("", -1, (a, b) -> Double.NaN); | ||
| There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 반환 값으로 UnSupportedOp를 사용하게 되면 어떻게 되나요? | ||
|  | ||
| private String operator; | ||
| private int priority; | ||
| private Calculable calculable; | ||
|  | ||
| Operator(String operator, int priority, Calculable calculable) { | ||
| this.operator = operator; | ||
| this.priority = priority; | ||
| this.calculable = calculable; | ||
| } | ||
|  | ||
| public static Operator opValueOf(String op) { | ||
| return Arrays.stream(values()) | ||
| .filter( | ||
| value -> value | ||
| .getOperator() | ||
| .equals(op) | ||
| ) | ||
| .findAny() | ||
| .orElse(Operator.UnSupportedOp); | ||
| } | ||
|  | ||
| public String getOperator() { | ||
| return this.operator; | ||
| } | ||
|  | ||
| public int getPriority() { | ||
| return this.priority; | ||
| } | ||
|  | ||
| public double calculate(double num1, double num2) { | ||
| return this.calculable.calculate(num1, num2); | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change | 
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| package calcproject.engine.tokenaction; | ||
|  | ||
| public interface TokenAction { | ||
| void perform(); | ||
| } | ||
|          | ||
| Original file line number | Diff line number | Diff line change | 
|---|---|---|
| @@ -0,0 +1,10 @@ | ||
| package calcproject.factory; | ||
|  | ||
| import calcproject.view.CalcInput; | ||
| import calcproject.view.CalcOutput; | ||
|  | ||
| public interface CalcManagerViewFactory { | ||
| public CalcInput createCalcInput(); | ||
|  | ||
| public CalcOutput createCalcOutput(); | ||
| } | 
| Original file line number | Diff line number | Diff line change | 
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| package calcproject.factory; | ||
|  | ||
| import calcproject.repository.CalcResultRecordRepository; | ||
|  | ||
| public interface CalcResultRecordRepositoryFactory { | ||
| public CalcResultRecordRepository createCalcResultRecordRepository(); | ||
| } | 
| Original file line number | Diff line number | Diff line change | 
|---|---|---|
| @@ -0,0 +1,29 @@ | ||
| package calcproject.factory; | ||
|  | ||
| import calcproject.view.CalcInput; | ||
| import calcproject.view.CalcOutput; | ||
| import calcproject.view.console.CalcConsoleView; | ||
|  | ||
| public class ConsoleViewCalcManagerViewFactory implements CalcManagerViewFactory { | ||
|  | ||
| private CalcConsoleView calcConsoleView; | ||
|  | ||
| public ConsoleViewCalcManagerViewFactory() { | ||
| this.calcConsoleView = createCalcConsoleView(); | ||
| } | ||
|  | ||
| public CalcConsoleView createCalcConsoleView() { | ||
| CalcConsoleView calcConsoleView = new CalcConsoleView(); | ||
| return calcConsoleView; | ||
| } | ||
|  | ||
| @Override | ||
| public CalcInput createCalcInput() { | ||
| return this.calcConsoleView; | ||
| } | ||
|  | ||
| @Override | ||
| public CalcOutput createCalcOutput() { | ||
| return this.calcConsoleView; | ||
| } | ||
| } | 
| Original file line number | Diff line number | Diff line change | 
|---|---|---|
| @@ -0,0 +1,20 @@ | ||
| package calcproject.factory; | ||
|  | ||
| import java.util.HashMap; | ||
| import java.util.Map; | ||
|  | ||
| import calcproject.models.CalcResultRecordModel; | ||
| import calcproject.repository.CalcResultRecordRepository; | ||
| import calcproject.repository.MemoryCalcResultRecordRepository; | ||
|  | ||
| public class InMemoryCalcResultRecordRepositoryFacotry implements CalcResultRecordRepositoryFactory { | ||
| @Override | ||
| public CalcResultRecordRepository createCalcResultRecordRepository() { | ||
| Map<Integer, CalcResultRecordModel> calcMap = new HashMap<>(); | ||
| int startIdx = 0; | ||
| CalcResultRecordRepository calcResultRecordRepository = | ||
| new MemoryCalcResultRecordRepository(calcMap); | ||
|  | ||
| return calcResultRecordRepository; | ||
| } | ||
| } | 
| Original file line number | Diff line number | Diff line change | 
|---|---|---|
|  | @@ -12,9 +12,9 @@ public class MemoryCalcResultRecordRepository implements CalcResultRecordReposit | |
| private Map<Integer, CalcResultRecordModel> calcMap; | ||
| There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 입력과 조회(모든 레코드) 두 가지 기능만 사용하고 있는데 굳이 Map을 쓰신 이유가 있나요? | ||
| private int lastIdx; | ||
|  | ||
| public MemoryCalcResultRecordRepository(Map<Integer, CalcResultRecordModel> calcMap, int startIdx) { | ||
| public MemoryCalcResultRecordRepository(Map<Integer, CalcResultRecordModel> calcMap) { | ||
| this.calcMap = calcMap; | ||
| this.lastIdx = startIdx; | ||
| this.lastIdx = 0; | ||
| } | ||
|  | ||
| @Override | ||
|  | @@ -27,7 +27,7 @@ public void saveCalcResultRecord(CalcResultRecordModel calcResultRecord) { | |
| public List<CalcResultRecordModel> loadCalcResultRecords() { | ||
| return this.calcMap.values() | ||
| .stream() | ||
| .sorted(Comparator.comparing(calcModel -> calcModel.getId())) | ||
| .sorted(Comparator.comparing(CalcResultRecordModel::getId)) | ||
| .collect(Collectors.toList()); | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change | 
|---|---|---|
|  | @@ -54,4 +54,4 @@ private void executeCmd(Command cmd) { | |
| break; | ||
| } | ||
| } | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change | 
|---|---|---|
|  | @@ -15,7 +15,7 @@ public enum Command { | |
|  | ||
| public static Command valueOf(int choiceNum) { | ||
| return Arrays.stream(values()) | ||
| .filter(value -> value.equals(choiceNum)) | ||
| .filter(value -> value.getCmdIdx() == choiceNum) | ||
| There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 비교하는 메서드를 따로 만드는건 어떨까요? | ||
| .findAny() | ||
| .orElse(CALCULATE.EXIT); | ||
| There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. CALCULATE.EXIT는 사용자 의도로 인해 종료한다는 느낌인데요 | ||
| } | ||
|  | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
모든 객체가 main을 통해서 생성되고 있어서, main과 강한 의존성을 가지겠네요.
구조를 짜고 계층형으로 분리하면 좀 더 좋을 것 같아요.