From b0cc0d1d9fd526c6705b6b80299f8c7c0fd6cfa5 Mon Sep 17 00:00:00 2001 From: MaybeLemon Date: Tue, 16 Jun 2026 17:25:23 +0900 Subject: [PATCH 1/6] =?UTF-8?q?260616=5F=EC=97=B0=EC=8A=B5=EB=AC=B8?= =?UTF-8?q?=EC=A0=9C1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...\354\227\260\354\212\265\353\254\270\354\240\2341" | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 "game/src/main/java/com/survivalcoding/260616_\354\227\260\354\212\265\353\254\270\354\240\2341" diff --git "a/game/src/main/java/com/survivalcoding/260616_\354\227\260\354\212\265\353\254\270\354\240\2341" "b/game/src/main/java/com/survivalcoding/260616_\354\227\260\354\212\265\353\254\270\354\240\2341" new file mode 100644 index 0000000..1d6bb91 --- /dev/null +++ "b/game/src/main/java/com/survivalcoding/260616_\354\227\260\354\212\265\353\254\270\354\240\2341" @@ -0,0 +1,11 @@ +다음 중에서 "잘못 된 상속"인 것을 모두 구하시오 + 슈퍼클래스 서브클래스 +1 Person Student +2 Car Engine +3 Father Child +4 Food Susi +5 SuperMan Man + +예) Man extends SuperMan: X + +답) 2, 3, 5 \ No newline at end of file From 927c307faeb5b127e977b70065c06ef5449d0ecf Mon Sep 17 00:00:00 2001 From: MaybeLemon Date: Tue, 16 Jun 2026 17:34:14 +0900 Subject: [PATCH 2/6] =?UTF-8?q?260616=5F=EC=97=B0=EC=8A=B5=EB=AC=B8?= =?UTF-8?q?=EC=A0=9C2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...16_\354\227\260\354\212\265\353\254\270\354\240\2342" | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 "game/src/main/java/com/survivalcoding/260616_\354\227\260\354\212\265\353\254\270\354\240\2342" diff --git "a/game/src/main/java/com/survivalcoding/260616_\354\227\260\354\212\265\353\254\270\354\240\2342" "b/game/src/main/java/com/survivalcoding/260616_\354\227\260\354\212\265\353\254\270\354\240\2342" new file mode 100644 index 0000000..ea080b9 --- /dev/null +++ "b/game/src/main/java/com/survivalcoding/260616_\354\227\260\354\212\265\353\254\270\354\240\2342" @@ -0,0 +1,9 @@ +다음 클래스에 대해 "부모 클래스"와 "자식 클래스"를 1개씩 생각 해 보시오. + +예) Character <- Hero <- SuperHero + +1. [Device] <- Phone <- [SmartPhone] + +2. [Vehicle] <- Car <- [SportsCar] + +3. [Book] <- Dictionary <- [Korean Dictionary] \ No newline at end of file From 5633f039ea335008109f1864a17839b9ea601818 Mon Sep 17 00:00:00 2001 From: MaybeLemon Date: Tue, 16 Jun 2026 17:45:00 +0900 Subject: [PATCH 3/6] =?UTF-8?q?260616=5F=EC=97=B0=EC=8A=B5=EB=AC=B8?= =?UTF-8?q?=EC=A0=9C3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...354\212\265\353\254\270\354\240\2343.puml" | 34 ++++++++ .../java/com/survivalcoding/PoisonSlime.java | 31 ++++++++ .../main/java/com/survivalcoding/Slime.java | 32 ++++++++ .../com/survivalcoding/PoisonSlimeTest.java | 78 +++++++++++++++++++ .../java/com/survivalcoding/SlimeTest.java | 31 ++++++++ 5 files changed, 206 insertions(+) create mode 100644 "game/260616_\354\227\260\354\212\265\353\254\270\354\240\2343.puml" create mode 100644 game/src/main/java/com/survivalcoding/PoisonSlime.java create mode 100644 game/src/main/java/com/survivalcoding/Slime.java create mode 100644 game/src/test/java/com/survivalcoding/PoisonSlimeTest.java create mode 100644 game/src/test/java/com/survivalcoding/SlimeTest.java diff --git "a/game/260616_\354\227\260\354\212\265\353\254\270\354\240\2343.puml" "b/game/260616_\354\227\260\354\212\265\353\254\270\354\240\2343.puml" new file mode 100644 index 0000000..26889db --- /dev/null +++ "b/game/260616_\354\227\260\354\212\265\353\254\270\354\240\2343.puml" @@ -0,0 +1,34 @@ +@startuml + +class Slime { + ~ final suffix : String + ~ hp : int + ~ slimeDamage : int + + + Slime(suffix : String) + + getSuffix() : String + + getHp() : int + + setHp(hp : int) : void + ~ attack(hero : Hero) : void +} + +class PoisonSlime { + - poisonCount : int + + + PoisonSlime(suffix : String) + ~ attack(hero : Hero) : void + + getPoisonCount() : int +} + +class Hero { + - hp : int + + + getHp() : int + + setHp(hp : int) : void +} + +PoisonSlime --|> Slime +Slime ..> Hero : attack(hero) +PoisonSlime ..> Hero : attack(hero) + +@enduml \ No newline at end of file diff --git a/game/src/main/java/com/survivalcoding/PoisonSlime.java b/game/src/main/java/com/survivalcoding/PoisonSlime.java new file mode 100644 index 0000000..0ce255a --- /dev/null +++ b/game/src/main/java/com/survivalcoding/PoisonSlime.java @@ -0,0 +1,31 @@ +package com.survivalcoding; + +public class PoisonSlime extends Slime { + private static final int INITIAL_POISON_COUNT = 5; + private static final int POISON_DAMAGE_DIVISOR = 5; + + private int poisonCount = INITIAL_POISON_COUNT; + + public PoisonSlime(String suffix) { + super(suffix); + } + + @Override + void attack(Hero hero) { + super.attack(hero); + if (poisonCount > 0) { + System.out.println("추가로, 독 포자를 살포했다!"); + + int poisonDamage = hero.getHp() / POISON_DAMAGE_DIVISOR; + hero.setHp(hero.getHp() - poisonDamage); + + System.out.println(poisonDamage + "포인트 데미지"); + + poisonCount--; + } + } + + public int getPoisonCount() { + return poisonCount; + } +} diff --git a/game/src/main/java/com/survivalcoding/Slime.java b/game/src/main/java/com/survivalcoding/Slime.java new file mode 100644 index 0000000..e388ff3 --- /dev/null +++ b/game/src/main/java/com/survivalcoding/Slime.java @@ -0,0 +1,32 @@ +package com.survivalcoding; + +public class Slime { + private static final int DEFAULT_HP = 50; + private static final int ATTACK_DAMAGE = 10; + + final String suffix; + int hp = DEFAULT_HP; + + public Slime(String suffix) { + this.suffix = suffix; + } + + public String getSuffix() { + return suffix; + } + + public int getHp() { + return hp; + } + + public void setHp(int hp) { + this.hp = hp; + } + + void attack(Hero hero) { + System.out.println("슬라임 " + suffix + "이/가 공격했다"); + System.out.println(ATTACK_DAMAGE + "의 데미지"); + + hero.setHp(hero.getHp() - ATTACK_DAMAGE); + } +} diff --git a/game/src/test/java/com/survivalcoding/PoisonSlimeTest.java b/game/src/test/java/com/survivalcoding/PoisonSlimeTest.java new file mode 100644 index 0000000..f436054 --- /dev/null +++ b/game/src/test/java/com/survivalcoding/PoisonSlimeTest.java @@ -0,0 +1,78 @@ +package com.survivalcoding; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +class PoisonSlimeTest { + + @Test + @DisplayName("PoisonSlime은 Slime을 상속받는다") + void poisonSlimeIsSlime() { + PoisonSlime poisonSlime = new PoisonSlime("A"); + + assertInstanceOf(Slime.class, poisonSlime); + } + + @Test + @DisplayName("PoisonSlime은 suffix를 받아 생성되고 poisonCount 초기값은 5이다") + void poisonSlimeConstructorTest() { + PoisonSlime poisonSlime = new PoisonSlime("A"); + + assertEquals("A", poisonSlime.getSuffix()); + assertEquals(5, poisonSlime.getPoisonCount()); + } + + @Test + @DisplayName("PoisonSlime은 일반 공격 후 독 공격을 한다") + void poisonSlimeAttackTest() { + PoisonSlime poisonSlime = new PoisonSlime("A"); + + Hero hero = new Hero(); + hero.setHp(100); + + poisonSlime.attack(hero); + + assertEquals(72, hero.getHp()); + assertEquals(4, poisonSlime.getPoisonCount()); + } + + @Test + @DisplayName("독 데미지는 소수점 이하를 버린다") + void poisonDamageFloorTest() { + PoisonSlime poisonSlime = new PoisonSlime("A"); + + Hero hero = new Hero(); + hero.setHp(83); + + poisonSlime.attack(hero); + + assertEquals(59, hero.getHp()); + assertEquals(4, poisonSlime.getPoisonCount()); + } + + @Test + @DisplayName("독 공격은 poisonCount가 남아있을 때만 실행된다") + void poisonAttackLimitTest() { + PoisonSlime poisonSlime = new PoisonSlime("A"); + + Hero hero = new Hero(); + hero.setHp(1000); + + poisonSlime.attack(hero); + poisonSlime.attack(hero); + poisonSlime.attack(hero); + poisonSlime.attack(hero); + poisonSlime.attack(hero); + + assertEquals(0, poisonSlime.getPoisonCount()); + + int beforeHp = hero.getHp(); + + poisonSlime.attack(hero); + + assertEquals(beforeHp - 10, hero.getHp()); + assertEquals(0, poisonSlime.getPoisonCount()); + } +} \ No newline at end of file diff --git a/game/src/test/java/com/survivalcoding/SlimeTest.java b/game/src/test/java/com/survivalcoding/SlimeTest.java new file mode 100644 index 0000000..26e1355 --- /dev/null +++ b/game/src/test/java/com/survivalcoding/SlimeTest.java @@ -0,0 +1,31 @@ +package com.survivalcoding; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +class SlimeTest { + + @Test + @DisplayName("Slime은 suffix를 받아 생성된다") + void slimeConstructorTest() { + Slime slime = new Slime("A"); + + assertEquals("A", slime.getSuffix()); + assertEquals(50, slime.getHp()); + } + + @Test + @DisplayName("Slime이 공격하면 용사의 HP가 10 감소한다") + void slimeAttackTest() { + Slime slime = new Slime("A"); + + Hero hero = new Hero(); + hero.setHp(100); + + slime.attack(hero); + + assertEquals(90, hero.getHp()); + } +} \ No newline at end of file From 46ee0e4baa6e377f64c5eaefe6691d6b583c0d84 Mon Sep 17 00:00:00 2001 From: MaybeLemon Date: Tue, 16 Jun 2026 18:03:15 +0900 Subject: [PATCH 4/6] =?UTF-8?q?260616=5F=EC=97=B0=EC=8A=B5=EB=AC=B8?= =?UTF-8?q?=EC=A0=9C4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...354\212\265\353\254\270\354\240\2343.puml" | 0 ...354\212\265\353\254\270\354\240\2344.puml" | 44 +++ .../main/java/com/survivalcoding/Wizard.java | 18 +- .../java/com/survivalcoding/WizardTest.java | 258 ++++++++++++------ 4 files changed, 229 insertions(+), 91 deletions(-) rename "game/260616_\354\227\260\354\212\265\353\254\270\354\240\2343.puml" => "game/puml/260616_\354\227\260\354\212\265\353\254\270\354\240\2343.puml" (100%) create mode 100644 "game/puml/260616_\354\227\260\354\212\265\353\254\270\354\240\2344.puml" diff --git "a/game/260616_\354\227\260\354\212\265\353\254\270\354\240\2343.puml" "b/game/puml/260616_\354\227\260\354\212\265\353\254\270\354\240\2343.puml" similarity index 100% rename from "game/260616_\354\227\260\354\212\265\353\254\270\354\240\2343.puml" rename to "game/puml/260616_\354\227\260\354\212\265\353\254\270\354\240\2343.puml" diff --git "a/game/puml/260616_\354\227\260\354\212\265\353\254\270\354\240\2344.puml" "b/game/puml/260616_\354\227\260\354\212\265\353\254\270\354\240\2344.puml" new file mode 100644 index 0000000..d003763 --- /dev/null +++ "b/game/puml/260616_\354\227\260\354\212\265\353\254\270\354\240\2344.puml" @@ -0,0 +1,44 @@ +@startuml + +class Wizard { + - {static} INITIAL_MP : int + - {static} HEAL_POINT : int + - {static} HEAL_MP_COST : int + + - hp : int + - mp : int + - name : String + - wand : Wand + + + heal(hero : Hero) : void + + getHp() : int + + setHp(hp : int) : void + + getMp() : int + + setMp(mp : int) : void + + getName() : String + + setName(name : String) : void + + getWand() : Wand + + setWand(wand : Wand) : void +} + +class Wand { + - name : String + - power : double + + + getName() : String + + setName(name : String) : void + + getPower() : double + + setPower(power : double) : void +} + +class Hero { + - hp : int + + + getHp() : int + + setHp(hp : int) : void +} + +Wizard ..> Hero : heal(hero) +Wizard --> Wand : wand + +@enduml \ No newline at end of file diff --git a/game/src/main/java/com/survivalcoding/Wizard.java b/game/src/main/java/com/survivalcoding/Wizard.java index 94f19fd..dbf8d25 100644 --- a/game/src/main/java/com/survivalcoding/Wizard.java +++ b/game/src/main/java/com/survivalcoding/Wizard.java @@ -1,15 +1,25 @@ package com.survivalcoding; public class Wizard { + private static final int INITIAL_MP = 100; + private static final int HEAL_POINT = 20; + private static final int HEAL_MP_COST = 10; + private int hp; - private int mp; + private int mp = INITIAL_MP; private String name; private Wand wand; public void heal(Hero hero) { - int basePoint = 10; - int recovPoint = (int) (basePoint * this.wand.getPower()); - hero.setHp(hero.getHp() + recovPoint); + if (mp < HEAL_MP_COST) { + System.out.println("마나가 부족합니다"); + return; + } + + hero.setHp(hero.getHp() + HEAL_POINT); + mp -= HEAL_MP_COST; + + System.out.println("힐을 시전했습니다. 대상 HP: " + hero.getHp()); } public int getHp() { diff --git a/game/src/test/java/com/survivalcoding/WizardTest.java b/game/src/test/java/com/survivalcoding/WizardTest.java index b9180b4..d41459d 100644 --- a/game/src/test/java/com/survivalcoding/WizardTest.java +++ b/game/src/test/java/com/survivalcoding/WizardTest.java @@ -1,5 +1,8 @@ package com.survivalcoding; +import java.io.ByteArrayOutputStream; +import java.io.PrintStream; + import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -7,117 +10,198 @@ class WizardTest { +// @Test +// @DisplayName("Heal은 지팡이의 power 계수만큼 회복") +// void heal() { +// Wizard wizard = new Wizard(); +// +// Wand wand = new Wand(); +// wand.setName("기다란완드"); +// wand.setPower(1.0); +// +// wizard.setWand(wand); +// +// Hero hero = new Hero(); +// hero.setHp(30); +// +// wizard.heal(hero); +// +// assertEquals(40, hero.getHp()); +// } +// +// @Test +// @DisplayName("Wizard Hp Getter / Setter") +// void getHp() { +// Wizard wizard = new Wizard(); +// +// wizard.setHp(30); +// +// assertEquals(30, wizard.getHp()); +// } +// +// @Test +// @DisplayName("Wizard Mp Getter / Setter") +// void getMp() { +// Wizard wizard = new Wizard(); +// +// wizard.setMp(5); +// +// assertEquals(5, wizard.getMp()); +// } +// +// @Test +// @DisplayName("Wizard Name") +// void getName() { +// Wizard wizard = new Wizard(); +// +// wizard.setName("마법사"); +// +// assertEquals("마법사", wizard.getName()); +// } +// +// +// @Test +// @DisplayName("Wand 상세정보") +// void getWand() { +// Wizard wizard = new Wizard(); +// +// Wand wand = new Wand(); +// wand.setName("기다란완드"); +// wand.setPower(2.0); +// +// wizard.setWand(wand); +// +// assertSame(wand, wizard.getWand()); +// } +// +// @Test +// @DisplayName("마법사 이름은 null일 수 없다") +// void setName_null() { +// Wizard wizard = new Wizard(); +// +// assertThrows(IllegalArgumentException.class, () -> { +// wizard.setName(null); +// }); +// } +// +// @Test +// @DisplayName("마법사 이름은 3문자 이상이어야 한다") +// void setName_under3Characters() { +// Wizard wizard = new Wizard(); +// +// assertThrows(IllegalArgumentException.class, () -> { +// wizard.setName("ab"); +// }); +// } +// +// @Test +// @DisplayName("마법사의 지팡이는 null일 수 없다") +// void setWand_null() { +// Wizard wizard = new Wizard(); +// +// assertThrows(IllegalArgumentException.class, () -> { +// wizard.setWand(null); +// }); +// } +// +// @Test +// @DisplayName("마법사의 MP는 0 미만일 수 없다") +// void setMp_negative() { +// Wizard wizard = new Wizard(); +// +// assertThrows(IllegalArgumentException.class, () -> { +// wizard.setMp(-1); +// }); +// } +// +// @Test +// @DisplayName("마법사의 HP가 음수이면 0으로 설정된다") +// void setHp_negativeBecomesZero() { +// Wizard wizard = new Wizard(); +// +// wizard.setHp(-10); +// +// assertEquals(0, wizard.getHp()); +// } @Test - @DisplayName("Heal은 지팡이의 power 계수만큼 회복") - void heal() { + @DisplayName("마법사의 MP 초기값이 100인지 확인") + void wizardInitialMpTest() { Wizard wizard = new Wizard(); - Wand wand = new Wand(); - wand.setName("기다란완드"); - wand.setPower(1.0); - - wizard.setWand(wand); - - Hero hero = new Hero(); - hero.setHp(30); - - wizard.heal(hero); - - assertEquals(40, hero.getHp()); + assertEquals(100, wizard.getMp()); } - @Test - @DisplayName("Wizard Hp Getter / Setter") - void getHp() { - Wizard wizard = new Wizard(); + @Test + @DisplayName("힐을 사용하면 용사 HP가 20 회복되고 마법사 MP가 10 줄어드는지 확인") + void healSuccessTest() { + Wizard wizard = new Wizard(); - wizard.setHp(30); + Hero hero = new Hero(); + hero.setHp(100); - assertEquals(30, wizard.getHp()); - } + wizard.heal(hero); - @Test - @DisplayName("Wizard Mp Getter / Setter") - void getMp() { - Wizard wizard = new Wizard(); + assertEquals(120, hero.getHp()); + assertEquals(90, wizard.getMp()); + } - wizard.setMp(5); + @Test + @DisplayName("힐 성공했을 때 출력문이 잘 나오는지 확인") + void healSuccessPrintTest() { + Wizard wizard = new Wizard(); - assertEquals(5, wizard.getMp()); - } + Hero hero = new Hero(); + hero.setHp(100); - @Test - @DisplayName("Wizard Name") - void getName() { - Wizard wizard = new Wizard(); + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + PrintStream originalOut = System.out; + System.setOut(new PrintStream(outputStream)); - wizard.setName("마법사"); + wizard.heal(hero); - assertEquals("마법사", wizard.getName()); - } + System.setOut(originalOut); + String output = outputStream.toString(); - @Test - @DisplayName("Wand 상세정보") - void getWand() { - Wizard wizard = new Wizard(); + assertTrue(output.contains("힐을 시전했습니다. 대상 HP: 120")); + } - Wand wand = new Wand(); - wand.setName("기다란완드"); - wand.setPower(2.0); + @Test + @DisplayName("MP가 부족하면 힐이 안 되고 마나 부족 메시지가 나오는지 확인") + void healFailByLackOfMpTest() { + Wizard wizard = new Wizard(); + wizard.setMp(5); - wizard.setWand(wand); + Hero hero = new Hero(); + hero.setHp(100); - assertSame(wand, wizard.getWand()); - } + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + PrintStream originalOut = System.out; + System.setOut(new PrintStream(outputStream)); - @Test - @DisplayName("마법사 이름은 null일 수 없다") - void setName_null() { - Wizard wizard = new Wizard(); + wizard.heal(hero); - assertThrows(IllegalArgumentException.class, () -> { - wizard.setName(null); - }); - } + System.setOut(originalOut); - @Test - @DisplayName("마법사 이름은 3문자 이상이어야 한다") - void setName_under3Characters() { - Wizard wizard = new Wizard(); + String output = outputStream.toString(); - assertThrows(IllegalArgumentException.class, () -> { - wizard.setName("ab"); - }); - } + assertEquals(100, hero.getHp()); + assertEquals(5, wizard.getMp()); + assertTrue(output.contains("마나가 부족합니다")); + } - @Test - @DisplayName("마법사의 지팡이는 null일 수 없다") - void setWand_null() { - Wizard wizard = new Wizard(); + @Test + @DisplayName("MP가 딱 10일 때 힐이 되는지 확인") + void healWhenMpIsExactlyTenTest() { + Wizard wizard = new Wizard(); + wizard.setMp(10); - assertThrows(IllegalArgumentException.class, () -> { - wizard.setWand(null); - }); - } + Hero hero = new Hero(); + hero.setHp(50); - @Test - @DisplayName("마법사의 MP는 0 미만일 수 없다") - void setMp_negative() { - Wizard wizard = new Wizard(); - - assertThrows(IllegalArgumentException.class, () -> { - wizard.setMp(-1); - }); - } - - @Test - @DisplayName("마법사의 HP가 음수이면 0으로 설정된다") - void setHp_negativeBecomesZero() { - Wizard wizard = new Wizard(); + wizard.heal(hero); - wizard.setHp(-10); - - assertEquals(0, wizard.getHp()); - } + assertEquals(70, hero.getHp()); + assertEquals(0, wizard.getMp()); + } } \ No newline at end of file From ec9c7eb610ab45894ce706285d6202e5c2eb6bdd Mon Sep 17 00:00:00 2001 From: MaybeLemon Date: Tue, 16 Jun 2026 18:12:10 +0900 Subject: [PATCH 5/6] =?UTF-8?q?260616=5F=EC=97=B0=EC=8A=B5=EB=AC=B8?= =?UTF-8?q?=EC=A0=9C5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...4\212\265\353\254\270\354\240\2344-5.puml" | 45 +++++-- .../java/com/survivalcoding/GreatWizard.java | 37 +++++ .../main/java/com/survivalcoding/Hero.java | 4 +- .../com/survivalcoding/GreatWizardTest.java | 126 ++++++++++++++++++ 4 files changed, 197 insertions(+), 15 deletions(-) rename "game/puml/260616_\354\227\260\354\212\265\353\254\270\354\240\2344.puml" => "game/puml/260616_\354\227\260\354\212\265\353\254\270\354\240\2344-5.puml" (65%) create mode 100644 game/src/main/java/com/survivalcoding/GreatWizard.java create mode 100644 game/src/test/java/com/survivalcoding/GreatWizardTest.java diff --git "a/game/puml/260616_\354\227\260\354\212\265\353\254\270\354\240\2344.puml" "b/game/puml/260616_\354\227\260\354\212\265\353\254\270\354\240\2344-5.puml" similarity index 65% rename from "game/puml/260616_\354\227\260\354\212\265\353\254\270\354\240\2344.puml" rename to "game/puml/260616_\354\227\260\354\212\265\353\254\270\354\240\2344-5.puml" index d003763..9fd4a3c 100644 --- "a/game/puml/260616_\354\227\260\354\212\265\353\254\270\354\240\2344.puml" +++ "b/game/puml/260616_\354\227\260\354\212\265\353\254\270\354\240\2344-5.puml" @@ -1,5 +1,24 @@ @startuml +class Hero { + - name : String + - hp : int + + ~ attack() : void + + getHp() : int + + setHp(hp : int) : void +} + +class Wand { + - name : String + - power : double + + + getName() : String + + setName(name : String) : void + + getPower() : double + + setPower(power : double) : void +} + class Wizard { - {static} INITIAL_MP : int - {static} HEAL_POINT : int @@ -21,24 +40,22 @@ class Wizard { + setWand(wand : Wand) : void } -class Wand { - - name : String - - power : double +class GreatWizard { + - {static} INITIAL_MP : int + - {static} HEAL_POINT : int + - {static} HEAL_MP_COST : int + - {static} SUPER_HEAL_MP_COST : int + - {static} HERO_MAX_HP : int - + getName() : String - + setName(name : String) : void - + getPower() : double - + setPower(power : double) : void + + GreatWizard() + + heal(hero : Hero) : void + + superHeal(hero : Hero) : void } -class Hero { - - hp : int +GreatWizard --|> Wizard - + getHp() : int - + setHp(hp : int) : void -} - -Wizard ..> Hero : heal(hero) Wizard --> Wand : wand +Wizard ..> Hero : heal(hero) +GreatWizard ..> Hero : heal(hero), superHeal(hero) @enduml \ No newline at end of file diff --git a/game/src/main/java/com/survivalcoding/GreatWizard.java b/game/src/main/java/com/survivalcoding/GreatWizard.java new file mode 100644 index 0000000..2bd1f96 --- /dev/null +++ b/game/src/main/java/com/survivalcoding/GreatWizard.java @@ -0,0 +1,37 @@ +package com.survivalcoding; + +public class GreatWizard extends Wizard { + private static final int INITIAL_MP = 150; + private static final int HEAL_POINT = 25; + private static final int HEAL_MP_COST = 5; + private static final int SUPER_HEAL_MP_COST = 50; + + public GreatWizard() { + setMp(INITIAL_MP); + } + + @Override + public void heal(Hero hero) { + if (getMp() < HEAL_MP_COST) { + System.out.println("마나가 부족합니다"); + return; + } + + hero.setHp(hero.getHp() + HEAL_POINT); + setMp(getMp() - HEAL_MP_COST); + + System.out.println("힐을 시전했습니다. 대상 HP: " + hero.getHp()); + } + + public void superHeal(Hero hero) { + if (getMp() < SUPER_HEAL_MP_COST) { + System.out.println("마나가 부족합니다"); + return; + } + + hero.setHp(Hero.MAX_HP); + setMp(getMp() - SUPER_HEAL_MP_COST); + + System.out.println("슈퍼 힐을 시전했습니다. 대상 HP: " + hero.getHp()); + } +} \ No newline at end of file diff --git a/game/src/main/java/com/survivalcoding/Hero.java b/game/src/main/java/com/survivalcoding/Hero.java index 37d8e15..d0de0cb 100644 --- a/game/src/main/java/com/survivalcoding/Hero.java +++ b/game/src/main/java/com/survivalcoding/Hero.java @@ -1,6 +1,8 @@ package com.survivalcoding; public class Hero { + public static final int MAX_HP = 100; + private String name; private int hp; @@ -15,4 +17,4 @@ public int getHp() { public void setHp(int hp) { this.hp = hp; } -} +} \ No newline at end of file diff --git a/game/src/test/java/com/survivalcoding/GreatWizardTest.java b/game/src/test/java/com/survivalcoding/GreatWizardTest.java new file mode 100644 index 0000000..a910add --- /dev/null +++ b/game/src/test/java/com/survivalcoding/GreatWizardTest.java @@ -0,0 +1,126 @@ +package com.survivalcoding; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import java.io.ByteArrayOutputStream; +import java.io.PrintStream; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +class GreatWizardTest { + + @Test + @DisplayName("GreatWizard가 Wizard를 상속받는지 확인") + void greatWizardIsWizardTest() { + GreatWizard greatWizard = new GreatWizard(); + + assertTrue(greatWizard instanceof Wizard); + } + + @Test + @DisplayName("GreatWizard의 MP 초기값이 150인지 확인") + void greatWizardInitialMpTest() { + GreatWizard greatWizard = new GreatWizard(); + + assertEquals(150, greatWizard.getMp()); + } + + @Test + @DisplayName("heal을 사용하면 HP가 25 회복되고 MP가 5 줄어드는지 확인") + void healSuccessTest() { + GreatWizard greatWizard = new GreatWizard(); + + Hero hero = new Hero(); + hero.setHp(100); + + greatWizard.heal(hero); + + assertEquals(125, hero.getHp()); + assertEquals(145, greatWizard.getMp()); + } + + @Test + @DisplayName("superHeal을 사용하면 HP가 최대로 회복되고 MP가 50 줄어드는지 확인") + void superHealSuccessTest() { + GreatWizard greatWizard = new GreatWizard(); + + Hero hero = new Hero(); + hero.setHp(30); + + greatWizard.superHeal(hero); + + assertEquals(100, hero.getHp()); + assertEquals(100, greatWizard.getMp()); + } + + @Test + @DisplayName("superHeal 성공했을 때 출력문이 잘 나오는지 확인") + void superHealPrintTest() { + GreatWizard greatWizard = new GreatWizard(); + + Hero hero = new Hero(); + hero.setHp(30); + + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + PrintStream originalOut = System.out; + System.setOut(new PrintStream(outputStream)); + + greatWizard.superHeal(hero); + + System.setOut(originalOut); + + String output = outputStream.toString(); + + assertTrue(output.contains("슈퍼 힐을 시전했습니다. 대상 HP: 100")); + } + + @Test + @DisplayName("MP가 부족하면 heal이 안 되고 마나 부족 메시지가 나오는지 확인") + void healFailByLackOfMpTest() { + GreatWizard greatWizard = new GreatWizard(); + greatWizard.setMp(4); + + Hero hero = new Hero(); + hero.setHp(100); + + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + PrintStream originalOut = System.out; + System.setOut(new PrintStream(outputStream)); + + greatWizard.heal(hero); + + System.setOut(originalOut); + + String output = outputStream.toString(); + + assertEquals(100, hero.getHp()); + assertEquals(4, greatWizard.getMp()); + assertTrue(output.contains("마나가 부족합니다")); + } + + @Test + @DisplayName("MP가 부족하면 superHeal이 안 되고 마나 부족 메시지가 나오는지 확인") + void superHealFailByLackOfMpTest() { + GreatWizard greatWizard = new GreatWizard(); + greatWizard.setMp(49); + + Hero hero = new Hero(); + hero.setHp(30); + + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + PrintStream originalOut = System.out; + System.setOut(new PrintStream(outputStream)); + + greatWizard.superHeal(hero); + + System.setOut(originalOut); + + String output = outputStream.toString(); + + assertEquals(30, hero.getHp()); + assertEquals(49, greatWizard.getMp()); + assertTrue(output.contains("마나가 부족합니다")); + } +} \ No newline at end of file From cc97938085026375943e6cdb5f3a9229791ae40e Mon Sep 17 00:00:00 2001 From: MaybeLemon Date: Tue, 16 Jun 2026 18:49:59 +0900 Subject: [PATCH 6/6] =?UTF-8?q?260616=5F=EC=83=81=EC=86=8D.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- "TIL/2026-06-16-\354\203\201\354\206\215.md" | 270 +++++++++++++++++++ 1 file changed, 270 insertions(+) create mode 100644 "TIL/2026-06-16-\354\203\201\354\206\215.md" diff --git "a/TIL/2026-06-16-\354\203\201\354\206\215.md" "b/TIL/2026-06-16-\354\203\201\354\206\215.md" new file mode 100644 index 0000000..3afdca8 --- /dev/null +++ "b/TIL/2026-06-16-\354\203\201\354\206\215.md" @@ -0,0 +1,270 @@ +# 2026-06-16 상속 + +## 오늘 배운 내용 + +- 상속 + - 기존 클래스를 바탕으로 새로운 클래스를 만드는 기능 + - "extends" 키워드를 사용해서 부모 클래스를 상속받음 + - 부모 클래스에 있는 필드와 메서드는 자식 클래스에서 사용할 수 있음 + - 자식 클래스에는 부모 클래스에 없는 기능을 추가로 작성할 수 있음 + - 상속 관계는 보통 "자식 클래스 is-a 부모 클래스" 관계일 때 사용 + - 예제 + - public class Hero { // 부모 클래스 + String name; + int hp; + + public void attack() { + } + } + + public class SuperHero extends Hero { 자식 클래스 + boolean flying; + + public void fly() { + flying = true; + } + } + SuperHero sh = new SuperHero(); + + sh.name = "슈퍼맨"; // 부모 클래스의 필드 사용 + sh.hp = 100; // 〃 의 필드 사용 + sh.attack(); // 〃 의 메서드 사용 + sh.fly(); // 자식 클래스에서 추가한 메서드 사용 + +- Override + - Override는 부모 클래스에 있는 메서드를 자식 클래스에서 다시 정의하는 것 + - 같은 이름, 같은 매개변수, 같은 반환 타입으로 작성해야 함 + - 자식 클래스에서 재정의한 메서드가 우선적으로 실행됨 + - @Override를 붙이면 오타나 형식 오류를 컴파일러가 확인해줘서 좋음 + - 예제 + - public class Hero { + public void run() { + System.out.println("도망쳤다."); + } + } + public class SuperHero extends Hero { + @Override + public void run() { + System.out.println("하늘을 날아서 도망쳤다."); + } + } + - 출력: 하늘을 날아서 도망쳤다. + +- super와 생성자 호출 순서 + - super는 부모 클래스의 멤버에 접근할 때 사용 + - super.메서드명()을 사용하면 부모 클래스의 메서드를 호출할 수 있음 + - super()는 부모 클래스의 생성자를 호출할 때 사용 + - 자식 클래스의 객체가 생성될 때는 부모 생성자가 먼저 실행되고, 그 다음 자식 생성자가 실행됨 + - 자식 생성자 안에 super()를 직접 작성하지 않으면, 컴파일러가 자동으로 super()를 추가 + - super() 또는 super(값)은 생성자 안에서 첫 줄에 작성해야 함 + - 예제 + - public class Hero { + public Hero() { + System.out.println("부모 생성자 실행"); + } + } + + public class SuperHero extends Hero { + public SuperHero() { + super(); + System.out.println("자식 생성자 실행"); + } + } + + - SuperHero sh = new SuperHero(); 를 실행하면 생성자가 호출된다. + - 호출 순서는 부모 생성자 -> 자식 생성자 순서이다. + - 출력: 부모 생성자 실행 + 자식 생성자 실행 + + - 부모 생성자에 매개변수가 있을 경우 + - 부모 클래스에 기본 생성자가 없고, 매개변수가 있는 생성자만 있다면 + 자식 클래스에서 반드시 super(값)을 작성해야 한다. + - 예제 + - public class Hero { + String name; + + public Hero(String name) { + this.name = name; + } + } + public class SuperHero extends Hero { + public SuperHero(String name) { + super(name); + } + + - SuperHero sh = new SuperHero("슈퍼맨"); 를 실행하면 + "슈퍼맨" 값이 super(name)을 통해 부모 생성자로 전달된다. + - 즉, SuperHero 생성자가 실행되기 전에 부모 클래스인 Hero의 생성자가 먼저 실행된다. + + - 정리 + - 생성자 호출 순서는 항상 부모 생성자 -> 자식 생성자 이다. + - 부모 생성자에 필요한 값이 있다면 자식 생성자에서 super(name)처럼 값을 넘겨줘야 한다. + +## 기억할 것 + +- 상속은 기존 클래스의 기능을 재사용하기 위해 사용 +- extends를 사용해서 부모 클래스를 상속받음 +- 부모 클래스의 필드와 메서드는 자식 클래스에서 사용할 수 있음 +- 부모 메서드를 자식 클래스에서 다시 작성하는 것을 오버라이드라고 함 +- super는 부모 클래스의 메서드나 생성자를 호출할 때 사용함 +- 생성자는 상속되지 않지만, 자식 객체가 생성될 때 부모 생성자가 먼저 실행됨 +- final이 붙은 클래스는 상속할 수 없고, final이 붙은 메서드는 오버라이드할 수 없음 + +## 실습 코드 + +```java +package com.survivalcoding; + +public class Slime { + private static final int DEFAULT_HP = 50; + private static final int ATTACK_DAMAGE = 10; + + final String suffix; + int hp = DEFAULT_HP; + + public Slime(String suffix) { + this.suffix = suffix; + } + + public String getSuffix() { + return suffix; + } + + public int getHp() { + return hp; + } + + public void setHp(int hp) { + this.hp = hp; + } + + void attack(Hero hero) { + System.out.println("슬라임 " + suffix + "이/가 공격했다"); + System.out.println(ATTACK_DAMAGE + "의 데미지"); + + hero.setHp(hero.getHp() - ATTACK_DAMAGE); + } +} + +public class PoisonSlime extends Slime { + private static final int INITIAL_POISON_COUNT = 5; + private static final int POISON_DAMAGE_DIVISOR = 5; + + private int poisonCount = INITIAL_POISON_COUNT; + + public PoisonSlime(String suffix) { + super(suffix); + } + + @Override + void attack(Hero hero) { + super.attack(hero); + if (poisonCount > 0) { + System.out.println("추가로, 독 포자를 살포했다!"); + + int poisonDamage = hero.getHp() / POISON_DAMAGE_DIVISOR; + hero.setHp(hero.getHp() - poisonDamage); + + System.out.println(poisonDamage + "포인트 데미지"); + + poisonCount--; + } + } + + public int getPoisonCount() { + return poisonCount; + } +} +public class Wizard { + private static final int INITIAL_MP = 100; + private static final int HEAL_POINT = 20; + private static final int HEAL_MP_COST = 10; + + private int hp; + private int mp = INITIAL_MP; + private String name; + private Wand wand; + + public void heal(Hero hero) { + if (mp < HEAL_MP_COST) { + System.out.println("마나가 부족합니다"); + return; + } + + hero.setHp(hero.getHp() + HEAL_POINT); + mp -= HEAL_MP_COST; + + System.out.println("힐을 시전했습니다. 대상 HP: " + hero.getHp()); + } + + public int getMp() { + return mp; + } + public void setMp(int mp) { + if (mp < 0) { + throw new IllegalArgumentException("마법사의 MP는 0 이상이어야 한다."); + } + this.mp = mp; + } +} + +public class GreatWizard extends Wizard { + private static final int INITIAL_MP = 150; + private static final int HEAL_POINT = 25; + private static final int HEAL_MP_COST = 5; + private static final int SUPER_HEAL_MP_COST = 50; + + public GreatWizard() { + setMp(INITIAL_MP); + } + + @Override + public void heal(Hero hero) { + if (getMp() < HEAL_MP_COST) { + System.out.println("마나가 부족합니다"); + return; + } + + hero.setHp(hero.getHp() + HEAL_POINT); + setMp(getMp() - HEAL_MP_COST); + + System.out.println("힐을 시전했습니다. 대상 HP: " + hero.getHp()); + } + + public void superHeal(Hero hero) { + if (getMp() < SUPER_HEAL_MP_COST) { + System.out.println("마나가 부족합니다"); + return; + } + + hero.setHp(Hero.MAX_HP); + setMp(getMp() - SUPER_HEAL_MP_COST); + + System.out.println("슈퍼 힐을 시전했습니다. 대상 HP: " + hero.getHp()); + } +} +``` + +## 어려웠던 점 + +- 상수로 빼야 하는 값과 그냥 숫자로 써도 되는 값을 구분하는 게 아직 익숙하지 않았다. +- Override를 할 때 메서드 이름, 매개변수, 반환 타입이 부모 클래스랑 똑같아야 한다는 점이 헷갈렸다. +- super.attack(hero)처럼 부모 클래스의 메서드를 먼저 실행하고, 그 뒤에 추가 기능을 작성하는 흐름이 처음에는 어려웠다. +- PoisonSlime에서 일반 공격을 먼저 하고, 남은 HP를 기준으로 독 데미지를 계산하는 부분이 조금 어려웠다. + +## 해결 방법 + +- 반복해서 사용하는 숫자나 의미가 있는 숫자는 상수로 빼서 이름을 붙이려고 했다. +- Override는 @Override를 붙여서 오타나 형식이 틀렸을 때 바로 확인할 수 있게 했다. +- super.attack(hero)를 사용하면 부모 클래스의 공격을 먼저 실행하고, + 그 다음에 독 공격 같은 추가 기능을 넣을 수 있다는 식으로 이해했다. +- 테스트 코드를 작성하면서 일반 공격 데미지와 독 데미지가 순서대로 잘 적용되는지 확인했다. + +## 내일 더 공부할 것 + +- 상속을 써야 하는 경우와 그냥 클래스를 따로 만드는 경우의 차이를 더 공부할 것이다. +- Override와 Overload의 차이가 아직 헷갈려서 예제로 다시 정리해볼 것이다. +- super()와 super.메서드명()의 차이를 더 확실하게 공부할 것이다. +- 상수와 매직넘버를 구분해서 코드에 적용하는 방법을 더 연습할 것이다. +- 부모 생성자와 자식 생성자의 호출 순서를 코드로 더 연습해볼 것이다. +- JUnit으로 상속과 오버라이드가 제대로 동작하는지 테스트하는 방법을 더 연습할 것이다.