diff --git a/.idea/2021-Java-Study.iml b/.idea/2021-Java-Study.iml
new file mode 100644
index 00000000..d6ebd480
--- /dev/null
+++ b/.idea/2021-Java-Study.iml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
new file mode 100644
index 00000000..40674af8
--- /dev/null
+++ b/.idea/misc.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
new file mode 100644
index 00000000..7fabbc98
--- /dev/null
+++ b/.idea/modules.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 00000000..35eb1ddf
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/workspace.xml b/.idea/workspace.xml
new file mode 100644
index 00000000..c40d1f3d
--- /dev/null
+++ b/.idea/workspace.xml
@@ -0,0 +1,44 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 1617259629172
+
+
+ 1617259629172
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/CQRS.md b/CQRS.md
new file mode 100644
index 00000000..7985879f
--- /dev/null
+++ b/CQRS.md
@@ -0,0 +1,25 @@
+# 자바 기초
+## CQRS
+> CQRS는 Command and Query Responsibility Segregation(명령과 조회의 책임 분리)을 나타낸다. 이름처럼 시스템에서 명령을 처리하는 책임과 조회를 처리하는 책임을 분리하는 것이 CQRS의 핵심이다.
+
+
+
+- 명령(Command) : 시스템의 상태를 변경하는 작업
+ - ex) 주문 취소, 배송 완료
+- 쿼리(Query) : 시스템의 상태를 반환하는 작업
+ - ex) 주문 목록
+- 책임(Responsibility) : 구성 요소의 역할
+ - 구성 요소 : 클래스, 함수, 모듈/패키지, 웹서버/DB
+
+- 분리(Segregation) : 역할에 따라 구성 요소 나누기
+
+### 명령과 조회에 단일 모델을 사용한다면?
+🔍 명령과 쿼리가 다루는 데이터가 다르기 때문에 이도 저도 아닌 잡탕이 된다.
+- 코드 역할/책임 모호
+- 의미/가독성 등 나빠짐
+- 유지보수성이 떨어짐
+ - 명령과 쿼리는 코드 변경 빈도/사용자가 다르기 때문
+ - 기능마다 요구하는 성능이 다르기 때문
+
+
+
diff --git a/racingcar/.gradle/6.7/executionHistory/executionHistory.bin b/racingcar/.gradle/6.7/executionHistory/executionHistory.bin
new file mode 100644
index 00000000..fa5d6d6b
Binary files /dev/null and b/racingcar/.gradle/6.7/executionHistory/executionHistory.bin differ
diff --git a/racingcar/.gradle/6.7/executionHistory/executionHistory.lock b/racingcar/.gradle/6.7/executionHistory/executionHistory.lock
new file mode 100644
index 00000000..8dba8f0d
Binary files /dev/null and b/racingcar/.gradle/6.7/executionHistory/executionHistory.lock differ
diff --git a/racingcar/.gradle/6.7/fileChanges/last-build.bin b/racingcar/.gradle/6.7/fileChanges/last-build.bin
new file mode 100644
index 00000000..f76dd238
Binary files /dev/null and b/racingcar/.gradle/6.7/fileChanges/last-build.bin differ
diff --git a/racingcar/.gradle/6.7/fileHashes/fileHashes.bin b/racingcar/.gradle/6.7/fileHashes/fileHashes.bin
new file mode 100644
index 00000000..661393ed
Binary files /dev/null and b/racingcar/.gradle/6.7/fileHashes/fileHashes.bin differ
diff --git a/racingcar/.gradle/6.7/fileHashes/fileHashes.lock b/racingcar/.gradle/6.7/fileHashes/fileHashes.lock
new file mode 100644
index 00000000..a02bace5
Binary files /dev/null and b/racingcar/.gradle/6.7/fileHashes/fileHashes.lock differ
diff --git a/racingcar/.gradle/6.7/gc.properties b/racingcar/.gradle/6.7/gc.properties
new file mode 100644
index 00000000..e69de29b
diff --git a/racingcar/.gradle/6.7/javaCompile/javaCompile.lock b/racingcar/.gradle/6.7/javaCompile/javaCompile.lock
new file mode 100644
index 00000000..d5d6533a
Binary files /dev/null and b/racingcar/.gradle/6.7/javaCompile/javaCompile.lock differ
diff --git a/racingcar/.gradle/6.7/javaCompile/taskHistory.bin b/racingcar/.gradle/6.7/javaCompile/taskHistory.bin
new file mode 100644
index 00000000..3f5afb7e
Binary files /dev/null and b/racingcar/.gradle/6.7/javaCompile/taskHistory.bin differ
diff --git a/racingcar/.gradle/buildOutputCleanup/buildOutputCleanup.lock b/racingcar/.gradle/buildOutputCleanup/buildOutputCleanup.lock
new file mode 100644
index 00000000..080f075f
Binary files /dev/null and b/racingcar/.gradle/buildOutputCleanup/buildOutputCleanup.lock differ
diff --git a/racingcar/.gradle/buildOutputCleanup/cache.properties b/racingcar/.gradle/buildOutputCleanup/cache.properties
new file mode 100644
index 00000000..f53ce95e
--- /dev/null
+++ b/racingcar/.gradle/buildOutputCleanup/cache.properties
@@ -0,0 +1,2 @@
+#Mon Apr 12 17:58:13 KST 2021
+gradle.version=6.7
diff --git a/racingcar/.gradle/buildOutputCleanup/outputFiles.bin b/racingcar/.gradle/buildOutputCleanup/outputFiles.bin
new file mode 100644
index 00000000..36368bec
Binary files /dev/null and b/racingcar/.gradle/buildOutputCleanup/outputFiles.bin differ
diff --git a/racingcar/.gradle/checksums/checksums.lock b/racingcar/.gradle/checksums/checksums.lock
new file mode 100644
index 00000000..f0f1452d
Binary files /dev/null and b/racingcar/.gradle/checksums/checksums.lock differ
diff --git a/racingcar/.gradle/configuration-cache/gc.properties b/racingcar/.gradle/configuration-cache/gc.properties
new file mode 100644
index 00000000..e69de29b
diff --git a/racingcar/.gradle/vcs-1/gc.properties b/racingcar/.gradle/vcs-1/gc.properties
new file mode 100644
index 00000000..e69de29b
diff --git a/racingcar/.idea/.gitignore b/racingcar/.idea/.gitignore
new file mode 100644
index 00000000..ed950358
--- /dev/null
+++ b/racingcar/.idea/.gitignore
@@ -0,0 +1,8 @@
+# Default ignored files
+/shelf/
+/workspace.xml
+# Datasource local storage ignored files
+/../../../../../../:\Users\nohyg\IdeaProjects\racingcar\.idea/dataSources/
+/dataSources.local.xml
+# Editor-based HTTP Client requests
+/httpRequests/
diff --git a/racingcar/.idea/compiler.xml b/racingcar/.idea/compiler.xml
new file mode 100644
index 00000000..61a9130c
--- /dev/null
+++ b/racingcar/.idea/compiler.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/racingcar/.idea/gradle.xml b/racingcar/.idea/gradle.xml
new file mode 100644
index 00000000..02b3e5bf
--- /dev/null
+++ b/racingcar/.idea/gradle.xml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/racingcar/.idea/jarRepositories.xml b/racingcar/.idea/jarRepositories.xml
new file mode 100644
index 00000000..fdc392fe
--- /dev/null
+++ b/racingcar/.idea/jarRepositories.xml
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/racingcar/.idea/misc.xml b/racingcar/.idea/misc.xml
new file mode 100644
index 00000000..2266f6bc
--- /dev/null
+++ b/racingcar/.idea/misc.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/racingcar/.idea/modules/racingcar.iml b/racingcar/.idea/modules/racingcar.iml
new file mode 100644
index 00000000..5e3f563c
--- /dev/null
+++ b/racingcar/.idea/modules/racingcar.iml
@@ -0,0 +1,2 @@
+
+
\ No newline at end of file
diff --git a/racingcar/build.gradle b/racingcar/build.gradle
new file mode 100644
index 00000000..95687b5b
--- /dev/null
+++ b/racingcar/build.gradle
@@ -0,0 +1,19 @@
+plugins {
+ id 'java'
+}
+
+group 'org.example'
+version '1.0-SNAPSHOT'
+
+repositories {
+ mavenCentral()
+}
+
+dependencies {
+ testImplementation 'org.junit.jupiter:junit-jupiter-api:5.6.0'
+ testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine'
+}
+
+test {
+ useJUnitPlatform()
+}
\ No newline at end of file
diff --git a/racingcar/build/classes/java/main/Application.class b/racingcar/build/classes/java/main/Application.class
new file mode 100644
index 00000000..861c6036
Binary files /dev/null and b/racingcar/build/classes/java/main/Application.class differ
diff --git a/racingcar/build/classes/java/main/racingcar/Car.class b/racingcar/build/classes/java/main/racingcar/Car.class
new file mode 100644
index 00000000..8fe4c1d1
Binary files /dev/null and b/racingcar/build/classes/java/main/racingcar/Car.class differ
diff --git a/racingcar/build/classes/java/main/racingcar/Cars.class b/racingcar/build/classes/java/main/racingcar/Cars.class
new file mode 100644
index 00000000..97b65fbf
Binary files /dev/null and b/racingcar/build/classes/java/main/racingcar/Cars.class differ
diff --git a/racingcar/build/classes/java/main/racingcar/Game.class b/racingcar/build/classes/java/main/racingcar/Game.class
new file mode 100644
index 00000000..1746d845
Binary files /dev/null and b/racingcar/build/classes/java/main/racingcar/Game.class differ
diff --git a/racingcar/build/classes/java/main/racingcar/Winner.class b/racingcar/build/classes/java/main/racingcar/Winner.class
new file mode 100644
index 00000000..d388d4b6
Binary files /dev/null and b/racingcar/build/classes/java/main/racingcar/Winner.class differ
diff --git a/racingcar/build/classes/java/main/utils/RandomUtils.class b/racingcar/build/classes/java/main/utils/RandomUtils.class
new file mode 100644
index 00000000..b37e7178
Binary files /dev/null and b/racingcar/build/classes/java/main/utils/RandomUtils.class differ
diff --git a/racingcar/build/classes/java/main/view/InputView.class b/racingcar/build/classes/java/main/view/InputView.class
new file mode 100644
index 00000000..24e1815c
Binary files /dev/null and b/racingcar/build/classes/java/main/view/InputView.class differ
diff --git a/racingcar/build/classes/java/main/view/ResultView.class b/racingcar/build/classes/java/main/view/ResultView.class
new file mode 100644
index 00000000..8326b991
Binary files /dev/null and b/racingcar/build/classes/java/main/view/ResultView.class differ
diff --git a/racingcar/build/tmp/compileJava/source-classes-mapping.txt b/racingcar/build/tmp/compileJava/source-classes-mapping.txt
new file mode 100644
index 00000000..b58b8b59
--- /dev/null
+++ b/racingcar/build/tmp/compileJava/source-classes-mapping.txt
@@ -0,0 +1,16 @@
+racingcar/Winner.java
+ racingcar.Winner
+racingcar/Game.java
+ racingcar.Game
+view/ResultView.java
+ view.ResultView
+Application.java
+ Application
+view/InputView.java
+ view.InputView
+racingcar/Car.java
+ racingcar.Car
+racingcar/Cars.java
+ racingcar.Cars
+utils/RandomUtils.java
+ utils.RandomUtils
diff --git a/racingcar/gradle/wrapper/gradle-wrapper.jar b/racingcar/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 00000000..e708b1c0
Binary files /dev/null and b/racingcar/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/racingcar/gradle/wrapper/gradle-wrapper.properties b/racingcar/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 00000000..be52383e
--- /dev/null
+++ b/racingcar/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,5 @@
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-6.7-bin.zip
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
diff --git a/racingcar/gradlew b/racingcar/gradlew
new file mode 100644
index 00000000..4f906e0c
--- /dev/null
+++ b/racingcar/gradlew
@@ -0,0 +1,185 @@
+#!/usr/bin/env sh
+
+#
+# Copyright 2015 the original author or authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+##############################################################################
+##
+## Gradle start up script for UN*X
+##
+##############################################################################
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+ ls=`ls -ld "$PRG"`
+ link=`expr "$ls" : '.*-> \(.*\)$'`
+ if expr "$link" : '/.*' > /dev/null; then
+ PRG="$link"
+ else
+ PRG=`dirname "$PRG"`"/$link"
+ fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >/dev/null
+APP_HOME="`pwd -P`"
+cd "$SAVED" >/dev/null
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn () {
+ echo "$*"
+}
+
+die () {
+ echo
+ echo "$*"
+ echo
+ exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+nonstop=false
+case "`uname`" in
+ CYGWIN* )
+ cygwin=true
+ ;;
+ Darwin* )
+ darwin=true
+ ;;
+ MINGW* )
+ msys=true
+ ;;
+ NONSTOP* )
+ nonstop=true
+ ;;
+esac
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD="$JAVA_HOME/jre/sh/java"
+ else
+ JAVACMD="$JAVA_HOME/bin/java"
+ fi
+ if [ ! -x "$JAVACMD" ] ; then
+ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+else
+ JAVACMD="java"
+ which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
+ MAX_FD_LIMIT=`ulimit -H -n`
+ if [ $? -eq 0 ] ; then
+ if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+ MAX_FD="$MAX_FD_LIMIT"
+ fi
+ ulimit -n $MAX_FD
+ if [ $? -ne 0 ] ; then
+ warn "Could not set maximum file descriptor limit: $MAX_FD"
+ fi
+ else
+ warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+ fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+ GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin or MSYS, switch paths to Windows format before running java
+if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
+ APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+ CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+
+ JAVACMD=`cygpath --unix "$JAVACMD"`
+
+ # We build the pattern for arguments to be converted via cygpath
+ ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+ SEP=""
+ for dir in $ROOTDIRSRAW ; do
+ ROOTDIRS="$ROOTDIRS$SEP$dir"
+ SEP="|"
+ done
+ OURCYGPATTERN="(^($ROOTDIRS))"
+ # Add a user-defined pattern to the cygpath arguments
+ if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+ OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+ fi
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ i=0
+ for arg in "$@" ; do
+ CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+ CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
+
+ if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
+ eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+ else
+ eval `echo args$i`="\"$arg\""
+ fi
+ i=`expr $i + 1`
+ done
+ case $i in
+ 0) set -- ;;
+ 1) set -- "$args0" ;;
+ 2) set -- "$args0" "$args1" ;;
+ 3) set -- "$args0" "$args1" "$args2" ;;
+ 4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+ 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+ 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+ 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+ 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+ 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+ esac
+fi
+
+# Escape application args
+save () {
+ for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
+ echo " "
+}
+APP_ARGS=`save "$@"`
+
+# Collect all arguments for the java command, following the shell quoting and substitution rules
+eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
+
+exec "$JAVACMD" "$@"
diff --git a/racingcar/gradlew.bat b/racingcar/gradlew.bat
new file mode 100644
index 00000000..107acd32
--- /dev/null
+++ b/racingcar/gradlew.bat
@@ -0,0 +1,89 @@
+@rem
+@rem Copyright 2015 the original author or authors.
+@rem
+@rem Licensed under the Apache License, Version 2.0 (the "License");
+@rem you may not use this file except in compliance with the License.
+@rem You may obtain a copy of the License at
+@rem
+@rem https://www.apache.org/licenses/LICENSE-2.0
+@rem
+@rem Unless required by applicable law or agreed to in writing, software
+@rem distributed under the License is distributed on an "AS IS" BASIS,
+@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+@rem See the License for the specific language governing permissions and
+@rem limitations under the License.
+@rem
+
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Resolve any "." and ".." in APP_HOME to make it shorter.
+for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto execute
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto execute
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/racingcar/out/production/classes/Application.class b/racingcar/out/production/classes/Application.class
new file mode 100644
index 00000000..861c6036
Binary files /dev/null and b/racingcar/out/production/classes/Application.class differ
diff --git a/racingcar/out/production/classes/StreamTest.class b/racingcar/out/production/classes/StreamTest.class
new file mode 100644
index 00000000..d23c190d
Binary files /dev/null and b/racingcar/out/production/classes/StreamTest.class differ
diff --git a/racingcar/out/production/classes/racingcar/Car.class b/racingcar/out/production/classes/racingcar/Car.class
new file mode 100644
index 00000000..7bd5cebe
Binary files /dev/null and b/racingcar/out/production/classes/racingcar/Car.class differ
diff --git a/racingcar/out/production/classes/racingcar/Cars.class b/racingcar/out/production/classes/racingcar/Cars.class
new file mode 100644
index 00000000..52c8d4d2
Binary files /dev/null and b/racingcar/out/production/classes/racingcar/Cars.class differ
diff --git a/racingcar/out/production/classes/racingcar/Game.class b/racingcar/out/production/classes/racingcar/Game.class
new file mode 100644
index 00000000..faf03591
Binary files /dev/null and b/racingcar/out/production/classes/racingcar/Game.class differ
diff --git a/racingcar/out/production/classes/racingcar/Winner.class b/racingcar/out/production/classes/racingcar/Winner.class
new file mode 100644
index 00000000..d388d4b6
Binary files /dev/null and b/racingcar/out/production/classes/racingcar/Winner.class differ
diff --git a/racingcar/out/production/classes/utils/RandomUtils.class b/racingcar/out/production/classes/utils/RandomUtils.class
new file mode 100644
index 00000000..e79d6ff3
Binary files /dev/null and b/racingcar/out/production/classes/utils/RandomUtils.class differ
diff --git a/racingcar/out/production/classes/view/InputView.class b/racingcar/out/production/classes/view/InputView.class
new file mode 100644
index 00000000..ed04c004
Binary files /dev/null and b/racingcar/out/production/classes/view/InputView.class differ
diff --git a/racingcar/out/production/classes/view/ResultView.class b/racingcar/out/production/classes/view/ResultView.class
new file mode 100644
index 00000000..901d55d1
Binary files /dev/null and b/racingcar/out/production/classes/view/ResultView.class differ
diff --git a/racingcar/settings.gradle b/racingcar/settings.gradle
new file mode 100644
index 00000000..563821bb
--- /dev/null
+++ b/racingcar/settings.gradle
@@ -0,0 +1,2 @@
+rootProject.name = 'racingcar'
+
diff --git a/racingcar/src/main/java/Application.java b/racingcar/src/main/java/Application.java
new file mode 100644
index 00000000..a16bc9a2
--- /dev/null
+++ b/racingcar/src/main/java/Application.java
@@ -0,0 +1,8 @@
+import racingcar.Game;
+
+public class Application {
+ public static void main(String[] args) {
+ Game game = new Game();
+ game.start();
+ }
+}
\ No newline at end of file
diff --git a/racingcar/src/main/java/racingcar/Car.java b/racingcar/src/main/java/racingcar/Car.java
new file mode 100644
index 00000000..118d5432
--- /dev/null
+++ b/racingcar/src/main/java/racingcar/Car.java
@@ -0,0 +1,31 @@
+package racingcar;
+
+import utils.RandomUtils;
+
+public class Car {
+ private static final int FIRST_DIGIT = 0;
+ private static final int LAST_DIGIT = 9;
+ private static final int POINT_DIGIT = 4;
+
+ private final String name;
+ private int position = 0;
+
+ public Car(String name) {
+ this.name = name;
+ }
+
+ public String getName(){
+ return name;
+ }
+
+ public int getPosition(){
+ return position;
+ }
+
+ public void move() {
+ int randomNumber = RandomUtils.nextInt(FIRST_DIGIT, LAST_DIGIT);
+ if (randomNumber >= POINT_DIGIT) {
+ position++;
+ }
+ }
+}
\ No newline at end of file
diff --git a/racingcar/src/main/java/racingcar/Cars.java b/racingcar/src/main/java/racingcar/Cars.java
new file mode 100644
index 00000000..baf918fc
--- /dev/null
+++ b/racingcar/src/main/java/racingcar/Cars.java
@@ -0,0 +1,28 @@
+package racingcar;
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+public class Cars {
+ private List cars;
+
+ public Cars(List carNames) {
+ this.cars = carNames.stream()
+ .map(Car::new)
+ .collect(Collectors.toList());
+ }
+
+ public List run() {
+ for (Car car: cars) {
+ car.move();
+ }
+ return cars;
+ }
+
+ public Winner findWinner() {
+ return new Winner(cars ,cars.stream()
+ .mapToInt(Car::getPosition)
+ .max()
+ .getAsInt());
+ }
+}
diff --git a/racingcar/src/main/java/racingcar/Game.java b/racingcar/src/main/java/racingcar/Game.java
new file mode 100644
index 00000000..f11696a3
--- /dev/null
+++ b/racingcar/src/main/java/racingcar/Game.java
@@ -0,0 +1,21 @@
+package racingcar;
+
+import view.InputView;
+import view.ResultView;
+
+public class Game {
+
+ public void start() {
+ Cars cars = new Cars(InputView.inputCarName());
+ int gameNumber = InputView.inputNumber();
+
+ ResultView.printResultTitle();
+
+ for (int i = 0; i < gameNumber; i++) {
+ ResultView.printResultPosition(cars.run());
+ System.out.println();
+ }
+
+ ResultView.printWinners(cars.findWinner());
+ }
+}
diff --git a/racingcar/src/main/java/racingcar/Winner.java b/racingcar/src/main/java/racingcar/Winner.java
new file mode 100644
index 00000000..06573ec7
--- /dev/null
+++ b/racingcar/src/main/java/racingcar/Winner.java
@@ -0,0 +1,24 @@
+package racingcar;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class Winner {
+ private List cars;
+ private int maxPosition;
+
+ public Winner(List cars, int maxPosition) {
+ this.cars = cars;
+ this.maxPosition = maxPosition;
+ }
+
+ public List getWinnersName() {
+ List winnerNames = new ArrayList<>();
+ for (int i = 0; i < cars.size(); i++) {
+ if(cars.get(i).getPosition() == maxPosition){
+ winnerNames.add(cars.get(i).getName());
+ }
+ }
+ return winnerNames;
+ }
+}
diff --git a/racingcar/src/main/java/utils/RandomUtils.java b/racingcar/src/main/java/utils/RandomUtils.java
new file mode 100644
index 00000000..f951aecf
--- /dev/null
+++ b/racingcar/src/main/java/utils/RandomUtils.java
@@ -0,0 +1,27 @@
+package utils;
+
+import java.util.Random;
+
+public class RandomUtils {
+ private static final Random RANDOM = new Random();
+
+ private RandomUtils() {
+
+ }
+
+ public static int nextInt(final int startInclusive, final int endInclusive) {
+ if (startInclusive > endInclusive) {
+ throw new IllegalArgumentException("[ERROR] Random 값이 잘못 되었습니다.");
+ }
+
+ if (startInclusive < 0) {
+ throw new IllegalArgumentException("[ERROR] Random 값이 잘못 되었습니다.");
+ }
+
+ if (startInclusive == endInclusive) {
+ return startInclusive;
+ }
+
+ return startInclusive + RANDOM.nextInt(endInclusive - startInclusive + 1);
+ }
+}
\ No newline at end of file
diff --git a/racingcar/src/main/java/view/InputView.java b/racingcar/src/main/java/view/InputView.java
new file mode 100644
index 00000000..21941bd5
--- /dev/null
+++ b/racingcar/src/main/java/view/InputView.java
@@ -0,0 +1,26 @@
+package view;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Scanner;
+
+public class InputView {
+ private static final Scanner SCANNER = new Scanner(System.in);
+
+ private InputView() { }
+
+ public static List inputCarName(){
+ System.out.println("경주할 자동차 이름을 입력하세요.(이름은 쉼표(,) 기준으로 구분)");
+ return Arrays.asList(SCANNER.nextLine().split(","));
+ }
+
+ public static int inputNumber(){
+ System.out.println("시도할 회수는 몇회인가요?");
+ try {
+ int number = SCANNER.nextInt();
+ return number;
+ } catch (IllegalArgumentException e) {
+ throw new IllegalArgumentException("[ERROR] 숫자가 아닌 문자를 입력하셨습니다.\n");
+ }
+ }
+}
\ No newline at end of file
diff --git a/racingcar/src/main/java/view/ResultView.java b/racingcar/src/main/java/view/ResultView.java
new file mode 100644
index 00000000..03bf18d1
--- /dev/null
+++ b/racingcar/src/main/java/view/ResultView.java
@@ -0,0 +1,35 @@
+package view;
+
+import racingcar.Car;
+import racingcar.Winner;
+
+import java.util.List;
+
+public class ResultView {
+ public static final String Bar = "-";
+
+ private ResultView() { }
+
+ public static void printResultTitle(){
+ System.out.println();
+ System.out.println("실행 결과");
+ }
+
+ public static void printResultPosition(List cars){
+ for(Car car : cars) {
+ printCarPosition(car);
+ }
+ }
+
+ public static void printCarPosition(Car car) {
+ System.out.print(car.getName() + " : ");
+ for (int i = 0; i < car.getPosition(); i++) {
+ System.out.print(Bar);
+ }
+ System.out.println();
+ }
+
+ public static void printWinners(Winner winner) {
+ System.out.println("최종 우승자: " + winner.getWinnersName());
+ }
+}
diff --git "a/\353\224\224\353\257\270\355\204\260 \353\262\225\354\271\231.md" "b/\353\224\224\353\257\270\355\204\260 \353\262\225\354\271\231.md"
new file mode 100644
index 00000000..e7f6b853
--- /dev/null
+++ "b/\353\224\224\353\257\270\355\204\260 \353\262\225\354\271\231.md"
@@ -0,0 +1,81 @@
+# 디미터 법칙
+> "Object-Oriented Programming: An Objective Sense of Style"에서 처음으로 소개된 개념으로 이 글의 저자들은 디미터라는 이름의 프로젝트를 진행하던 도중 객체들의 협력 경로를 제한하면 결합도를 효과적으로 낮출 수 있다는 사실을 발견했다.
+
+## 구조 은닉 설계
+간단하게 말하면, 긴 객체 구조의 경로를 따라 멀리 떨어져 있는 간접적인(낯선) 객체에 메시지를 보내는(또는 이야기하는) 설계는 피하라는 것이다. 이러한 설계는 일반적으로 불안정한 지점으로, 객체 구조의 변화에 부서지기 쉽다.
+
+
+## Don't Talk to Strangers (낯선 이에게 말하지 마라)
+Don't Talk to Strangers 패턴은 메소드 내에서 어떤 객체에 메시지를 보내야 하는가에 대한 제약을 가한다. 메소드 안에서 다음의 객체들에게만 메시지를 보내야 한다.
+
+1. this(또는 self) 객체
+2. 메소드의 매개변수
+3. this의 속성
+4. this의 속성인 컬렉션의 요소
+5. 메소드 내에서 생성된 객체
+
+좀 더 정확히 표현하자면, 디미터 법칙은 "클래스 C의 메서드 f는 다음과 같은 객체의 메서드만 호출해야 한다"고 주장한다.
+- 클래스 C
+- f가 생성한 객체
+- f 인수로 넘어온 객체
+- C 인스턴스 변수에 저장된 객체
+
+하지만 위 객체에서 허용된 메서드가 반환하는 객체의 메서드는 호출하면 안 된다. 다시 말해, 낯선 사람은 경계하고 친구랑만 놀라는 의미다.
+
+디미터 법칙은 객체의 모든 메소드는 다음에 해당하는 메소드만을 호출해야 한다고 말한다.
+1. 객체 자신의 메소드
+2. 메소드의 매개변수로 넘어온 인자의 메소드
+3. 메소드 내부에서 생성 된 객체의 메소드
+4. 메소드가 포함하고 있는 객체의 메소드
+```java
+class A {
+ private B b;
+ public setA(B b) {
+ b = b;
+ }
+ public myMethod(OtherObject other) {
+ // ...
+ }
+ /* 디미터의 법칙을 잘 따른 예 */
+ public okLawOfDemeter(Paramemter param) {
+ myMethod(); // 자신의 메소드
+ b.method(); // 자신의 멤버의 메소드
+ Local local = new Local();
+ local.method(); // 직접 생성한 객체의 메소드
+ param.method(); // 메소드의 인자로 넘어온 메소드
+ }
+ /* 디미터의 법칙을 어긴 예 */
+ public violateLawOfDemeter(Paramemter param) {
+ C c = param.getC();
+ c.method(); // 인자로 받은 객체에서의 호출.
+ param.getC().method(); // 위와 같음.
+ }
+}
+
+```
+## 디미터 법칙을 위반한 코드 (기차 충돌)
+```java
+object.getChild().getContent().getItem().getTitle();
+```
+getter가 줄줄이 이어진 모습이 기차와 닮아서 열차 전복, 기차 충돌(train wreck) 이라는 단어로 표현하기도 한다.
+
+원거리의 간접적인 객체에 메시지를 보내기 위하여(즉, 원거리의 낯선 사람에게 이야기하기 위해서) 객체의 연결 경로를 따라 더 멀리 순회한다. 이러한 설계는 객체들이 어떻게 연결되어 있는지를 나타내는 특정한 구조와 결합된다. ***프로그램 순회의 경로가 길어질수록 프로그램은 더 불안정해진다.***
+
+## 주의사항
+1. 자료구조라면 디미터 법칙을 거론할 필요가 없다.
+2. 하나의 .을 강제하는 규칙이 아니다.
+```java
+IntStream.of(1, 15, 20, 3, 9)
+ .filter(x -> x > 10)
+ .distinct()
+ .count();
+```
+위 코드에서 of, filter, distinct 메서드는 모두 IntStream이라는 동일한 클래스의 인스턴스를 반환한다. 즉, 이들은 IntStream의 인스턴스를 또다른 IntStream의 인스턴스로 변환한다.
+
+따라서 이 코드는 디미터 법칙을 위반하지 않는다.
+디미터 법칙은 결합도와 관련된 것이며, 이 결합도가 문제가 되는 것은 객체의 내부 구조가 외부로 노출되는 경우로 한정된다.
+
+## Reference
+- [디미터 법칙](https://johngrib.github.io/wiki/law-of-demeter/)
+- [[클린코드] 6장 객체와 자료구조](https://namget.tistory.com/entry/%ED%81%B4%EB%A6%B0%EC%BD%94%EB%93%9C-6%EC%9E%A5-%EA%B0%9D%EC%B2%B4%EC%99%80-%EC%9E%90%EB%A3%8C%EA%B5%AC%EC%A1%B0)
+
diff --git "a/\354\235\274\352\270\211 \354\273\254\353\240\211\354\205\230.md" "b/\354\235\274\352\270\211 \354\273\254\353\240\211\354\205\230.md"
new file mode 100644
index 00000000..f03af602
--- /dev/null
+++ "b/\354\235\274\352\270\211 \354\273\254\353\240\211\354\205\230.md"
@@ -0,0 +1,275 @@
+# 일급 콜렉션
+> Collection을 Wrapping하면서, Wrapping한 Collection 외 다른 멤버 변수가 없는 상태를 일급 컬렉션이라 한다.
+
+먼저 ***Collection을 Wrapping한다***의 의미는 아래 코드를
+```java
+public class Person {
+ private String name;
+ private List cars;
+ // ...
+}
+
+public class Car {
+ private String name;
+ private String oil;
+ // ...
+}
+```
+다음과 같이 바꾸는 것을 말한다.
+```java
+public class Person {
+ private String name;
+ private Cars cars;
+ // ...
+}
+
+// List cars를 Wrapping
+// 일급 컬렉션
+public class Cars {
+ // 멤버변수가 하나 밖에 없다!!
+ private List cars;
+ // ...
+}
+
+public class Car {
+ private String name;
+ private String oil;
+ // ...
+}
+```
+위의 코드에서 봤듯이 일급 컬렉션은 그(List\ cars) 외 다른 멤버 변수가 없다.
+
+## 사용 이유
+GS편의점에 아이스크림을 팔고 있다.
+```java
+// GSConvenienceStore.class
+public class GSConvenienceStore {
+ // 편의점에는 여러 개의 아이스크림을 팔고 있을 것이다.
+ private List iceCreams;
+
+ public GSConvenienceStore(List iceCreams) {
+ this.iceCreams = iceCreams;
+ }
+ ...
+}
+
+// IceCream.class
+public class IceCream {
+ private String name;
+ ...
+}
+```
+특이하게도 해당 편의점은 아이스크림의 종류를 10가지 이상 넘으면 안 되는 검증이 필요할 것이다.
+```java
+// GSConvenienceStore.class
+public class GSConvenienceStore {
+ private List iceCreams;
+
+ public GSConvenienceStore(List iceCreams) {
+ validateSize(iceCreams)
+ this.iceCreams = iceCreams;
+ }
+
+ private void validateSize(List iceCreams) {
+ if (iceCreams.size() >= 10) {
+ new throw IllegalArgumentException("아이스크림은 10개 이상의 종류를 팔지 않습니다.")
+ }
+ }
+ // ...
+}
+```
+
+여기서 문제는 만약 아이스크림뿐만 아니라 과자, 라면 등 여러가지가 있다고 가정하였을 때
+- 모든 검증을 ***GSConvenienceStore class***에서 할 것인가?
+- 만약 ***CUConvenienceStore class***에서도 동일한 것을 판다면 ***GSConvenienceStore class***에서 했던 검증을 또 사용할 것인가?
+
+List iceCreams의 원소 중에서 하나를 ***find***하는 메서드를 만든다고 가정해보자.
+- ***GSConvenienceStore class***와 ***CUConvenienceStore class*** 같은 메서드(find)를 두번 구현할 것인가?
+
+```java
+// GSConvenienceStore.class
+public class GSConvenienceStore {
+ private List iceCreams;
+ // ...
+ public IceCream find(String name) {
+ return iceCreams.stream()
+ .filter(iceCream::isSameName)
+ .findFirst()
+ .orElseThrow(RuntimeException::new)
+ }
+ // ...
+}
+
+// CUConvenienceStore.class
+public class CUConvenienceStore {
+ private List iceCreams;
+ // ...
+ public IceCream find(String name) {
+ return iceCreams.stream()
+ .filter(iceCream::isSameName)
+ .findFirst()
+ .orElseThrow(RuntimeException::new)
+ }
+ // ...
+}
+```
+이럴 경우 편의점 ***class의 역할***이 무거워지고, ***중복코드***가 많아진다.
+이것을 해결해주는 것이 ***일급컬렉션***이다.
+***상태와 행위***를 각각 관리할 수 있다.
+아이스크림을 일급 컬렉션으로 만들어 보았다.
+```java
+// IceCream.class
+public class IceCreams {
+ private List iceCreams;
+
+ public IceCreams(List iceCreams) {
+ validateSize(iceCreams)
+ this.iceCreams = iceCreams
+ }
+
+ private void validateSize(List iceCreams) {
+ if (iceCreams.size() >= 10) {
+ new throw IllegalArgumentException("아이스크림은 10개 이상의 종류를 팔지않습니다.")
+ }
+ }
+
+ public IceCream find(String name) {
+ return iceCreams.stream()
+ .filter(iceCream::isSameName)
+ .findFirst()
+ .orElseThrow(RuntimeException::new)
+ }
+ // ...
+}
+```
+그렇다면 편의점 class는 어떻게 달라졌을까?
+```java
+// GSConvenienceStore.class
+public class GSConvenienceStore {
+ private IceCreams iceCreams;
+
+ public GSConvenienceStore(IceCreams iceCreams) {
+ this.iceCreams = iceCreams;
+ }
+
+ public IceCream find(String name) {
+ return iceCreams.find(name);
+ }
+ // ...
+}
+
+// CUConvenienceStore.class
+public class CUConvenienceStore {
+ private IceCreams iceCreams;
+
+ public CUConvenienceStore(IceCreams iceCreams) {
+ this.iceCreams = iceCreams;
+ }
+
+ public IceCream find(String name) {
+ return iceCreams.find(name);
+ }
+ // ...
+}
+```
+이로써 과자랑 라면 등이 생겨도 과자의 일급 컬렉션과 라면의 일급 컬렉션이 해줄 것이다.
+그리고 편의점 class가 했던 역할을 아이스크림, 과자, 라면 등 각각에게 위임하여 상태와 로직을 관리할 것이다.
+
+정리하자면 ***일급 컬렉션***을 사용하면 ***상태와 로직을 따로 관리***할 수 있기 때문에 로직이 사용되는 ***클래스의 부담***을 줄일 수 있고, ***중복 코드***를 줄일 수 있다.
+
+## 불변성을 보장할 필요가 없는 이유
+밑의 코드와 같이 setter를 구현하지 않으면 불변 컬렉션이 된다는 글을 많이 보았을 것이다.
+```java
+public class Lotto {
+ private final List lotto;
+ // ...
+ public List getLotto() {
+ return lotto;
+ }
+}
+```
+하지만 setter를 사용하지 않더라도 Lotto 안에 있는 lotto 변수에 변화를 줄 수 있다.
+```java
+public class Lotto {
+ private final List lotto;
+
+ public Lotto(List lotto) {
+ this.lotto = lotto;
+ }
+
+ public List getLotto() {
+ return lotto;
+ }
+}
+
+public class LottoNumber {
+ private final int lottoNumber;
+
+ public LottoNumber(int lottoNumber) {
+ this.lottoNumber = lottoNumber;
+ }
+
+ // toString()은 로그를 찍기 위함이다.
+ @Override
+ public String toString() {
+ return "LottoNumber{" +
+ "lottoNumber=" + lottoNumber +
+ '}';
+ }
+}
+```
+위와 같은 코드가 있다고 가정하였을 때,
+```java
+@Test
+public void lotto_변화_테스트() {
+ List lottoNumbers = new ArrayList<>();
+ lottoNumbers.add(new LottoNumber(1));
+ Lotto lotto = new Lotto(lottoNumbers);
+ lottoNumbers.add(new LottoNumber(2));
+}
+```
+이러한 상황에서 lotto를 get하였을 때 ```[LottoNumber{lottoNumber=1}, LottoNumber{lottoNumber=2}]``` 이러한 값을 가지고 있는 것을 알 수 있다.
+***lottoNumbers***와 ***lotto class의 멤버변수***와 주소값이 같기 때문에 영향을 받는다.
+Lotto class의 맴버변수인 lotto가 파라미터로 받은 lottoNumbers의 영향을 받지 않기 위해서는 다음과 같이 수정하면 된다.
+```java
+public class Lotto {
+ private final List lotto;
+
+ public Lotto(List lotto) {
+ this.lotto = new ArrayList<>(lotto);
+ }
+
+ public List getLotto() {
+ return lotto;
+ }
+}
+```
+이렇게 수정하면 멤버변수에 저장되는 주소값을 재할당하기 때문에 영향을 받지 않는다.
+```java
+@Test
+public void lotto_변화_테스트() {
+ List lottoNumbers = new ArrayList<>();
+ lottoNumbers.add(new LottoNumber(1));
+ Lotto lotto = new Lotto(lottoNumbers);
+ lotto.getLotto().add(new LottoNumber(2));
+}
+```
+하지만 이러한 상황에도 위와 같은 결과 값이 나온다.
+이를 해결하는 방법으로 ***unmodifiableList*** 사용한다.
+```java
+public class Lotto {
+ private final List lotto;
+
+ public Lotto(List lotto) {
+ this.lotto = new ArrayList<>(lotto);
+ }
+
+ public List getLotto() {
+ return Collections.unmodifiableList(lotto);
+ }
+}
+```
+***unmodifiableList***를 사용하면 lotto는 불변이 되고, getter로 return해서 사용될 때 변경이 불가능하다.
+
+## Reference
+- [일급 컬렉션](https://velog.io/@tigger/%EC%9D%BC%EA%B8%89-%EC%BB%AC%EB%A0%89%EC%85%98)
\ No newline at end of file