SOLID, Design Pattern 샘플 코드 추가 (#17)

* initial commit

* feat : SOLID - SRP 샘플 코드 구현

* feat : SOLID - OCP 샘플 코드 구현

* feat : SOLID - LSP 샘플 코드 구현

* feat : SOLID - ISP 샘플 코드 구현

* feat : SOLID - DIP 샘플 코드 구현

* docs : README.md Design Pattern 항목 추가

* feat : Design Pattern - 전략(Strategy) 패턴 구현

* feat : Design Pattern - 템플릿 메서드(Template Method) 패턴 구현

* feat : Design Pattern - 상태(State) 패턴 구현

* feat : Design Pattern - 프록시(Proxy) 패턴 구현

* feat : Design Pattern - 어댑터(Adapter) 패턴 구현

* feat : Design Pattern - 옵저버(Observer) 패턴 구현

* feat : Design Pattern - 파사드(Facade) 패턴 구현

* feat : Design Pattern - 추상 팩토리 패턴(Abstract Factory) 패턴 구현

* feat : Design Pattern - 컴포지트(Composite) 패턴 구현

* feat : Design Pattern - 미디에이터(Mediator) 패턴 구현

* feat : Design Pattern - 널 객체(Null Object) 패턴 구현

* feat : Design Pattern - 데코레이터(Decorator) 패턴 구현
This commit is contained in:
Colt
2022-11-16 01:36:13 +09:00
committed by GitHub
parent ec46451143
commit c6a8493aa3
185 changed files with 2913 additions and 0 deletions

View 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/

View 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))

View 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()
}

View 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

View 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" "$@"

View 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

View File

@@ -0,0 +1 @@
rootProject.name = "solid-design-pattern-sample"

View File

@@ -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)
}

View File

@@ -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}]을 만들었습니다!")
}
}

View File

@@ -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}]을 만들었습니다!")
}
}

View File

@@ -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()
//}

View File

@@ -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()
}

View File

@@ -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}]을 만들었습니다!")
}
}

View File

@@ -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}]을 만들었습니다!")
}
}

View File

@@ -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)
}

View File

@@ -0,0 +1,7 @@
package com.banjjoknim.soliddesignpatternsample.designpattern.abstractfactory.common
enum class FruitType {
APPLE,
BANANA,
ORANGE
}

View File

@@ -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

View File

@@ -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

View File

@@ -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
}

View File

@@ -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()
}
}

View File

@@ -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) // 가정은 발전소의 전기를 사용하는 클라이언트 역할을 한다.
}

View File

@@ -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) // 가정은 발전소의 전기를 사용하는 클라이언트 역할을 한다.
}

View File

@@ -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
}
}

View File

@@ -0,0 +1,5 @@
package com.banjjoknim.soliddesignpatternsample.designpattern.adapter.common
data class HomeElectric(
val current: Int,
)

View File

@@ -0,0 +1,7 @@
package com.banjjoknim.soliddesignpatternsample.designpattern.adapter.common
class PowerStation {
fun generateElectric(request: PowerStationElectricRequest): PowerStationElectric {
return PowerStationElectric(request.current)
}
}

View File

@@ -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))
}
}

View File

@@ -0,0 +1,5 @@
package com.banjjoknim.soliddesignpatternsample.designpattern.adapter.common
data class PowerStationElectricRequest(
val current: Int
)

View File

@@ -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()
}

View File

@@ -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]의 정산을 완료했습니다.")
}
}

View File

@@ -0,0 +1,9 @@
package com.banjjoknim.soliddesignpatternsample.designpattern.composite.after
class FranchiseeStore(
val name: String
) : Store {
override fun calculate() {
println("프랜차이즈 가게 [$name]이(가) 정산을 진행합니다.")
}
}

View File

@@ -0,0 +1,5 @@
package com.banjjoknim.soliddesignpatternsample.designpattern.composite.after
interface Store {
fun calculate()
}

View File

