Compare commits
26 Commits
learn-with
...
solid-desi
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a279d6b481 | ||
|
|
beab021cfb | ||
|
|
86cd9824de | ||
|
|
c93ab002c0 | ||
|
|
6b2c3eced2 | ||
|
|
21937f8dc8 | ||
|
|
4b2d8a9669 | ||
|
|
826c70834d | ||
|
|
27311dc1eb | ||
|
|
588b4c41b5 | ||
|
|
b8853e5a30 | ||
|
|
d05562f532 | ||
|
|
f0a16b9096 | ||
|
|
2ea7227b04 | ||
|
|
2dd284d300 | ||
|
|
ddc3f84a5d | ||
|
|
e9b76a0024 | ||
|
|
f9af46e64a | ||
|
|
8ac2fd7eff | ||
|
|
ec46451143 | ||
|
|
8a0df3a322 | ||
|
|
6aa4913294 | ||
|
|
e05abb53f1 | ||
|
|
c659243c32 | ||
|
|
a52e454a26 | ||
|
|
c5e5a3047b |
37
놀이터(예제 코드 작성)/graphql-kotlin/.gitignore
vendored
Normal file
37
놀이터(예제 코드 작성)/graphql-kotlin/.gitignore
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
HELP.md
|
||||
.gradle
|
||||
build/
|
||||
!gradle/wrapper/gradle-wrapper.jar
|
||||
!**/src/main/**/build/
|
||||
!**/src/test/**/build/
|
||||
|
||||
### STS ###
|
||||
.apt_generated
|
||||
.classpath
|
||||
.factorypath
|
||||
.project
|
||||
.settings
|
||||
.springBeans
|
||||
.sts4-cache
|
||||
bin/
|
||||
!**/src/main/**/bin/
|
||||
!**/src/test/**/bin/
|
||||
|
||||
### IntelliJ IDEA ###
|
||||
.idea
|
||||
*.iws
|
||||
*.iml
|
||||
*.ipr
|
||||
out/
|
||||
!**/src/main/**/out/
|
||||
!**/src/test/**/out/
|
||||
|
||||
### NetBeans ###
|
||||
/nbproject/private/
|
||||
/nbbuild/
|
||||
/dist/
|
||||
/nbdist/
|
||||
/.nb-gradle/
|
||||
|
||||
### VS Code ###
|
||||
.vscode/
|
||||
14
놀이터(예제 코드 작성)/graphql-kotlin/README.md
Normal file
14
놀이터(예제 코드 작성)/graphql-kotlin/README.md
Normal file
@@ -0,0 +1,14 @@
|
||||
# GraphQL Kotlin
|
||||
|
||||
- [MVN Repository - GraphQL Kotlin Spring Server](https://mvnrepository.com/artifact/com.expediagroup/graphql-kotlin-spring-server)
|
||||
|
||||
## Spring Server
|
||||
|
||||
- [Getting Started](https://opensource.expediagroup.com/graphql-kotlin/docs/)
|
||||
- [Spring Server Overview](https://opensource.expediagroup.com/graphql-kotlin/docs/server/spring-server/spring-overview/)
|
||||
- [Writing Schemas with Spring](https://opensource.expediagroup.com/graphql-kotlin/docs/server/spring-server/spring-schema)
|
||||
- [Generating GraphQL Context](https://opensource.expediagroup.com/graphql-kotlin/docs/server/spring-server/spring-graphql-context)
|
||||
- [HTTP Request and Response](https://opensource.expediagroup.com/graphql-kotlin/docs/server/spring-server/spring-http-request-response)
|
||||
- [Automatically Created Beans](https://opensource.expediagroup.com/graphql-kotlin/docs/server/spring-server/spring-beans)
|
||||
- [Configuration Properties](https://opensource.expediagroup.com/graphql-kotlin/docs/server/spring-server/spring-properties)
|
||||
- [Subscriptions](https://opensource.expediagroup.com/graphql-kotlin/docs/server/spring-server/spring-subscriptions)
|
||||
41
놀이터(예제 코드 작성)/graphql-kotlin/build.gradle.kts
Normal file
41
놀이터(예제 코드 작성)/graphql-kotlin/build.gradle.kts
Normal file
@@ -0,0 +1,41 @@
|
||||
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
|
||||
|
||||
plugins {
|
||||
id("org.springframework.boot") version "2.7.2"
|
||||
id("io.spring.dependency-management") version "1.0.12.RELEASE"
|
||||
kotlin("jvm") version "1.6.21"
|
||||
kotlin("plugin.spring") version "1.6.21"
|
||||
}
|
||||
|
||||
group = "com.banjjoknim"
|
||||
version = "0.0.1-SNAPSHOT"
|
||||
java.sourceCompatibility = JavaVersion.VERSION_11
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation("org.springframework.boot:spring-boot-starter-webflux")
|
||||
implementation("com.fasterxml.jackson.module:jackson-module-kotlin")
|
||||
implementation("io.projectreactor.kotlin:reactor-kotlin-extensions")
|
||||
implementation("org.jetbrains.kotlin:kotlin-reflect")
|
||||
implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
|
||||
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-reactor")
|
||||
testImplementation("org.springframework.boot:spring-boot-starter-test")
|
||||
testImplementation("io.projectreactor:reactor-test")
|
||||
|
||||
implementation("com.expediagroup", "graphql-kotlin-spring-server", "6.0.0")
|
||||
implementation("com.graphql-java:graphql-java-extended-scalars:18.1")
|
||||
}
|
||||
|
||||
tasks.withType<KotlinCompile> {
|
||||
kotlinOptions {
|
||||
freeCompilerArgs = listOf("-Xjsr305=strict")
|
||||
jvmTarget = "11"
|
||||
}
|
||||
}
|
||||
|
||||
tasks.withType<Test> {
|
||||
useJUnitPlatform()
|
||||
}
|
||||
BIN
놀이터(예제 코드 작성)/graphql-kotlin/gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
BIN
놀이터(예제 코드 작성)/graphql-kotlin/gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
Binary file not shown.
5
놀이터(예제 코드 작성)/graphql-kotlin/gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
5
놀이터(예제 코드 작성)/graphql-kotlin/gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-bin.zip
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
240
놀이터(예제 코드 작성)/graphql-kotlin/gradlew
vendored
Executable file
240
놀이터(예제 코드 작성)/graphql-kotlin/gradlew
vendored
Executable file
@@ -0,0 +1,240 @@
|
||||
#!/bin/sh
|
||||
|
||||
#
|
||||
# Copyright © 2015-2021 the original 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 POSIX generated by Gradle.
|
||||
#
|
||||
# Important for running:
|
||||
#
|
||||
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
|
||||
# noncompliant, but you have some other compliant shell such as ksh or
|
||||
# bash, then to run this script, type that shell name before the whole
|
||||
# command line, like:
|
||||
#
|
||||
# ksh Gradle
|
||||
#
|
||||
# Busybox and similar reduced shells will NOT work, because this script
|
||||
# requires all of these POSIX shell features:
|
||||
# * functions;
|
||||
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
|
||||
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
|
||||
# * compound commands having a testable exit status, especially «case»;
|
||||
# * various built-in commands including «command», «set», and «ulimit».
|
||||
#
|
||||
# Important for patching:
|
||||
#
|
||||
# (2) This script targets any POSIX shell, so it avoids extensions provided
|
||||
# by Bash, Ksh, etc; in particular arrays are avoided.
|
||||
#
|
||||
# The "traditional" practice of packing multiple parameters into a
|
||||
# space-separated string is a well documented source of bugs and security
|
||||
# problems, so this is (mostly) avoided, by progressively accumulating
|
||||
# options in "$@", and eventually passing that to Java.
|
||||
#
|
||||
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
|
||||
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
|
||||
# see the in-line comments for details.
|
||||
#
|
||||
# There are tweaks for specific operating systems such as AIX, CygWin,
|
||||
# Darwin, MinGW, and NonStop.
|
||||
#
|
||||
# (3) This script is generated from the Groovy template
|
||||
# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
||||
# within the Gradle project.
|
||||
#
|
||||
# You can find Gradle at https://github.com/gradle/gradle/.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
# Attempt to set APP_HOME
|
||||
|
||||
# Resolve links: $0 may be a link
|
||||
app_path=$0
|
||||
|
||||
# Need this for daisy-chained symlinks.
|
||||
while
|
||||
APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
|
||||
[ -h "$app_path" ]
|
||||
do
|
||||
ls=$( ls -ld "$app_path" )
|
||||
link=${ls#*' -> '}
|
||||
case $link in #(
|
||||
/*) app_path=$link ;; #(
|
||||
*) app_path=$APP_HOME$link ;;
|
||||
esac
|
||||
done
|
||||
|
||||
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
|
||||
|
||||
APP_NAME="Gradle"
|
||||
APP_BASE_NAME=${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 "$*"
|
||||
} >&2
|
||||
|
||||
die () {
|
||||
echo
|
||||
echo "$*"
|
||||
echo
|
||||
exit 1
|
||||
} >&2
|
||||
|
||||
# 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 ;; #(
|
||||
MSYS* | 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" && ! "$darwin" && ! "$nonstop" ; then
|
||||
case $MAX_FD in #(
|
||||
max*)
|
||||
MAX_FD=$( ulimit -H -n ) ||
|
||||
warn "Could not query maximum file descriptor limit"
|
||||
esac
|
||||
case $MAX_FD in #(
|
||||
'' | soft) :;; #(
|
||||
*)
|
||||
ulimit -n "$MAX_FD" ||
|
||||
warn "Could not set maximum file descriptor limit to $MAX_FD"
|
||||
esac
|
||||
fi
|
||||
|
||||
# Collect all arguments for the java command, stacking in reverse order:
|
||||
# * args from the command line
|
||||
# * the main class name
|
||||
# * -classpath
|
||||
# * -D...appname settings
|
||||
# * --module-path (only if needed)
|
||||
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
|
||||
|
||||
# For Cygwin or MSYS, switch paths to Windows format before running java
|
||||
if "$cygwin" || "$msys" ; then
|
||||
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
|
||||
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
|
||||
|
||||
JAVACMD=$( cygpath --unix "$JAVACMD" )
|
||||
|
||||
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||
for arg do
|
||||
if
|
||||
case $arg in #(
|
||||
-*) false ;; # don't mess with options #(
|
||||
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
|
||||
[ -e "$t" ] ;; #(
|
||||
*) false ;;
|
||||
esac
|
||||
then
|
||||
arg=$( cygpath --path --ignore --mixed "$arg" )
|
||||
fi
|
||||
# Roll the args list around exactly as many times as the number of
|
||||
# args, so each arg winds up back in the position where it started, but
|
||||
# possibly modified.
|
||||
#
|
||||
# NB: a `for` loop captures its iteration list before it begins, so
|
||||
# changing the positional parameters here affects neither the number of
|
||||
# iterations, nor the values presented in `arg`.
|
||||
shift # remove old arg
|
||||
set -- "$@" "$arg" # push replacement arg
|
||||
done
|
||||
fi
|
||||
|
||||
# Collect all arguments for the java command;
|
||||
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
|
||||
# shell script including quotes and variable substitutions, so put them in
|
||||
# double quotes to make sure that they get re-expanded; and
|
||||
# * put everything else in single quotes, so that it's not re-expanded.
|
||||
|
||||
set -- \
|
||||
"-Dorg.gradle.appname=$APP_BASE_NAME" \
|
||||
-classpath "$CLASSPATH" \
|
||||
org.gradle.wrapper.GradleWrapperMain \
|
||||
"$@"
|
||||
|
||||
# Stop when "xargs" is not available.
|
||||
if ! command -v xargs >/dev/null 2>&1
|
||||
then
|
||||
die "xargs is not available"
|
||||
fi
|
||||
|
||||
# Use "xargs" to parse quoted args.
|
||||
#
|
||||
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
|
||||
#
|
||||
# In Bash we could simply go:
|
||||
#
|
||||
# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
|
||||
# set -- "${ARGS[@]}" "$@"
|
||||
#
|
||||
# but POSIX shell has neither arrays nor command substitution, so instead we
|
||||
# post-process each arg (as a line of input to sed) to backslash-escape any
|
||||
# character that might be a shell metacharacter, then use eval to reverse
|
||||
# that process (while maintaining the separation between arguments), and wrap
|
||||
# the whole thing up as a single "set" statement.
|
||||
#
|
||||
# This will of course break if any of these variables contains a newline or
|
||||
# an unmatched quote.
|
||||
#
|
||||
|
||||
eval "set -- $(
|
||||
printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
|
||||
xargs -n1 |
|
||||
sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
|
||||
tr '\n' ' '
|
||||
)" '"$@"'
|
||||
|
||||
exec "$JAVACMD" "$@"
|
||||
91
놀이터(예제 코드 작성)/graphql-kotlin/gradlew.bat
vendored
Normal file
91
놀이터(예제 코드 작성)/graphql-kotlin/gradlew.bat
vendored
Normal file
@@ -0,0 +1,91 @@
|
||||
@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% equ 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% equ 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!
|
||||
set EXIT_CODE=%ERRORLEVEL%
|
||||
if %EXIT_CODE% equ 0 set EXIT_CODE=1
|
||||
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
|
||||
exit /b %EXIT_CODE%
|
||||
|
||||
:mainEnd
|
||||
if "%OS%"=="Windows_NT" endlocal
|
||||
|
||||
:omega
|
||||
1
놀이터(예제 코드 작성)/graphql-kotlin/settings.gradle.kts
Normal file
1
놀이터(예제 코드 작성)/graphql-kotlin/settings.gradle.kts
Normal file
@@ -0,0 +1 @@
|
||||
rootProject.name = "graphql-kotlin"
|
||||
@@ -0,0 +1,31 @@
|
||||
package com.banjjoknim.graphqlkotlin
|
||||
|
||||
import com.expediagroup.graphql.server.spring.execution.DefaultSpringGraphQLContextFactory
|
||||
import org.springframework.stereotype.Component
|
||||
import org.springframework.web.reactive.function.server.ServerRequest
|
||||
|
||||
/**
|
||||
* # [Generating GraphQL Context](https://opensource.expediagroup.com/graphql-kotlin/docs/server/spring-server/spring-graphql-context)
|
||||
*
|
||||
* graphql-kotlin-spring-server provides a Spring specific implementation of GraphQLContextFactory and the context.
|
||||
*
|
||||
* SpringGraphQLContext (deprecated) - Implements the Spring ServerRequest and federation tracing HTTPRequestHeaders
|
||||
*
|
||||
* SpringGraphQLContextFactory - Generates GraphQL context map with federated tracing information per request
|
||||
*
|
||||
* If you are using graphql-kotlin-spring-server, you should extend DefaultSpringGraphQLContextFactory to automatically support federated tracing.
|
||||
*
|
||||
* Once your application is configured to build your custom GraphQL context map, you can then access it through a data fetching environment argument.
|
||||
*
|
||||
* While executing the query, data fetching environment will be automatically injected to the function input arguments.
|
||||
*
|
||||
* This argument will not appear in the GraphQL schema.
|
||||
*/
|
||||
@Component
|
||||
class GraphQLContextFactory : DefaultSpringGraphQLContextFactory() {
|
||||
override suspend fun generateContextMap(request: ServerRequest): Map<*, Any> {
|
||||
return super.generateContextMap(request) + mapOf(
|
||||
"myCustomValue" to (request.headers().firstHeader("MyHeader") ?: "defaultContext")
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package com.banjjoknim.graphqlkotlin
|
||||
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication
|
||||
import org.springframework.boot.runApplication
|
||||
|
||||
@SpringBootApplication
|
||||
class GraphqlKotlinApplication
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
runApplication<GraphqlKotlinApplication>(*args)
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
package com.banjjoknim.graphqlkotlin.configuration
|
||||
|
||||
import com.expediagroup.graphql.generator.hooks.SchemaGeneratorHooks
|
||||
import graphql.language.StringValue
|
||||
import graphql.scalars.ExtendedScalars
|
||||
import graphql.scalars.util.Kit.typeName
|
||||
import graphql.schema.Coercing
|
||||
import graphql.schema.CoercingParseLiteralException
|
||||
import graphql.schema.CoercingParseValueException
|
||||
import graphql.schema.CoercingSerializeException
|
||||
import graphql.schema.GraphQLScalarType
|
||||
import graphql.schema.GraphQLType
|
||||
import org.springframework.context.annotation.Bean
|
||||
import org.springframework.context.annotation.Configuration
|
||||
import java.time.LocalDate
|
||||
import java.time.LocalDateTime
|
||||
import java.time.LocalTime
|
||||
import java.time.format.DateTimeFormatter
|
||||
import kotlin.reflect.KClass
|
||||
import kotlin.reflect.KType
|
||||
|
||||
/**
|
||||
* - [Extended Scalars for graphql-java](https://github.com/graphql-java/graphql-java-extended-scalars)
|
||||
*
|
||||
* - [Cannot use java.util.Date](https://github.com/ExpediaGroup/graphql-kotlin/discussions/1198)
|
||||
*
|
||||
* - [GraphQL Kotlin - Extended Scalars](https://opensource.expediagroup.com/graphql-kotlin/docs/schema-generator/writing-schemas/scalars/#common-issues)
|
||||
*
|
||||
* - [GraphQL Kotlin - Generator Configuration & Hooks](https://opensource.expediagroup.com/graphql-kotlin/docs/schema-generator/customizing-schemas/generator-config)
|
||||
*/
|
||||
@Configuration
|
||||
class ExtendedScalarsConfiguration {
|
||||
/**
|
||||
* 아래와 같이 Bean으로 Hook을 등록해주면 Schema Generator가 Schema를 생성할 때 이 Bean에 정의된 Hook을 이용해서 Schema를 만든다.
|
||||
*/
|
||||
@Bean
|
||||
fun extendedScalarsHooks(): SchemaGeneratorHooks {
|
||||
return object : SchemaGeneratorHooks {
|
||||
override fun willGenerateGraphQLType(type: KType): GraphQLType? {
|
||||
return when (type.classifier as? KClass<*>) {
|
||||
Long::class -> ExtendedScalars.GraphQLLong
|
||||
LocalDateTime::class -> localDateTimeScalar()
|
||||
LocalTime::class -> ExtendedScalars.LocalTime
|
||||
LocalDate::class -> ExtendedScalars.Date
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Bean으로 ScalarType을 등록해주지 않으면 어플리케이션 실행시 스키마를 구성하는 단계(스키마에 포함될 타입중에서 LocalDateTime 이 포함되어 있는 경우)에서 아래와 같은 예외가 발생한다.
|
||||
*
|
||||
* ```
|
||||
* graphql.AssertException: All types within a GraphQL schema must have unique names. No two provided types may have the same name.
|
||||
* No provided type may have a name which conflicts with any built in types (including Scalar and Introspection types). You have redefined the type 'LocalDateTime' from being a 'GraphQLScalarType' to a 'GraphQLScalarType'
|
||||
* ```
|
||||
*
|
||||
* @see graphql.scalars.datetime.DateTimeScalar
|
||||
*/
|
||||
@Bean
|
||||
fun localDateTimeScalar(): GraphQLScalarType? {
|
||||
val coercing = object : Coercing<LocalDateTime, String> {
|
||||
override fun serialize(dataFetcherResult: Any): String {
|
||||
return when (dataFetcherResult) {
|
||||
is LocalDateTime -> DateTimeFormatter.ISO_LOCAL_DATE_TIME.format(
|
||||
LocalDateTime.from(dataFetcherResult)
|
||||
)
|
||||
is String -> DateTimeFormatter.ISO_LOCAL_DATE_TIME.format(
|
||||
LocalDateTime.parse(dataFetcherResult)
|
||||
)
|
||||
else -> throw CoercingSerializeException(
|
||||
"Expected something we can convert to 'java.time.LocalDateTime' but was '" +
|
||||
"${typeName(dataFetcherResult)}'."
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override fun parseValue(input: Any): LocalDateTime {
|
||||
return when (input) {
|
||||
is LocalDateTime -> input
|
||||
is String -> LocalDateTime.parse(
|
||||
input.toString(),
|
||||
DateTimeFormatter.ISO_LOCAL_DATE_TIME
|
||||
)
|
||||
else -> throw CoercingParseValueException(
|
||||
"Expected a 'String' but was '" + "${typeName(input)}'."
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override fun parseLiteral(input: Any): LocalDateTime {
|
||||
if (input !is StringValue) {
|
||||
throw CoercingParseLiteralException(
|
||||
"Expected AST type 'StringValue' but was '${typeName(input)}'."
|
||||
)
|
||||
}
|
||||
return LocalDateTime.parse(input.toString(), DateTimeFormatter.ISO_LOCAL_DATE_TIME)
|
||||
}
|
||||
}
|
||||
return GraphQLScalarType.newScalar()
|
||||
.name("LocalDateTime")
|
||||
.description("Custom LocalDateTime Scalar")
|
||||
.coercing(coercing)
|
||||
.build()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package com.banjjoknim.graphqlkotlin.person
|
||||
|
||||
import com.expediagroup.graphql.generator.annotations.GraphQLDescription
|
||||
import com.expediagroup.graphql.server.Schema
|
||||
import org.springframework.stereotype.Component
|
||||
|
||||
/**
|
||||
* In order to expose your schema directives, queries, mutations, and subscriptions in the GraphQL schema create beans that implement the corresponding marker interface and they will be automatically picked up by graphql-kotlin-spring-server auto-configuration library.
|
||||
*/
|
||||
@GraphQLDescription("Sample GraphQL Schema")
|
||||
@Component
|
||||
class GraphQLSchema : Schema
|
||||
@@ -0,0 +1,9 @@
|
||||
package com.banjjoknim.graphqlkotlin.person
|
||||
|
||||
import java.time.LocalDateTime
|
||||
|
||||
data class Person(
|
||||
var name: String,
|
||||
var age: Long? = 0L,
|
||||
var birthDate: LocalDateTime = LocalDateTime.now()
|
||||
)
|
||||
@@ -0,0 +1,14 @@
|
||||
package com.banjjoknim.graphqlkotlin.person
|
||||
|
||||
import com.expediagroup.graphql.server.operations.Mutation
|
||||
import org.springframework.stereotype.Component
|
||||
|
||||
@Component
|
||||
class PersonMutation : Mutation {
|
||||
|
||||
fun changeName(person: Person, newName: String): Person {
|
||||
return person.apply {
|
||||
name = newName
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
package com.banjjoknim.graphqlkotlin.person
|
||||
|
||||
import com.expediagroup.graphql.generator.annotations.GraphQLDescription
|
||||
import com.expediagroup.graphql.generator.annotations.GraphQLIgnore
|
||||
import com.expediagroup.graphql.generator.annotations.GraphQLName
|
||||
import com.expediagroup.graphql.server.operations.Query
|
||||
import org.springframework.beans.factory.annotation.Autowired
|
||||
import org.springframework.stereotype.Component
|
||||
import kotlin.random.Random
|
||||
|
||||
@Component
|
||||
class PersonQuery(
|
||||
/**
|
||||
* # Spring Beans
|
||||
*
|
||||
* Since the top level objects are Spring components, Spring will automatically autowire dependent beans as normal.
|
||||
*
|
||||
* Refer to [Spring Documentation](https://docs.spring.io/spring-framework/docs/current/reference/html/) for details.
|
||||
*/
|
||||
private val personRepository: PersonRepository
|
||||
) : Query {
|
||||
|
||||
@GraphQLDescription("get Person Instance")
|
||||
fun getPerson(name: String): Person = Person(name)
|
||||
|
||||
/**
|
||||
* # Spring Beans in Arguments
|
||||
*
|
||||
* graphql-kotlin-spring-server provides Spring-aware data fetcher that automatically autowires Spring beans when they are specified as function arguments.
|
||||
*
|
||||
* `@Autowired` arguments should be explicitly excluded from the GraphQL schema by also specifying @GraphQLIgnore.
|
||||
*
|
||||
* ```
|
||||
* NOTE
|
||||
* If you are using custom data fetcher make sure that you extend SpringDataFetcher instead of the base FunctionDataFetcher to keep this functionallity.
|
||||
* ```
|
||||
*/
|
||||
@GraphQLDescription("find Person Instance")
|
||||
fun findPerson(@GraphQLIgnore @Autowired personRepository: PersonRepository, name: String): Person? {
|
||||
return personRepository.findPerson(name)
|
||||
}
|
||||
|
||||
@GraphQLDescription("@GraphQLName example")
|
||||
@GraphQLName("somePerson")
|
||||
fun randomPerson(name: String): Person = Person(name = name, age = Random.nextLong())
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
package com.banjjoknim.graphqlkotlin.person
|
||||
|
||||
interface PersonRepository {
|
||||
|
||||
fun findPerson(name: String): Person?
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package com.banjjoknim.graphqlkotlin.person
|
||||
|
||||
import org.springframework.stereotype.Repository
|
||||
|
||||
@Repository
|
||||
class PersonRepositoryImpl : PersonRepository {
|
||||
|
||||
companion object {
|
||||
private val people = mapOf(
|
||||
"banjjoknim" to Person("banjjoknim"),
|
||||
"colt" to Person("colt")
|
||||
)
|
||||
}
|
||||
|
||||
override fun findPerson(name: String): Person? {
|
||||
return people[name]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package com.banjjoknim.graphqlkotlin.person
|
||||
|
||||
import com.expediagroup.graphql.server.operations.Subscription
|
||||
import org.reactivestreams.Publisher
|
||||
import org.springframework.stereotype.Component
|
||||
|
||||
@Component
|
||||
class PersonSubscription : Subscription {
|
||||
|
||||
fun changeName(person: Person, newName: String): Publisher<Person> {
|
||||
return Publisher { println("change name published") }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
# At a minimum, in order for graphql-kotlin-spring-server to automatically configure your GraphQL web server
|
||||
#
|
||||
# you need to specify a list of supported packages that can be scanned for exposing your schema objects through reflections.
|
||||
#
|
||||
# You can do this through the spring application config or by overriding the SchemaGeneratorConfig bean.
|
||||
#
|
||||
# See customization below.
|
||||
graphql:
|
||||
packages:
|
||||
- "com.banjjoknim.graphqlkotlin"
|
||||
@@ -0,0 +1,13 @@
|
||||
package com.banjjoknim.graphqlkotlin
|
||||
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.springframework.boot.test.context.SpringBootTest
|
||||
|
||||
@SpringBootTest
|
||||
class GraphqlKotlinApplicationTests {
|
||||
|
||||
@Test
|
||||
fun contextLoads() {
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
package com.banjjoknim.graphqlkotlin.person
|
||||
|
||||
import org.json.JSONObject
|
||||
import org.junit.jupiter.api.DisplayName
|
||||
import org.junit.jupiter.api.Nested
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.springframework.beans.factory.annotation.Autowired
|
||||
import org.springframework.boot.test.context.SpringBootTest
|
||||
import org.springframework.http.MediaType
|
||||
import org.springframework.test.web.reactive.server.WebTestClient
|
||||
|
||||
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
|
||||
class PersonQueryTest(
|
||||
@Autowired
|
||||
private val webTestClient: WebTestClient
|
||||
) {
|
||||
|
||||
@DisplayName("getPerson Query Tests")
|
||||
@Nested
|
||||
inner class GetPersonTestCases {
|
||||
@Test
|
||||
fun `인자로 넣은 이름을 가진 Person 객체를 얻는다`() {
|
||||
val query = """
|
||||
query {
|
||||
getPerson(name: "colt") {
|
||||
name
|
||||
}
|
||||
}
|
||||
""".trimIndent()
|
||||
val json = JSONObject().put("query", query).toString()
|
||||
webTestClient.post()
|
||||
.uri("/graphql")
|
||||
.accept(MediaType.APPLICATION_JSON)
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.bodyValue(json)
|
||||
.exchange()
|
||||
.expectBody().json("""{"data":{"getPerson":{"name":"colt"}}}""")
|
||||
.consumeWith {
|
||||
// assertThat(something...)
|
||||
println(it.responseHeaders)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@DisplayName("findPerson Query Tests")
|
||||
@Nested
|
||||
inner class FindPersonTestCases {
|
||||
|
||||
@Test
|
||||
fun `메모리에 존재하는 Person 객체 중에서 인자와 이름이 일치하는 객체를 얻는다`() {
|
||||
val query = """
|
||||
|
||||
query {
|
||||
findPerson(name: "banjjoknim") {
|
||||
name
|
||||
}
|
||||
}
|
||||
|
||||
""".trimIndent()
|
||||
val json = JSONObject().put("query", query).toString()
|
||||
webTestClient.post()
|
||||
.uri("/graphql")
|
||||
.accept(MediaType.APPLICATION_JSON)
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.bodyValue(json)
|
||||
.exchange()
|
||||
.expectBody().json("""{"data":{"findPerson":{"name":"banjjoknim"}}}""")
|
||||
.consumeWith {
|
||||
// assertThat(something...)
|
||||
println(it.responseHeaders)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `인자와 이름이 일치하는 객체가 메모리에 없으면 null을 얻는다`() {
|
||||
val query = """
|
||||
|
||||
query {
|
||||
findPerson(name: "invalid") {
|
||||
name
|
||||
}
|
||||
}
|
||||
|
||||
""".trimIndent()
|
||||
val json = JSONObject().put("query", query).toString()
|
||||
webTestClient.post()
|
||||
.uri("/graphql")
|
||||
.accept(MediaType.APPLICATION_JSON)
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.bodyValue(json)
|
||||
.exchange()
|
||||
.expectBody().json("""{"data":{"findPerson":null}}""")
|
||||
.consumeWith {
|
||||
// assertThat(something...)
|
||||
println(it.responseHeaders)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
37
놀이터(예제 코드 작성)/solid-design-pattern-sample/.gitignore
vendored
Normal file
37
놀이터(예제 코드 작성)/solid-design-pattern-sample/.gitignore
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
HELP.md
|
||||
.gradle
|
||||
build/
|
||||
!gradle/wrapper/gradle-wrapper.jar
|
||||
!**/src/main/**/build/
|
||||
!**/src/test/**/build/
|
||||
|
||||
### STS ###
|
||||
.apt_generated
|
||||
.classpath
|
||||
.factorypath
|
||||
.project
|
||||
.settings
|
||||
.springBeans
|
||||
.sts4-cache
|
||||
bin/
|
||||
!**/src/main/**/bin/
|
||||
!**/src/test/**/bin/
|
||||
|
||||
### IntelliJ IDEA ###
|
||||
.idea
|
||||
*.iws
|
||||
*.iml
|
||||
*.ipr
|
||||
out/
|
||||
!**/src/main/**/out/
|
||||
!**/src/test/**/out/
|
||||
|
||||
### NetBeans ###
|
||||
/nbproject/private/
|
||||
/nbbuild/
|
||||
/dist/
|
||||
/nbdist/
|
||||
/.nb-gradle/
|
||||
|
||||
### VS Code ###
|
||||
.vscode/
|
||||
178
놀이터(예제 코드 작성)/solid-design-pattern-sample/README.md
Normal file
178
놀이터(예제 코드 작성)/solid-design-pattern-sample/README.md
Normal file
@@ -0,0 +1,178 @@
|
||||
# SOLID & Design Pattern Sample
|
||||
|
||||
## SOLID
|
||||
|
||||
- SOLID 원칙들은 소프트웨어 작업에서 프로그래머가 소스 코드가 읽기 쉽고 확장하기 쉽게 될 때까지 소프트웨어 소스 코드를 리팩터링하여 코드 냄새를 제거하기 위해 적용할 수 있는 지침이다.
|
||||
- 각 항목별 before & after 를 비교하면서 어떤 차이가 있는지 생각해본다.
|
||||
- before & after 에 새로운, 또는 동일한 규칙(비즈니스 로직, 유효성 검사 등)을 적용해야 한다고 가정하고 변경을 시도해본다.
|
||||
|
||||
### SRP(Single Responsibility Principle)
|
||||
|
||||
- 단일 책임 원칙
|
||||
- 한 클래스는 하나의 책임만 가져야 한다. 즉, 한 클래스가 변경되는 이유는 한 가지여야 한다.
|
||||
|
||||
#### 구현 요구사항
|
||||
|
||||
- 예금주의 이름으로 계좌를 생성할 수 있다.
|
||||
- 계좌에 입금할 수 있다.
|
||||
- 계좌에서 출금할 수 있다.
|
||||
|
||||
### OCP(Open/Closed Principle)
|
||||
|
||||
- 개방-폐쇄 원칙
|
||||
- 소프트웨어 요소는 확장에는 열려 있으나 변경에는 닫혀 있어야 한다.
|
||||
|
||||
#### 구현 요구사항
|
||||
|
||||
- 최초의 결제방식은 현금, 카드 두 가지가 있다.
|
||||
- 쿠폰 결제방식을 추가한다고 가정한다.
|
||||
- 쿠폰으로 결제할 경우 잔고가 차감되지 않는다.
|
||||
|
||||
### LSP(Liskov Substitution Principle)
|
||||
|
||||
- 리스코프 치환 원칙
|
||||
- 프로그램의 객체는 프로그램의 정확성을 깨뜨리지 않으면서 하위 타입의 인스턴스로 바꿀 수 있어야 한다.
|
||||
|
||||
#### 구현 요구사항
|
||||
|
||||
- 좌표를 입력하면 해당 좌표로 이동수단의 위치가 변한다.
|
||||
|
||||
### ISP(Interface Segregation Principle)
|
||||
|
||||
- 인터페이스 분리 원칙
|
||||
- 특정 클라이언트를 위한 인터페이스 여러 개가 범용 인터페이스 하나보다 낫다.
|
||||
|
||||
#### 구현 요구사항
|
||||
|
||||
- 영화 상영관 좌석 현황을 조회할 수 있다.
|
||||
- 영화표 예매를 진행할 수 있다.
|
||||
|
||||
### DIP(Dependency Inversion Principle)
|
||||
|
||||
- 의존 역전 원칙
|
||||
- 프로그래머는 “추상화에 의존해야지, 구체화에 의존하면 안된다.” 의존성 주입은 이 원칙을 따르는 방법 중 하나다.
|
||||
|
||||
#### 구현 요구사항
|
||||
|
||||
- 저장소에서 파일 데이터를 불러올 수 있다.
|
||||
- 하나의 저장소만 사용하며 저장소의 타입은 언제든지 변경될 수 있다.
|
||||
- 각각의 저장소는 각자만의 파일 데이터 조회 요청 인터페이스를 제공한다.
|
||||
- 아마존에서는 파일 이름을 요구한다.
|
||||
- 구글에서는 파일 번호를 요구한다.
|
||||
|
||||
## Design Pattern
|
||||
|
||||
### 전략(Strategy) 패턴
|
||||
|
||||
#### 구현 요구사항
|
||||
|
||||
- 연령대별로 물건의 할인된 금액 계산기를 구현한다.
|
||||
- 아이일 경우 할인율은 15%이다.
|
||||
- 어른일 경우 할인율은 30%이다.
|
||||
|
||||
### 템플릿 메서드(Template Method) 패턴
|
||||
|
||||
#### 구현 요구사항
|
||||
|
||||
- 스포츠 강사를 구현한다.
|
||||
- 모든 강사는 강의가 시작할 때 스트레칭을 한다.
|
||||
- 모든 강사는 강의가 끝날 때 인사한다.
|
||||
- 수영 강사는 강의 중간에 수영 동작을 보여준다.
|
||||
- 축구 강사는 강의 중간에 축구 동작을 보여준다.
|
||||
|
||||
### 상태(State) 패턴
|
||||
|
||||
#### 구현 요구사항
|
||||
|
||||
- 상태별로 다르게 움직이는 게임 캐릭터를 구현한다.
|
||||
- 기본적으로 게임 캐릭터는 정지상태이다.
|
||||
- 정지 상태에서 버튼을 누르면 이동한다.
|
||||
- 이동하는 상태에서 버튼을 누르면 점프한다.
|
||||
- 점프하는 상태에서 버튼을 누르면 착지한 뒤 정지한다.
|
||||
- 게임 캐릭터는 버튼을 누르면 동작하는 상태로 스스로의 상태를 변경한다.
|
||||
|
||||
### 데코레이터(Decorator) 패턴
|
||||
|
||||
#### 구현 요구사항
|
||||
|
||||
- 용사는 검을 가진다.
|
||||
- 용사는 검을 바꿀 수 있다.
|
||||
- 검에는 속성이 부여될 수 있으며, 속성에 따라 공격이 변한다.
|
||||
- 용사가 공격하면 소지한 무기의 공격이 발동된다.
|
||||
|
||||
### 프록시(Proxy) 패턴
|
||||
|
||||
#### 구현 요구사항
|
||||
|
||||
- 지갑의 주인은 지갑에 대해 입금 또는 출금을 진행할 수 있다.
|
||||
- 지갑의 동작은 입금 및 출금만 가능하도록 제한된다.
|
||||
- 지갑에 대해 입금 또는 출금이 이루어질 때 메시지를 출력한다.
|
||||
|
||||
### 어댑터(Adapter) 패턴
|
||||
|
||||
#### 구현 요구사항
|
||||
|
||||
- 발전소는 정해진 요청 규격에 따라 전기를 생산한다.
|
||||
- 가정은 정해진 규격에 따라 전기를 얻는다.
|
||||
- 발전소와 가정에서 사용하는 전기는 각각 다르다.
|
||||
- 발전소에서 생산한 전기를 가정용으로 변환하는 계산식은 아래와 같다.
|
||||
- 생산된 전류량 * (발전소 전압 / 가정용 전압)
|
||||
- 발전소에서 생산한 전기의 전압은 11000V 이다.
|
||||
- 가정에서 사용하는 전기의 전압은 220V 이다.
|
||||
|
||||
### 옵저버(Observer) 패턴
|
||||
|
||||
#### 구현 요구사항
|
||||
|
||||
- 주문의 상태가 변경되면 배송팀과 운영팀에 알리고, 각각의 팀은 그에 따른 조치를 취한다.
|
||||
- 배송팀은 배송을 시작한다.
|
||||
- 운영팀은 고객에게 메시지를 전송한다.
|
||||
- 배송팀과 운영팀 외에 다른 팀에도 필요하다면 또 다른 팀에 메시지를 전송해야 할 수도 있다.
|
||||
|
||||
### 미디에이터(Mediator) 패턴
|
||||
|
||||
#### 구현 요구사항
|
||||
|
||||
- 가전제품의 전원을 제어한다.
|
||||
- 가전제품의 전원은 하나만 켤 수 있고, 하나를 켜면 나머지는 모두 꺼진다.
|
||||
- 가전제품을 켤 경우, 해당 가전제품의 이름을 메시지로 전송한다.
|
||||
|
||||
### 파사드(Facade) 패턴
|
||||
|
||||
#### 구현 요구사항
|
||||
|
||||
- 회원의 모든 정보를 조회한다.
|
||||
- 회원의 모든 정보에는 회원의 기본 정보와 친구들에 대한 정보가 있다.
|
||||
- 회원의 기본 정보에는 이름, 나이가 있다.
|
||||
- 회원의 친구 정보에는 친구의 이름, 나이가 있다.
|
||||
|
||||
### 추상 팩토리(Abstract Factory) 패턴
|
||||
|
||||
#### 구현 요구사항
|
||||
|
||||
- 과일 이름을 입력하면 해당 과일 또는 과일주스를 만들어주는 마법이 있다.
|
||||
- 과일의 종류는 사과, 바나나, 오렌지로 총 세 가지다.
|
||||
- 과일주스의 종류도 마찬가지로 사과주스, 바나나주스, 오렌즈주스로 총 세 가지다.
|
||||
|
||||
### 컴포지트(Composite) 패턴
|
||||
|
||||
#### 구현 요구사항
|
||||
|
||||
- 프랜차이즈 기업의 정산은 가맹점으로 가입된 모든 가게들의 정산을 포함한다.
|
||||
- 프랜차이즈 기업은 다른 프랜차이즈 기업을 포함할 수 있다.
|
||||
- 프랜차이즈 기업은 이름을 갖는다.
|
||||
- 프랜차이즈 가맹점은 이름을 갖는다.
|
||||
|
||||
### 널 객체(Null Object) 패턴
|
||||
|
||||
#### 구현 요구사항
|
||||
|
||||
- 식당에서는 직원을 이름으로 관리하며 동명이인은 없다고 가정한다.
|
||||
- 이름으로 직원을 찾을 수 있고, 해당 직원에게 근무일자를 할당할 수 있다.
|
||||
- 직원은 근무일자를 고지 받으면 해당 날짜를 기억한다.
|
||||
|
||||
## 참고자료
|
||||
|
||||
- [SOLID (객체 지향 설계)](https://ko.wikipedia.org/wiki/SOLID_(%EA%B0%9D%EC%B2%B4_%EC%A7%80%ED%96%A5_%EC%84%A4%EA%B3%84))
|
||||
|
||||
|
||||
39
놀이터(예제 코드 작성)/solid-design-pattern-sample/build.gradle.kts
Normal file
39
놀이터(예제 코드 작성)/solid-design-pattern-sample/build.gradle.kts
Normal file
@@ -0,0 +1,39 @@
|
||||
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
|
||||
|
||||
plugins {
|
||||
id("org.springframework.boot") version "2.7.5"
|
||||
id("io.spring.dependency-management") version "1.0.15.RELEASE"
|
||||
kotlin("jvm") version "1.6.21"
|
||||
kotlin("plugin.spring") version "1.6.21"
|
||||
kotlin("plugin.jpa") version "1.6.21"
|
||||
}
|
||||
|
||||
group = "com.banjjoknim"
|
||||
version = "0.0.1-SNAPSHOT"
|
||||
java.sourceCompatibility = JavaVersion.VERSION_11
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation("org.springframework.boot:spring-boot-starter-data-jpa")
|
||||
implementation("org.springframework.boot:spring-boot-starter-validation")
|
||||
implementation("org.springframework.boot:spring-boot-starter-web")
|
||||
implementation("com.fasterxml.jackson.module:jackson-module-kotlin")
|
||||
implementation("org.jetbrains.kotlin:kotlin-reflect")
|
||||
implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
|
||||
runtimeOnly("com.h2database:h2")
|
||||
testImplementation("org.springframework.boot:spring-boot-starter-test")
|
||||
}
|
||||
|
||||
tasks.withType<KotlinCompile> {
|
||||
kotlinOptions {
|
||||
freeCompilerArgs = listOf("-Xjsr305=strict")
|
||||
jvmTarget = "11"
|
||||
}
|
||||
}
|
||||
|
||||
tasks.withType<Test> {
|
||||
useJUnitPlatform()
|
||||
}
|
||||
BIN
놀이터(예제 코드 작성)/solid-design-pattern-sample/gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
BIN
놀이터(예제 코드 작성)/solid-design-pattern-sample/gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
Binary file not shown.
5
놀이터(예제 코드 작성)/solid-design-pattern-sample/gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
5
놀이터(예제 코드 작성)/solid-design-pattern-sample/gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.5.1-bin.zip
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
240
놀이터(예제 코드 작성)/solid-design-pattern-sample/gradlew
vendored
Executable file
240
놀이터(예제 코드 작성)/solid-design-pattern-sample/gradlew
vendored
Executable file
@@ -0,0 +1,240 @@
|
||||
#!/bin/sh
|
||||
|
||||
#
|
||||
# Copyright © 2015-2021 the original 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 POSIX generated by Gradle.
|
||||
#
|
||||
# Important for running:
|
||||
#
|
||||
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
|
||||
# noncompliant, but you have some other compliant shell such as ksh or
|
||||
# bash, then to run this script, type that shell name before the whole
|
||||
# command line, like:
|
||||
#
|
||||
# ksh Gradle
|
||||
#
|
||||
# Busybox and similar reduced shells will NOT work, because this script
|
||||
# requires all of these POSIX shell features:
|
||||
# * functions;
|
||||
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
|
||||
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
|
||||
# * compound commands having a testable exit status, especially «case»;
|
||||
# * various built-in commands including «command», «set», and «ulimit».
|
||||
#
|
||||
# Important for patching:
|
||||
#
|
||||
# (2) This script targets any POSIX shell, so it avoids extensions provided
|
||||
# by Bash, Ksh, etc; in particular arrays are avoided.
|
||||
#
|
||||
# The "traditional" practice of packing multiple parameters into a
|
||||
# space-separated string is a well documented source of bugs and security
|
||||
# problems, so this is (mostly) avoided, by progressively accumulating
|
||||
# options in "$@", and eventually passing that to Java.
|
||||
#
|
||||
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
|
||||
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
|
||||
# see the in-line comments for details.
|
||||
#
|
||||
# There are tweaks for specific operating systems such as AIX, CygWin,
|
||||
# Darwin, MinGW, and NonStop.
|
||||
#
|
||||
# (3) This script is generated from the Groovy template
|
||||
# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
||||
# within the Gradle project.
|
||||
#
|
||||
# You can find Gradle at https://github.com/gradle/gradle/.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
# Attempt to set APP_HOME
|
||||
|
||||
# Resolve links: $0 may be a link
|
||||
app_path=$0
|
||||
|
||||
# Need this for daisy-chained symlinks.
|
||||
while
|
||||
APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
|
||||
[ -h "$app_path" ]
|
||||
do
|
||||
ls=$( ls -ld "$app_path" )
|
||||
link=${ls#*' -> '}
|
||||
case $link in #(
|
||||
/*) app_path=$link ;; #(
|
||||
*) app_path=$APP_HOME$link ;;
|
||||
esac
|
||||
done
|
||||
|
||||
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
|
||||
|
||||
APP_NAME="Gradle"
|
||||
APP_BASE_NAME=${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 "$*"
|
||||
} >&2
|
||||
|
||||
die () {
|
||||
echo
|
||||
echo "$*"
|
||||
echo
|
||||
exit 1
|
||||
} >&2
|
||||
|
||||
# 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 ;; #(
|
||||
MSYS* | 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" && ! "$darwin" && ! "$nonstop" ; then
|
||||
case $MAX_FD in #(
|
||||
max*)
|
||||
MAX_FD=$( ulimit -H -n ) ||
|
||||
warn "Could not query maximum file descriptor limit"
|
||||
esac
|
||||
case $MAX_FD in #(
|
||||
'' | soft) :;; #(
|
||||
*)
|
||||
ulimit -n "$MAX_FD" ||
|
||||
warn "Could not set maximum file descriptor limit to $MAX_FD"
|
||||
esac
|
||||
fi
|
||||
|
||||
# Collect all arguments for the java command, stacking in reverse order:
|
||||
# * args from the command line
|
||||
# * the main class name
|
||||
# * -classpath
|
||||
# * -D...appname settings
|
||||
# * --module-path (only if needed)
|
||||
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
|
||||
|
||||
# For Cygwin or MSYS, switch paths to Windows format before running java
|
||||
if "$cygwin" || "$msys" ; then
|
||||
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
|
||||
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
|
||||
|
||||
JAVACMD=$( cygpath --unix "$JAVACMD" )
|
||||
|
||||
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||
for arg do
|
||||
if
|
||||
case $arg in #(
|
||||
-*) false ;; # don't mess with options #(
|
||||
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
|
||||
[ -e "$t" ] ;; #(
|
||||
*) false ;;
|
||||
esac
|
||||
then
|
||||
arg=$( cygpath --path --ignore --mixed "$arg" )
|
||||
fi
|
||||
# Roll the args list around exactly as many times as the number of
|
||||
# args, so each arg winds up back in the position where it started, but
|
||||
# possibly modified.
|
||||
#
|
||||
# NB: a `for` loop captures its iteration list before it begins, so
|
||||
# changing the positional parameters here affects neither the number of
|
||||
# iterations, nor the values presented in `arg`.
|
||||
shift # remove old arg
|
||||
set -- "$@" "$arg" # push replacement arg
|
||||
done
|
||||
fi
|
||||
|
||||
# Collect all arguments for the java command;
|
||||
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
|
||||
# shell script including quotes and variable substitutions, so put them in
|
||||
# double quotes to make sure that they get re-expanded; and
|
||||
# * put everything else in single quotes, so that it's not re-expanded.
|
||||
|
||||
set -- \
|
||||
"-Dorg.gradle.appname=$APP_BASE_NAME" \
|
||||
-classpath "$CLASSPATH" \
|
||||
org.gradle.wrapper.GradleWrapperMain \
|
||||
"$@"
|
||||
|
||||
# Stop when "xargs" is not available.
|
||||
if ! command -v xargs >/dev/null 2>&1
|
||||
then
|
||||
die "xargs is not available"
|
||||
fi
|
||||
|
||||
# Use "xargs" to parse quoted args.
|
||||
#
|
||||
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
|
||||
#
|
||||
# In Bash we could simply go:
|
||||
#
|
||||
# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
|
||||
# set -- "${ARGS[@]}" "$@"
|
||||
#
|
||||
# but POSIX shell has neither arrays nor command substitution, so instead we
|
||||
# post-process each arg (as a line of input to sed) to backslash-escape any
|
||||
# character that might be a shell metacharacter, then use eval to reverse
|
||||
# that process (while maintaining the separation between arguments), and wrap
|
||||
# the whole thing up as a single "set" statement.
|
||||
#
|
||||
# This will of course break if any of these variables contains a newline or
|
||||
# an unmatched quote.
|
||||
#
|
||||
|
||||
eval "set -- $(
|
||||
printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
|
||||
xargs -n1 |
|
||||
sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
|
||||
tr '\n' ' '
|
||||
)" '"$@"'
|
||||
|
||||
exec "$JAVACMD" "$@"
|
||||
91
놀이터(예제 코드 작성)/solid-design-pattern-sample/gradlew.bat
vendored
Normal file
91
놀이터(예제 코드 작성)/solid-design-pattern-sample/gradlew.bat
vendored
Normal file
@@ -0,0 +1,91 @@
|
||||
@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% equ 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% equ 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!
|
||||
set EXIT_CODE=%ERRORLEVEL%
|
||||
if %EXIT_CODE% equ 0 set EXIT_CODE=1
|
||||
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
|
||||
exit /b %EXIT_CODE%
|
||||
|
||||
:mainEnd
|
||||
if "%OS%"=="Windows_NT" endlocal
|
||||
|
||||
:omega
|
||||
@@ -0,0 +1 @@
|
||||
rootProject.name = "solid-design-pattern-sample"
|
||||
@@ -0,0 +1,11 @@
|
||||
package com.banjjoknim.soliddesignpatternsample
|
||||
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication
|
||||
import org.springframework.boot.runApplication
|
||||
|
||||
@SpringBootApplication
|
||||
class SolidDesignPatternSampleApplication
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
runApplication<SolidDesignPatternSampleApplication>(*args)
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package com.banjjoknim.soliddesignpatternsample.designpattern.abstractfactory.after
|
||||
|
||||
import com.banjjoknim.soliddesignpatternsample.designpattern.abstractfactory.common.Apple
|
||||
import com.banjjoknim.soliddesignpatternsample.designpattern.abstractfactory.common.AppleJuice
|
||||
|
||||
class AppleMagic : Magic {
|
||||
override fun createFruit() {
|
||||
val apple = Apple()
|
||||
println("과일 [${apple.name}]를 만들었습니다!")
|
||||
}
|
||||
|
||||
override fun createJuice() {
|
||||
val appleJuice = AppleJuice()
|
||||
println("과일주스 [${appleJuice.name}]을 만들었습니다!")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package com.banjjoknim.soliddesignpatternsample.designpattern.abstractfactory.after
|
||||
|
||||
import com.banjjoknim.soliddesignpatternsample.designpattern.abstractfactory.common.Banana
|
||||
import com.banjjoknim.soliddesignpatternsample.designpattern.abstractfactory.common.BananaJuice
|
||||
|
||||
class BananaMagic : Magic {
|
||||
override fun createFruit() {
|
||||
val banana = Banana()
|
||||
println("과일 [${banana.name}]를 만들었습니다!")
|
||||
}
|
||||
|
||||
override fun createJuice() {
|
||||
val bananaJuice = BananaJuice()
|
||||
println("과일주스 [${bananaJuice.name}]을 만들었습니다!")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package com.banjjoknim.soliddesignpatternsample.designpattern.abstractfactory.after
|
||||
|
||||
import com.banjjoknim.soliddesignpatternsample.designpattern.abstractfactory.common.FruitType
|
||||
|
||||
interface Magic {
|
||||
companion object {
|
||||
fun getMagic(fruitType: FruitType): Magic {
|
||||
return when (fruitType) {
|
||||
FruitType.APPLE -> AppleMagic()
|
||||
FruitType.BANANA -> BananaMagic()
|
||||
FruitType.ORANGE -> OrangeMagic()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun createFruit()
|
||||
|
||||
fun createJuice()
|
||||
}
|
||||
|
||||
//abstract class Magic {
|
||||
// companion object {
|
||||
// fun getMagic(fruitType: FruitType): Magic {
|
||||
// return when (fruitType) {
|
||||
// FruitType.APPLE -> AppleMagic()
|
||||
// FruitType.BANANA -> BananaMagic()
|
||||
// FruitType.ORANGE -> OrangeMagic()
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// abstract fun createFruit()
|
||||
//
|
||||
// abstract fun createJuice()
|
||||
//}
|
||||
@@ -0,0 +1,12 @@
|
||||
package com.banjjoknim.soliddesignpatternsample.designpattern.abstractfactory.after
|
||||
|
||||
import com.banjjoknim.soliddesignpatternsample.designpattern.abstractfactory.common.FruitType
|
||||
|
||||
class MagicApplication
|
||||
|
||||
fun main() {
|
||||
val fruitType = FruitType.APPLE
|
||||
val magic = Magic.getMagic(fruitType)
|
||||
magic.createFruit()
|
||||
magic.createJuice()
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package com.banjjoknim.soliddesignpatternsample.designpattern.abstractfactory.after
|
||||
|
||||
import com.banjjoknim.soliddesignpatternsample.designpattern.abstractfactory.common.Orange
|
||||
import com.banjjoknim.soliddesignpatternsample.designpattern.abstractfactory.common.OrangeJuice
|
||||
|
||||
class OrangeMagic : Magic {
|
||||
override fun createFruit() {
|
||||
val orange = Orange()
|
||||
println("과일 [${orange.name}]를 만들었습니다!")
|
||||
}
|
||||
|
||||
override fun createJuice() {
|
||||
val orangeJuice = OrangeJuice()
|
||||
println("과일주스 [${orangeJuice.name}]을 만들었습니다!")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package com.banjjoknim.soliddesignpatternsample.designpattern.abstractfactory.before
|
||||
|
||||
import com.banjjoknim.soliddesignpatternsample.designpattern.abstractfactory.common.Apple
|
||||
import com.banjjoknim.soliddesignpatternsample.designpattern.abstractfactory.common.AppleJuice
|
||||
import com.banjjoknim.soliddesignpatternsample.designpattern.abstractfactory.common.Banana
|
||||
import com.banjjoknim.soliddesignpatternsample.designpattern.abstractfactory.common.BananaJuice
|
||||
import com.banjjoknim.soliddesignpatternsample.designpattern.abstractfactory.common.FruitType
|
||||
import com.banjjoknim.soliddesignpatternsample.designpattern.abstractfactory.common.Orange
|
||||
import com.banjjoknim.soliddesignpatternsample.designpattern.abstractfactory.common.OrangeJuice
|
||||
|
||||
class Magic {
|
||||
fun createFruit(type: FruitType) {
|
||||
val fruit = when (type) {
|
||||
FruitType.APPLE -> Apple()
|
||||
FruitType.BANANA -> Banana()
|
||||
FruitType.ORANGE -> Orange()
|
||||
}
|
||||
println("과일 [${fruit.name}]를 만들었습니다!")
|
||||
}
|
||||
|
||||
fun createJuice(type: FruitType) {
|
||||
val juice = when (type) {
|
||||
FruitType.APPLE -> AppleJuice()
|
||||
FruitType.BANANA -> BananaJuice()
|
||||
FruitType.ORANGE -> OrangeJuice()
|
||||
}
|
||||
println("과일주스 [${juice.name}]을 만들었습니다!")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package com.banjjoknim.soliddesignpatternsample.designpattern.abstractfactory.before
|
||||
|
||||
import com.banjjoknim.soliddesignpatternsample.designpattern.abstractfactory.common.FruitType
|
||||
|
||||
class MagicApplication
|
||||
|
||||
fun main() {
|
||||
val magic = Magic()
|
||||
val fruitType = FruitType.APPLE
|
||||
magic.createFruit(fruitType)
|
||||
magic.createJuice(fruitType)
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package com.banjjoknim.soliddesignpatternsample.designpattern.abstractfactory.common
|
||||
|
||||
enum class FruitType {
|
||||
APPLE,
|
||||
BANANA,
|
||||
ORANGE
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package com.banjjoknim.soliddesignpatternsample.designpattern.abstractfactory.common
|
||||
|
||||
interface Fruit {
|
||||
val name: String
|
||||
}
|
||||
|
||||
data class Apple(override val name: String = "사과") : Fruit
|
||||
|
||||
data class Banana(override val name: String = "바나나") : Fruit
|
||||
|
||||
data class Orange(override val name: String = "오렌지") : Fruit
|
||||
@@ -0,0 +1,11 @@
|
||||
package com.banjjoknim.soliddesignpatternsample.designpattern.abstractfactory.common
|
||||
|
||||
interface Juice {
|
||||
val name: String
|
||||
}
|
||||
|
||||
data class AppleJuice(override val name: String = "사과주스") : Juice
|
||||
|
||||
data class BananaJuice(override val name: String = "바나나주스") : Juice
|
||||
|
||||
data class OrangeJuice(override val name: String = "오렌지주스") : Juice
|
||||
@@ -0,0 +1,7 @@
|
||||
package com.banjjoknim.soliddesignpatternsample.designpattern.adapter.after
|
||||
|
||||
import com.banjjoknim.soliddesignpatternsample.designpattern.adapter.common.HomeElectric
|
||||
|
||||
interface ElectricService {
|
||||
fun generateElectric(current: Int): HomeElectric
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package com.banjjoknim.soliddesignpatternsample.designpattern.adapter.after
|
||||
|
||||
import com.banjjoknim.soliddesignpatternsample.designpattern.adapter.common.HomeElectric
|
||||
import com.banjjoknim.soliddesignpatternsample.designpattern.adapter.common.PowerStation
|
||||
import com.banjjoknim.soliddesignpatternsample.designpattern.adapter.common.PowerStationElectricRequest
|
||||
|
||||
class HomePowerStationElectricAdapter(
|
||||
private val powerStation: PowerStation
|
||||
): ElectricService {
|
||||
override fun generateElectric(current: Int): HomeElectric {
|
||||
val powerStationElectricRequest = PowerStationElectricRequest(current)
|
||||
val powerStationElectric = powerStation.generateElectric(powerStationElectricRequest)
|
||||
return powerStationElectric.toHomeElectric()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package com.banjjoknim.soliddesignpatternsample.designpattern.adapter.after
|
||||
|
||||
import com.banjjoknim.soliddesignpatternsample.designpattern.adapter.common.Home
|
||||
import com.banjjoknim.soliddesignpatternsample.designpattern.adapter.common.PowerStation
|
||||
|
||||
class PowerStationApplication
|
||||
|
||||
fun main() {
|
||||
val powerStation = PowerStation()
|
||||
val homePowerStationElectricAdapter = HomePowerStationElectricAdapter(powerStation)
|
||||
|
||||
val homeElectric = homePowerStationElectricAdapter.generateElectric(1000)
|
||||
|
||||
val home = Home()
|
||||
home.takeElectric(homeElectric) // 가정은 발전소의 전기를 사용하는 클라이언트 역할을 한다.
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package com.banjjoknim.soliddesignpatternsample.designpattern.adapter.before
|
||||
|
||||
import com.banjjoknim.soliddesignpatternsample.designpattern.adapter.common.Home
|
||||
import com.banjjoknim.soliddesignpatternsample.designpattern.adapter.common.PowerStation
|
||||
import com.banjjoknim.soliddesignpatternsample.designpattern.adapter.common.PowerStationElectricRequest
|
||||
|
||||
class PowerStationApplication
|
||||
|
||||
fun main() {
|
||||
val powerStation = PowerStation()
|
||||
|
||||
val electricRequest = PowerStationElectricRequest(1000)
|
||||
val powerStationElectric = powerStation.generateElectric(electricRequest)
|
||||
|
||||
val homeElectric = powerStationElectric.toHomeElectric()
|
||||
|
||||
val home = Home()
|
||||
home.takeElectric(homeElectric) // 가정은 발전소의 전기를 사용하는 클라이언트 역할을 한다.
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package com.banjjoknim.soliddesignpatternsample.designpattern.adapter.common
|
||||
|
||||
class Home(
|
||||
private var electric: HomeElectric = HomeElectric(0)
|
||||
) {
|
||||
fun takeElectric(electric: HomeElectric) {
|
||||
this.electric = electric
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package com.banjjoknim.soliddesignpatternsample.designpattern.adapter.common
|
||||
|
||||
data class HomeElectric(
|
||||
val current: Int,
|
||||
)
|
||||
@@ -0,0 +1,7 @@
|
||||
package com.banjjoknim.soliddesignpatternsample.designpattern.adapter.common
|
||||
|
||||
class PowerStation {
|
||||
fun generateElectric(request: PowerStationElectricRequest): PowerStationElectric {
|
||||
return PowerStationElectric(request.current)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package com.banjjoknim.soliddesignpatternsample.designpattern.adapter.common
|
||||
|
||||
data class PowerStationElectric(
|
||||
val current: Int,
|
||||
) {
|
||||
fun toHomeElectric(): HomeElectric {
|
||||
return HomeElectric(this.current * (11000 / 220))
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package com.banjjoknim.soliddesignpatternsample.designpattern.adapter.common
|
||||
|
||||
data class PowerStationElectricRequest(
|
||||
val current: Int
|
||||
)
|
||||
@@ -0,0 +1,17 @@
|
||||
package com.banjjoknim.soliddesignpatternsample.designpattern.composite.after
|
||||
|
||||
class FranchiseeApplication
|
||||
|
||||
fun main() {
|
||||
val coffeeCorporation = FranchiseeCorporation("커피프린스")
|
||||
coffeeCorporation.addStore(FranchiseeStore("1호점"))
|
||||
coffeeCorporation.calculate()
|
||||
|
||||
println()
|
||||
println("가맹점 정산을 완료했습니다.")
|
||||
println()
|
||||
|
||||
val franchiseeCorporation = FranchiseeCorporation("모두의 프랜차이즈")
|
||||
franchiseeCorporation.addStore(coffeeCorporation)
|
||||
franchiseeCorporation.calculate()
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package com.banjjoknim.soliddesignpatternsample.designpattern.composite.after
|
||||
|
||||
class FranchiseeCorporation(
|
||||
private val name: String,
|
||||
private val stores: MutableList<Store> = mutableListOf()
|
||||
) : Store {
|
||||
fun addStore(store: Store) {
|
||||
stores.add(store)
|
||||
}
|
||||
|
||||
fun removeStore(store: Store) {
|
||||
stores.remove(store)
|
||||
}
|
||||
|
||||
override fun calculate() {
|
||||
for (store in stores) {
|
||||
store.calculate()
|
||||
}
|
||||
println("프랜차이즈 기업 [$name]의 정산을 완료했습니다.")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package com.banjjoknim.soliddesignpatternsample.designpattern.composite.after
|
||||
|
||||
class FranchiseeStore(
|
||||
val name: String
|
||||
) : Store {
|
||||
override fun calculate() {
|
||||
println("프랜차이즈 가게 [$name]이(가) 정산을 진행합니다.")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package com.banjjoknim.soliddesignpatternsample.designpattern.composite.after
|
||||
|
||||
interface Store {
|
||||
fun calculate()
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package com.banjjoknim.soliddesignpatternsample.designpattern.composite.before
|
||||
|
||||
class FranchiseeApplication
|
||||
|
||||
fun main() {
|
||||
val coffeeCorporation = FranchiseeCorporation("커피프린스")
|
||||
coffeeCorporation.addStore(FranchiseeStore("1호점"))
|
||||
coffeeCorporation.calculateAllStores()
|
||||
|
||||
println()
|
||||
println("가맹점 정산을 완료했습니다.")
|
||||
println()
|
||||
|
||||
val franchiseeCorporation = FranchiseeCorporation("모두의 프랜차이즈")
|
||||
franchiseeCorporation.addCorporation(coffeeCorporation)
|
||||
franchiseeCorporation.calculateAllCorporations()
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package com.banjjoknim.soliddesignpatternsample.designpattern.composite.before
|
||||
|
||||
class FranchiseeCorporation(
|
||||
private val name: String,
|
||||
private val corporations: MutableList<FranchiseeCorporation> = mutableListOf(),
|
||||
private val stores: MutableList<FranchiseeStore> = mutableListOf()
|
||||
) {
|
||||
fun addCorporation(franchiseeCorporation: FranchiseeCorporation) {
|
||||
corporations.add(franchiseeCorporation)
|
||||
}
|
||||
|
||||
fun removeCorporation(franchiseeCorporation: FranchiseeCorporation) {
|
||||
corporations.remove(franchiseeCorporation)
|
||||
}
|
||||
|
||||
fun addStore(store: FranchiseeStore) {
|
||||
stores.add(store)
|
||||
}
|
||||
|
||||
fun removeStore(store: FranchiseeStore) {
|
||||
stores.remove(store)
|
||||
}
|
||||
|
||||
fun calculateAllCorporations() {
|
||||
for (corporation in corporations) {
|
||||
corporation.calculateAllStores()
|
||||
}
|
||||
println("프랜차이즈 기업 [$name]의 정산을 완료했습니다.")
|
||||
}
|
||||
|
||||
fun calculateAllStores() {
|
||||
for (store in stores) {
|
||||
store.calculate()
|
||||
}
|
||||
println("프랜차이즈 기업 [$name]의 정산을 완료했습니다.")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package com.banjjoknim.soliddesignpatternsample.designpattern.composite.before
|
||||
|
||||
class FranchiseeStore(
|
||||
val name: String
|
||||
) {
|
||||
fun calculate() {
|
||||
println("프랜차이즈 가게 [$name]이(가) 정산을 진행합니다.")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package com.banjjoknim.soliddesignpatternsample.designpattern.decorator.after
|
||||
|
||||
import com.banjjoknim.soliddesignpatternsample.designpattern.decorator.common.Sword
|
||||
|
||||
class Fire(private val sword: Sword) : SwordDecorator() {
|
||||
override fun skill(): String {
|
||||
return "불꽃 ${sword.skill()}"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package com.banjjoknim.soliddesignpatternsample.designpattern.decorator.after
|
||||
|
||||
import com.banjjoknim.soliddesignpatternsample.designpattern.decorator.common.Hero
|
||||
import com.banjjoknim.soliddesignpatternsample.designpattern.decorator.common.Sword
|
||||
|
||||
class HeroApplication
|
||||
|
||||
fun main() {
|
||||
val hero = Hero()
|
||||
hero.attack()
|
||||
|
||||
val fireSword = Fire(Sword.DEFAULT)
|
||||
hero.changeSword(fireSword)
|
||||
hero.attack()
|
||||
|
||||
val iceSword = Ice(Sword.DEFAULT)
|
||||
hero.changeSword(iceSword)
|
||||
hero.attack()
|
||||
|
||||
val fireIceSword = Fire(Ice(Sword.DEFAULT))
|
||||
hero.changeSword(fireIceSword)
|
||||
hero.attack()
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package com.banjjoknim.soliddesignpatternsample.designpattern.decorator.after
|
||||
|
||||
import com.banjjoknim.soliddesignpatternsample.designpattern.decorator.common.Sword
|
||||
|
||||
class Ice(private val sword: Sword) : SwordDecorator() {
|
||||
override fun skill(): String {
|
||||
return "얼음 ${sword.skill()}"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package com.banjjoknim.soliddesignpatternsample.designpattern.decorator.after
|
||||
|
||||
import com.banjjoknim.soliddesignpatternsample.designpattern.decorator.common.Sword
|
||||
|
||||
abstract class SwordDecorator : Sword()
|
||||
@@ -0,0 +1,9 @@
|
||||
package com.banjjoknim.soliddesignpatternsample.designpattern.decorator.before
|
||||
|
||||
import com.banjjoknim.soliddesignpatternsample.designpattern.decorator.common.Sword
|
||||
|
||||
class FireIceSword : Sword() {
|
||||
override fun skill(): String {
|
||||
return "화염 얼음 ${DEFAULT.skill()}"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package com.banjjoknim.soliddesignpatternsample.designpattern.decorator.before
|
||||
|
||||
import com.banjjoknim.soliddesignpatternsample.designpattern.decorator.common.Sword
|
||||
|
||||
class FireSword : Sword() {
|
||||
override fun skill(): String {
|
||||
return "화염 ${DEFAULT.skill()}"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package com.banjjoknim.soliddesignpatternsample.designpattern.decorator.before
|
||||
|
||||
import com.banjjoknim.soliddesignpatternsample.designpattern.decorator.common.Hero
|
||||
|
||||
class HeroApplication
|
||||
|
||||
fun main() {
|
||||
val hero = Hero()
|
||||
hero.attack()
|
||||
|
||||
val fireSword = FireSword()
|
||||
hero.changeSword(fireSword)
|
||||
hero.attack()
|
||||
|
||||
val iceSword = IceSword()
|
||||
hero.changeSword(iceSword)
|
||||
hero.attack()
|
||||
|
||||
val fireIceSword = FireIceSword()
|
||||
hero.changeSword(fireIceSword)
|
||||
hero.attack()
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package com.banjjoknim.soliddesignpatternsample.designpattern.decorator.before
|
||||
|
||||
import com.banjjoknim.soliddesignpatternsample.designpattern.decorator.common.Sword
|
||||
|
||||
class IceSword : Sword() {
|
||||
override fun skill(): String {
|
||||
return "얼음 ${DEFAULT.skill()}"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package com.banjjoknim.soliddesignpatternsample.designpattern.decorator.common
|
||||
|
||||
class Hero(
|
||||
private var sword: Sword = Sword.DEFAULT
|
||||
) {
|
||||
fun changeSword(sword: Sword) {
|
||||
this.sword = sword
|
||||
}
|
||||
|
||||
fun attack() {
|
||||
val swordSkill = sword.skill()
|
||||
println("용사가 [$swordSkill]을 발동합니다.")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package com.banjjoknim.soliddesignpatternsample.designpattern.decorator.common
|
||||
|
||||
abstract class Sword {
|
||||
abstract fun skill(): String
|
||||
|
||||
companion object {
|
||||
val DEFAULT = object : Sword() {
|
||||
override fun skill(): String {
|
||||
return "참격"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package com.banjjoknim.soliddesignpatternsample.designpattern.facade.after
|
||||
|
||||
import com.banjjoknim.soliddesignpatternsample.designpattern.facade.common.Information
|
||||
|
||||
interface InformationFinder {
|
||||
fun findInformation(): Information
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package com.banjjoknim.soliddesignpatternsample.designpattern.facade.after
|
||||
|
||||
import com.banjjoknim.soliddesignpatternsample.designpattern.facade.common.FriendFinder
|
||||
import com.banjjoknim.soliddesignpatternsample.designpattern.facade.common.MemberFinder
|
||||
|
||||
class MemberApplication
|
||||
|
||||
fun main() {
|
||||
val memberFinder = MemberFinder()
|
||||
val friendFinder = FriendFinder()
|
||||
|
||||
val memberInformationFinder = MemberInformationFinder(memberFinder, friendFinder)
|
||||
|
||||
val memberInformation = memberInformationFinder.findInformation()
|
||||
println(memberInformation)
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package com.banjjoknim.soliddesignpatternsample.designpattern.facade.after
|
||||
|
||||
import com.banjjoknim.soliddesignpatternsample.designpattern.facade.common.FriendFinder
|
||||
import com.banjjoknim.soliddesignpatternsample.designpattern.facade.common.Information
|
||||
import com.banjjoknim.soliddesignpatternsample.designpattern.facade.common.MemberFinder
|
||||
import com.banjjoknim.soliddesignpatternsample.designpattern.facade.common.MemberInformation
|
||||
|
||||
class MemberInformationFinder(
|
||||
private val memberFinder: MemberFinder,
|
||||
private val friendFinder: FriendFinder,
|
||||
): InformationFinder {
|
||||
override fun findInformation(): Information {
|
||||
val member = memberFinder.findMember()
|
||||
val friends = friendFinder.findFriends(member)
|
||||
return MemberInformation(member, friends)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package com.banjjoknim.soliddesignpatternsample.designpattern.facade.before
|
||||
|
||||
import com.banjjoknim.soliddesignpatternsample.designpattern.facade.common.FriendFinder
|
||||
import com.banjjoknim.soliddesignpatternsample.designpattern.facade.common.MemberFinder
|
||||
import com.banjjoknim.soliddesignpatternsample.designpattern.facade.common.MemberInformation
|
||||
|
||||
class MemberApplication
|
||||
|
||||
fun main() {
|
||||
val memberFinder = MemberFinder()
|
||||
val friendFinder = FriendFinder()
|
||||
|
||||
val member = memberFinder.findMember()
|
||||
val friends = friendFinder.findFriends(member)
|
||||
|
||||
val memberInformation = MemberInformation(member, friends)
|
||||
println(memberInformation)
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
package com.banjjoknim.soliddesignpatternsample.designpattern.facade.common
|
||||
|
||||
data class Friend(
|
||||
val name: String,
|
||||
val age: Int
|
||||
)
|
||||
@@ -0,0 +1,10 @@
|
||||
package com.banjjoknim.soliddesignpatternsample.designpattern.facade.common
|
||||
|
||||
import com.banjjoknim.soliddesignpatternsample.designpattern.facade.common.Friend
|
||||
import com.banjjoknim.soliddesignpatternsample.designpattern.facade.common.Member
|
||||
|
||||
class FriendFinder {
|
||||
fun findFriends(member: Member): List<Friend> {
|
||||
return listOf(Friend("colt", 29))
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package com.banjjoknim.soliddesignpatternsample.designpattern.facade.common
|
||||
|
||||
data class FriendInformation(
|
||||
val name: String,
|
||||
val age: Int
|
||||
) : Information {
|
||||
constructor(friend: Friend) : this(
|
||||
name = friend.name,
|
||||
age = friend.age
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
package com.banjjoknim.soliddesignpatternsample.designpattern.facade.common
|
||||
|
||||
interface Information
|
||||
@@ -0,0 +1,6 @@
|
||||
package com.banjjoknim.soliddesignpatternsample.designpattern.facade.common
|
||||
|
||||
class Member(
|
||||
val name: String,
|
||||
val age: Int
|
||||
)
|
||||
@@ -0,0 +1,9 @@
|
||||
package com.banjjoknim.soliddesignpatternsample.designpattern.facade.common
|
||||
|
||||
import com.banjjoknim.soliddesignpatternsample.designpattern.facade.common.Member
|
||||
|
||||
class MemberFinder {
|
||||
fun findMember(): Member {
|
||||
return Member("banjjoknim", 29)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package com.banjjoknim.soliddesignpatternsample.designpattern.facade.common
|
||||
|
||||
data class MemberInformation(
|
||||
val memberName: String,
|
||||
val memberAge: Int,
|
||||
val friendsInformation: List<FriendInformation>
|
||||
): Information {
|
||||
constructor(member: Member, friends: List<Friend>) : this(
|
||||
memberName = member.name,
|
||||
memberAge = member.age,
|
||||
friendsInformation = friends.map { FriendInformation(it) }
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package com.banjjoknim.soliddesignpatternsample.designpattern.mediator.after
|
||||
|
||||
class AirConditioner(override val name: String) : HomeAppliance {
|
||||
override fun turnOn() {
|
||||
println("${name}을 켭니다.")
|
||||
}
|
||||
|
||||
override fun turnOff() {
|
||||
println("${name}을 끕니다.")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package com.banjjoknim.soliddesignpatternsample.designpattern.mediator.after
|
||||
|
||||
interface HomeAppliance {
|
||||
val name: String
|
||||
|
||||
fun turnOn()
|
||||
|
||||
fun turnOff()
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package com.banjjoknim.soliddesignpatternsample.designpattern.mediator.after
|
||||
|
||||
class HomeApplianceApplication
|
||||
|
||||
fun main() {
|
||||
val airConditioner = AirConditioner("에어컨")
|
||||
val television = Television("텔레비전")
|
||||
val messageSender = MessageSender()
|
||||
val remoteControl = RemoteControl(listOf(airConditioner, television), messageSender)
|
||||
|
||||
remoteControl.turnOn(airConditioner)
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package com.banjjoknim.soliddesignpatternsample.designpattern.mediator.after
|
||||
|
||||
class MessageSender {
|
||||
fun sendMessage(homeAppliance: HomeAppliance) {
|
||||
println("메시지 : ${homeAppliance.name}을 켰습니다.")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package com.banjjoknim.soliddesignpatternsample.designpattern.mediator.after
|
||||
|
||||
class RemoteControl(
|
||||
private val homeAppliances: List<HomeAppliance>,
|
||||
private val messageSender: MessageSender
|
||||
) {
|
||||
fun turnOn(homeAppliance: HomeAppliance) {
|
||||
homeAppliances.filterNot { it == homeAppliance }
|
||||
.forEach { it.turnOff() }
|
||||
homeAppliance.turnOn()
|
||||
messageSender.sendMessage(homeAppliance)
|
||||
}
|
||||
|
||||
fun turnOff(homeAppliance: HomeAppliance) {
|
||||
homeAppliance.turnOff()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package com.banjjoknim.soliddesignpatternsample.designpattern.mediator.after
|
||||
|
||||
class Television(override val name: String) : HomeAppliance {
|
||||
override fun turnOn() {
|
||||
println("${name}을 켭니다.")
|
||||
}
|
||||
|
||||
override fun turnOff() {
|
||||
println("${name}을 끕니다.")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package com.banjjoknim.soliddesignpatternsample.designpattern.mediator.before
|
||||
|
||||
class AirConditioner(override val name: String) : HomeAppliance {
|
||||
override fun turnOnBut(homeAppliance: HomeAppliance, messageSender: MessageSender) {
|
||||
homeAppliance.turnOff()
|
||||
println("${name}을 켭니다.")
|
||||
messageSender.sendMessage(this)
|
||||
}
|
||||
|
||||
override fun turnOff() {
|
||||
println("${name}을 끕니다.")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package com.banjjoknim.soliddesignpatternsample.designpattern.mediator.before
|
||||
|
||||
interface HomeAppliance {
|
||||
val name: String
|
||||
|
||||
fun turnOnBut(homeAppliance: HomeAppliance, messageSender: MessageSender)
|
||||
|
||||
fun turnOff()
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package com.banjjoknim.soliddesignpatternsample.designpattern.mediator.before
|
||||
|
||||
class HomeApplianceApplication
|
||||
|
||||
fun main() {
|
||||
val airConditioner = AirConditioner("에어컨")
|
||||
val television = Television("텔레비전")
|
||||
val messageSender = MessageSender()
|
||||
|
||||
airConditioner.turnOnBut(television, messageSender)
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package com.banjjoknim.soliddesignpatternsample.designpattern.mediator.before
|
||||
|
||||
class MessageSender {
|
||||
fun sendMessage(homeAppliance: HomeAppliance) {
|
||||
println("메시지 : ${homeAppliance.name}을 켰습니다.")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package com.banjjoknim.soliddesignpatternsample.designpattern.mediator.before
|
||||
|
||||
class Television(override val name: String) : HomeAppliance {
|
||||
override fun turnOnBut(homeAppliance: HomeAppliance, messageSender: MessageSender) {
|
||||
homeAppliance.turnOff()
|
||||
println("${name}을 켭니다.")
|
||||
messageSender.sendMessage(this)
|
||||
}
|
||||
|
||||
override fun turnOff() {
|
||||
println("${name}을 끕니다.")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package com.banjjoknim.soliddesignpatternsample.designpattern.nill.after
|
||||
|
||||
interface Employee {
|
||||
companion object {
|
||||
val NOT_FOUND = object : Employee {
|
||||
override val name: String
|
||||
get() = "존재하지 않음"
|
||||
|
||||
override fun memorizeWorkingDays(workingDays: List<Int>) {
|
||||
// 아무 작업도 하지 않는다.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val name: String
|
||||
var workingDays: List<Int>
|
||||
get() = listOf()
|
||||
set(workingDays) {
|
||||
memorizeWorkingDays(workingDays)
|
||||
}
|
||||
|
||||
fun memorizeWorkingDays(workingDays: List<Int>)
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package com.banjjoknim.soliddesignpatternsample.designpattern.nill.after
|
||||
|
||||
class Restaurant(
|
||||
private val employees: MutableList<Employee> = mutableListOf()
|
||||
) {
|
||||
fun addEmployee(employee: Employee) {
|
||||
employees.add(employee)
|
||||
}
|
||||
|
||||
fun removeEmployee(employee: Employee) {
|
||||
employees.remove(employee)
|
||||
}
|
||||
|
||||
fun showAllEmployeesWorkingDays() {
|
||||
for (employee in employees) {
|
||||
println("${employee.name}의 근무일은 ${employee.workingDays}일 입니다.")
|
||||
}
|
||||
}
|
||||
|
||||
fun assignWorkingDays(workingDays: List<Int>, employeeName: String) {
|
||||
val employee = findEmployee(employeeName)
|
||||
employee.memorizeWorkingDays(workingDays)
|
||||
}
|
||||
|
||||
private fun findEmployee(employeeName: String): Employee {
|
||||
return employees.find { it.name == employeeName } ?: Employee.NOT_FOUND
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package com.banjjoknim.soliddesignpatternsample.designpattern.nill.after
|
||||
|
||||
class RestaurantApplication
|
||||
|
||||
fun main() {
|
||||
val restaurant = Restaurant()
|
||||
restaurant.addEmployee(WorkingEmployee("banjjoknim"))
|
||||
|
||||
restaurant.assignWorkingDays(listOf(1, 4, 7, 14, 20, 27), "banjjoknim")
|
||||
restaurant.assignWorkingDays(listOf(2, 5, 10, 17, 23, 29), "colt")
|
||||
|
||||
restaurant.showAllEmployeesWorkingDays()
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package com.banjjoknim.soliddesignpatternsample.designpattern.nill.after
|
||||
|
||||
class WorkingEmployee(
|
||||
override val name: String,
|
||||
override var workingDays: List<Int> = listOf()
|
||||
) : Employee {
|
||||
override fun memorizeWorkingDays(workingDays: List<Int>) {
|
||||
this.workingDays = workingDays
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package com.banjjoknim.soliddesignpatternsample.designpattern.nill.before
|
||||
|
||||
class Employee(
|
||||
val name: String,
|
||||
var workingDays: List<Int> = listOf()
|
||||
) {
|
||||
fun memorizeWorkingDays(workingDays: List<Int>) {
|
||||
this.workingDays = workingDays
|
||||
}
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (javaClass != other?.javaClass) return false
|
||||
|
||||
other as Employee
|
||||
|
||||
if (name != other.name) return false
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
return name.hashCode()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package com.banjjoknim.soliddesignpatternsample.designpattern.nill.before
|
||||
|
||||
class Restaurant(
|
||||
private val employees: MutableList<Employee> = mutableListOf()
|
||||
) {
|
||||
fun addEmployee(employee: Employee) {
|
||||
employees.add(employee)
|
||||
}
|
||||
|
||||
fun removeEmployee(employee: Employee) {
|
||||
employees.remove(employee)
|
||||
}
|
||||
|
||||
fun showAllEmployeesWorkingDays() {
|
||||
for (employee in employees) {
|
||||
println("${employee.name}의 근무일은 ${employee.workingDays}일 입니다.")
|
||||
}
|
||||
}
|
||||
|
||||
fun assignWorkingDays(workingDays: List<Int>, employeeName: String) {
|
||||
val employee = findEmployee(employeeName)
|
||||
if (employee != null) {
|
||||
employee.memorizeWorkingDays(workingDays)
|
||||
}
|
||||
}
|
||||
|
||||
private fun findEmployee(employeeName: String): Employee? {
|
||||
return employees.find { it.name == employeeName }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package com.banjjoknim.soliddesignpatternsample.designpattern.nill.before
|
||||
|
||||
class RestaurantApplication
|
||||
|
||||
fun main() {
|
||||
val restaurant = Restaurant()
|
||||
restaurant.addEmployee(Employee("banjjoknim"))
|
||||
|
||||
restaurant.assignWorkingDays(listOf(1, 4, 7, 14, 20, 27), "banjjoknim")
|
||||
restaurant.assignWorkingDays(listOf(2, 5, 10, 17, 23, 29), "colt")
|
||||
|
||||
restaurant.showAllEmployeesWorkingDays()
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package com.banjjoknim.soliddesignpatternsample.designpattern.observer.after
|
||||
|
||||
import com.banjjoknim.soliddesignpatternsample.designpattern.observer.common.OrderState
|
||||
|
||||
class DeliveryTeam : Team {
|
||||
override val name: String
|
||||
get() = "배송팀"
|
||||
|
||||
override fun onNotice(state: OrderState) {
|
||||
println("$name : 주문이 ${state.description} 상태로 변경되었네요. 배송을 시작합니다.")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package com.banjjoknim.soliddesignpatternsample.designpattern.observer.after
|
||||
|
||||
import com.banjjoknim.soliddesignpatternsample.designpattern.observer.common.OrderState
|
||||
|
||||
class ManageTeam : Team {
|
||||
override val name: String
|
||||
get() = "운영팀"
|
||||
|
||||
override fun onNotice(state: OrderState) {
|
||||
println("$name : 주문이 ${state.description} 상태로 변경되었네요. 소비자에게 메시지를 전송합니다.")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package com.banjjoknim.soliddesignpatternsample.designpattern.observer.after
|
||||
|
||||
import com.banjjoknim.soliddesignpatternsample.designpattern.observer.common.OrderState
|
||||
|
||||
class Order(
|
||||
private var state: OrderState = OrderState.RECEIVED,
|
||||
private val teams: MutableList<Team> = mutableListOf()
|
||||
) {
|
||||
fun addTeam(team: Team) {
|
||||
this.teams.add(team)
|
||||
}
|
||||
|
||||
fun removeTeam(team: Team) {
|
||||
this.teams.remove(team)
|
||||
}
|
||||
|
||||
fun changeState(state: OrderState) {
|
||||
this.state = state
|
||||
teams.forEach { it.onNotice(state) }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package com.banjjoknim.soliddesignpatternsample.designpattern.observer.after
|
||||
|
||||
import com.banjjoknim.soliddesignpatternsample.designpattern.observer.common.OrderState
|
||||
|
||||
class OrderApplication
|
||||
|
||||
fun main() {
|
||||
val order = Order()
|
||||
order.addTeam(DeliveryTeam())
|
||||
order.addTeam(ManageTeam())
|
||||
order.changeState(OrderState.DELIVERY_READY_COMPLETE)
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package com.banjjoknim.soliddesignpatternsample.designpattern.observer.after
|
||||
|
||||
import com.banjjoknim.soliddesignpatternsample.designpattern.observer.common.OrderState
|
||||
|
||||
interface Team {
|
||||
val name: String
|
||||
|
||||
fun onNotice(state: OrderState)
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user