@@ -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()
}

View File

@@ -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]의 정산을 완료했습니다.")
}
}

View File

@@ -0,0 +1,9 @@
package com.banjjoknim.soliddesignpatternsample.designpattern.composite.before
class FranchiseeStore(
val name: String
) {
fun calculate() {
println("프랜차이즈 가게 [$name]이(가) 정산을 진행합니다.")
}
}

View File

@@ -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()}"
}
}

View File

@@ -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()
}

View File

@@ -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()}"
}
}

View File

@@ -0,0 +1,5 @@
package com.banjjoknim.soliddesignpatternsample.designpattern.decorator.after
import com.banjjoknim.soliddesignpatternsample.designpattern.decorator.common.Sword
abstract class SwordDecorator : Sword()

View File

@@ -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()}"
}
}

View File

@@ -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()}"
}
}

View File

@@ -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()
}

View File

@@ -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()}"
}
}

View File

@@ -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]을 발동합니다.")
}
}

View File

@@ -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 "참격"
}
}
}
}

View File

@@ -0,0 +1,7 @@
package com.banjjoknim.soliddesignpatternsample.designpattern.facade.after
import com.banjjoknim.soliddesignpatternsample.designpattern.facade.common.Information
interface InformationFinder {
fun findInformation(): Information
}

View File

@@ -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)
}

View File

@@ -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)
}
}

View File

@@ -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)
}

View File

@@ -0,0 +1,6 @@
package com.banjjoknim.soliddesignpatternsample.designpattern.facade.common
data class Friend(
val name: String,
val age: Int
)

View File

@@ -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))
}
}

View File

@@ -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
)
}

View File

@@ -0,0 +1,3 @@
package com.banjjoknim.soliddesignpatternsample.designpattern.facade.common
interface Information

View File

@@ -0,0 +1,6 @@
package com.banjjoknim.soliddesignpatternsample.designpattern.facade.common
class Member(
val name: String,
val age: Int
)

View File

@@ -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)
}
}

View File

@@ -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) }
)
}

View File

@@ -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}을 끕니다.")
}
}

View File

@@ -0,0 +1,9 @@
package com.banjjoknim.soliddesignpatternsample.designpattern.mediator.after
interface HomeAppliance {
val name: String
fun turnOn()
fun turnOff()
}

View File

@@ -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)
}

View File

@@ -0,0 +1,7 @@
package com.banjjoknim.soliddesignpatternsample.designpattern.mediator.after
class MessageSender {
fun sendMessage(homeAppliance: HomeAppliance) {
println("메시지 : ${homeAppliance.name}을 켰습니다.")
}
}

View File

@@ -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()
}
}

View File

@@ -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}을 끕니다.")
}
}

View File

@@ -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}을 끕니다.")
}
}

View File

@@ -0,0 +1,9 @@
package com.banjjoknim.soliddesignpatternsample.designpattern.mediator.before
interface HomeAppliance {
val name: String
fun turnOnBut(homeAppliance: HomeAppliance, messageSender: MessageSender)
fun turnOff()
}

View File

@@ -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)
}

View File

@@ -0,0 +1,7 @@
package com.banjjoknim.soliddesignpatternsample.designpattern.mediator.before
class MessageSender {
fun sendMessage(homeAppliance: HomeAppliance) {
println("메시지 : ${homeAppliance.name}을 켰습니다.")
}
}

View File

@@ -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}을 끕니다.")
}
}

View File

@@ -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>)
}

View File

@@ -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
}
}

View File

@@ -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()
}

View File

@@ -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
}
}

View File

@@ -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()
}
}

View File

@@ -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 }
}
}

View File

@@ -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()
}

View File

@@ -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} 상태로 변경되었네요. 배송을 시작합니다.")
}
}

View File

@@ -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} 상태로 변경되었네요. 소비자에게 메시지를 전송합니다.")
}
}

View File

@@ -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) }
}
}

View File

@@ -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)
}

View File

@@ -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)
}

View File

@@ -0,0 +1,9 @@
package com.banjjoknim.soliddesignpatternsample.designpattern.observer.before
import com.banjjoknim.soliddesignpatternsample.designpattern.observer.common.OrderState
class DeliveryTeam {
fun doDelivery(state: OrderState) {
println("배송팀 : 주문이 ${state.description} 상태로 변경되었네요. 배송을 시작합니다.")
}
}

View File

@@ -0,0 +1,9 @@
package com.banjjoknim.soliddesignpatternsample.designpattern.observer.before
import com.banjjoknim.soliddesignpatternsample.designpattern.observer.common.OrderState
class ManageTeam {
fun sendMessage(state: OrderState) {
println("운영팀 : 주문이 ${state.description} 상태로 변경되었네요. 소비자에게 메시지를 전송합니다.")
}
}

View File

@@ -0,0 +1,15 @@
package com.banjjoknim.soliddesignpatternsample.designpattern.observer.before
import com.banjjoknim.soliddesignpatternsample.designpattern.observer.common.OrderState
class Order(
private var state: OrderState = OrderState.RECEIVED,
private val deliveryTeam: DeliveryTeam,
private val manageTeam: ManageTeam
) {
fun changeState(state: OrderState) {
this.state = state
deliveryTeam.doDelivery(state)
manageTeam.sendMessage(state)
}
}

View File

@@ -0,0 +1,10 @@
package com.banjjoknim.soliddesignpatternsample.designpattern.observer.before
import com.banjjoknim.soliddesignpatternsample.designpattern.observer.common.OrderState
class OrderApplication
fun main() {
val order = Order(state = OrderState.RECEIVED, DeliveryTeam(), ManageTeam())
order.changeState(OrderState.DELIVERY_READY_COMPLETE)
}

View File

@@ -0,0 +1,8 @@
package com.banjjoknim.soliddesignpatternsample.designpattern.observer.common
enum class OrderState(
val description: String
) {
RECEIVED("접수됨"),
DELIVERY_READY_COMPLETE("배송 준비")
}

View File

@@ -0,0 +1,13 @@
package com.banjjoknim.soliddesignpatternsample.designpattern.proxy.after
class ExtendsProxyWallet(balance: Int) : RealWallet(balance) {
override fun deposit(amount: Int) {
println("지갑에 $amount 원이 입금되었습니다.")
super.deposit(amount)
}
override fun withdrawal(amount: Int) {
println("지갑에서 $amount 원이 출금되었습니다.")
super.withdrawal(amount)
}
}

View File

@@ -0,0 +1,15 @@
package com.banjjoknim.soliddesignpatternsample.designpattern.proxy.after
class ImplementsProxyWallet(
private val realWallet: RealWallet
) : Wallet {
override fun deposit(amount: Int) {
println("지갑에 $amount 원이 입금되었습니다.")
realWallet.deposit(amount)
}
override fun withdrawal(amount: Int) {
println("지갑에서 $amount 원이 출금되었습니다.")
realWallet.withdrawal(amount)
}
}

View File

@@ -0,0 +1,13 @@
package com.banjjoknim.soliddesignpatternsample.designpattern.proxy.after
class Owner(
private val wallet: Wallet
) {
fun deposit(amount: Int) {
wallet.deposit(amount)
}
fun withdrawal(amount: Int) {
wallet.withdrawal(amount)
}
}

View File

@@ -0,0 +1,13 @@
package com.banjjoknim.soliddesignpatternsample.designpattern.proxy.after
open class RealWallet(
private var balance: Int = 0
) : Wallet {
override fun deposit(amount: Int) {
this.balance += amount
}
override fun withdrawal(amount: Int) {
this.balance -= amount
}
}

View File

@@ -0,0 +1,7 @@
package com.banjjoknim.soliddesignpatternsample.designpattern.proxy.after
interface Wallet {
fun deposit(amount: Int)
fun withdrawal(amount: Int)
}

View File

@@ -0,0 +1,9 @@
package com.banjjoknim.soliddesignpatternsample.designpattern.proxy.after
class ProxyWalletApplication
fun main() {
val wallet = ImplementsProxyWallet(RealWallet())
val owner = Owner(wallet)
owner.deposit(1000)
}

View File

@@ -0,0 +1,13 @@
package com.banjjoknim.soliddesignpatternsample.designpattern.proxy.before
class Owner(
private val wallet: Wallet
) {
fun deposit(amount: Int) {
wallet.deposit(amount)
}
fun withdrawal(amount: Int) {
wallet.withdrawal(amount)
}
}

View File

@@ -0,0 +1,15 @@
package com.banjjoknim.soliddesignpatternsample.designpattern.proxy.before
class Wallet(
private var balance: Int = 0
) {
fun deposit(amount: Int) {
println("지갑에 $amount 원이 입금되었습니다.")
this.balance += amount
}
fun withdrawal(amount: Int) {
println("지갑에서 $amount 원이 출금되었습니다.")
this.balance -= amount
}
}

View File

@@ -0,0 +1,9 @@
package com.banjjoknim.soliddesignpatternsample.designpattern.proxy.before
class WalletApplication
fun main() {
val wallet = Wallet()
val owner = Owner(wallet)
owner.deposit(1000)
}

View File

@@ -0,0 +1,13 @@
package com.banjjoknim.soliddesignpatternsample.designpattern.state.after
class GameCharacter(
private var state: State = StoppingState()
) {
fun move() {
state.move(this)
}
fun changeState(newState: State) {
this.state = newState
}
}

View File

@@ -0,0 +1,10 @@
package com.banjjoknim.soliddesignpatternsample.designpattern.state.after
class GameCharacterApplicationAfter
fun main() {
val gameCharacter = GameCharacter()
gameCharacter.move()
gameCharacter.move()
gameCharacter.move()
}

View File

@@ -0,0 +1,5 @@
package com.banjjoknim.soliddesignpatternsample.designpattern.state.after
interface State {
fun move(gameCharacter: GameCharacter)
}

View File

@@ -0,0 +1,22 @@
package com.banjjoknim.soliddesignpatternsample.designpattern.state.after
class StoppingState : State {
override fun move(gameCharacter: GameCharacter) {
println("캐릭터가 이동한다.")
gameCharacter.changeState(MovingState())
}
}
class MovingState : State {
override fun move(gameCharacter: GameCharacter) {
println("캐릭터가 점프한다.")
gameCharacter.changeState(JumpingState())
}
}
class JumpingState : State {
override fun move(gameCharacter: GameCharacter) {
println("캐릭터가 착지한 뒤 정지한다.")
gameCharacter.changeState(StoppingState())
}
}

View File

@@ -0,0 +1,22 @@
package com.banjjoknim.soliddesignpatternsample.designpattern.state.before
class GameCharacter(
private var state: State = State.STOPPING
) {
fun move() {
when (state) {
State.STOPPING -> {
println("캐릭터가 이동한다.")
this.state = State.MOVING
}
State.MOVING -> {
println("캐릭터가 점프한다.")
this.state = State.JUMPING
}
State.JUMPING -> {
println("캐릭터가 착지한 뒤 정지한다.")
this.state = State.STOPPING
}
}
}
}

View File

@@ -0,0 +1,10 @@
package com.banjjoknim.soliddesignpatternsample.designpattern.state.before
class GameCharacterApplicationBefore
fun main() {
val gameCharacter = GameCharacter()
gameCharacter.move()
gameCharacter.move()
gameCharacter.move()
}

View File

@@ -0,0 +1,7 @@
package com.banjjoknim.soliddesignpatternsample.designpattern.state.before
enum class State {
STOPPING,
MOVING,
JUMPING,
}

Some files were not shown because too many files have changed in this diff Show More