Skip to content

260616_02_김선진#55

Open
ks98ks-ui wants to merge 20 commits into
SurvivalCodingCampus:student/02_김선진from
ks98ks-ui:master
Open

260616_02_김선진#55
ks98ks-ui wants to merge 20 commits into
SurvivalCodingCampus:student/02_김선진from
ks98ks-ui:master

Conversation

@ks98ks-ui

Copy link
Copy Markdown

260616_02_김선진

📝 과제 정보

  • 교육 주제:
    상속

📷 실행 결과 (또는 테스트 결과)

image image image

❓질문 및 어려웠던 점

  • 테스트코드를 짤 때 저번까지 보통 When 부분에 한개만 넣어져 있어서 신경 못썼는데 When 순서를 제대로 넣지 않아 원하는 대로 실행이 안되었습니다.

🔄 자체 평가 & 회고

  • 테스트코드를 짤 때 When 부분을 제대로 신경 쓰지 않아서 값이 제대로 안나왔고, 그러다보니 코드를 잘못 쓴거 같아서 수정하는데 시간을 많이 쓴게 아쉬웠습니다.

@coderabbitai

coderabbitai Bot commented Jun 16, 2026

Copy link
Copy Markdown

Review Change Stack

상속 개념 연습 구현

학생이 Java 상속의 핵심 개념들을 실습 코드로 구현했습니다. 세 가지 주요 상속 관계를 다루었습니다:

1. Wizard → GreatWizard 상속

  • Wizard: 마나(MP) 100을 가진 기본 마법사 클래스
  • GreatWizard: Wizard를 상속받아 마나를 150으로 확장
    • getMp()/setMp() 오버라이드로 독립적인 마나 관리
    • heal() 메서드 구현: 마나 5 소비, HP 25 회복
    • superHeal() 메서드 추가: 마나 50 소비, HP 최대값으로 회복

2. Slime → PoisonSlime 상속

  • Slime: 기본 슬라임의 공격 메서드 구현 (10 데미지)
  • PoisonSlime: Slime을 상속받아 독 포자 상태 추가
    • poisonCount 필드로 독 상태 관리
    • attack() 메서드 오버라이드: 기본 공격 후 독 카운트가 1 이상일 때 추가 독 데미지(최대HP의 1/5) 적용

3. 상속 기반 다형성 실습

  • SuperHero extends Hero: 비행 상태 추가 및 메서드 오버라이드
  • 모든 테스트 케이스 통과 (PoisonSlimeTest, GreatWizardTest, WizardTest)

주요 학습 성과

학생은 테스트 코드의 실행 순서와 상태 관리의 중요성을 발견했습니다. 특히 테스트의 "When" 섹션에서 메서드 호출 순서가 결과에 미치는 영향을 이해하는 데 시간을 투자했으며, 이는 상속 구조에서 상태 변경(예: 독 카운트 감소)을 추적하는 능력을 강화했습니다.

고려할 개선 사항

문서화 측면에서:

  • 캡슐화 관점: Slime 클래스의 필드 접근 제한자에 대해 생각해본 적 있나요? 부모 클래스의 필드들이 자식 클래스나 외부에서 어떻게 접근되어야 할까요?
  • 메서드 책임: PoisonSlime의 attack() 메서드가 동시에 공격과 독 상태 관리(poisonCount 감소)를 담당하고 있는데, 한 메서드가 여러 책임을 지는 것에 대해 어떻게 생각하세요?
  • 필드 명명 규칙: GreatWizard의 Mp 필드를 보면 첫 글자가 대문자인데, Java 관례에서는 어떤 규칙을 따라야 할까요?

Walkthrough

Hero 클래스에 MaxHP 필드, 생성자, run() 메서드를 추가하고 SuperHero·Slime·PoisonSlime·GreatWizard 서브클래스를 신규 구현했다. Wizardheal() 로직을 MP 조건부 방식으로 변경하고, JUnit5 테스트·PlantUML 다이어그램·TIL 문서를 추가했다.

Changes

Java 상속 실습 계층 구조 구현

Layer / File(s) Summary
Hero 기반 클래스 확장 및 SuperHero 서브클래스
game2/src/main/java/com/survivalcoding/Hero.java, game2/src/main/java/com/survivalcoding/SuperHero.java, game2/src/test/java/com/survivalcoding/HeroTest.java
HeroMaxHP 정적 필드, 생성자 2종, setHp 음수 클램프, run() 추가. SuperHeroisFlying 상태와 run()/attack() 오버라이드를 포함해 Hero를 상속 구현. HeroTestattack() 테스트 메서드는 삭제됨.
Slime 기반 클래스 및 PoisonSlime 서브클래스
game2/src/main/java/com/survivalcoding/Slime.java, game2/src/main/java/com/survivalcoding/PoisonSlime.java, game2/src/test/java/com/survivalcoding/PoisonSlimeTest.java
Slime 신규 추가(attack 시 Hero hp -10). PoisonSlimeSlime 상속 후 poisonCount > 0이면 기본 공격 후 hero hp의 1/5 추가 독 데미지 적용. PoisonSlimeTest로 poisonCount 유무 두 시나리오 검증.
Wizard heal 로직 변경 및 GreatWizard 서브클래스
game2/src/main/java/com/survivalcoding/Wizard.java, game2/src/main/java/com/survivalcoding/GreatWizard.java, game2/src/test/java/com/survivalcoding/WizardTest.java, game2/src/test/java/com/survivalcoding/GreatWizardTest.java
Wizard.mp 기본값 100 설정, heal() 로직을 MP 잔량 조건부 고정 회복(HP +20, MP -10)으로 전환. GreatWizard는 MP 150 유지, heal(HP +25, MP -5)·superHeal(HP=MaxHP, MP -50) 구현. WizardTest·GreatWizardTest로 MP 초기값·회복·소비 검증.
PlantUML 다이어그램, 보조 파일 변경, TIL 문서
game2/game2.puml, game2/src/main/java/com/survivalcoding/Person.java, game2/src/main/java/com/survivalcoding/260616_연습문제, TIL/2026-06-10-캡슐화, 컬렉션.md, TIL/2026-06-11-상속.md
game2.puml에 전체 클래스 계층을 PlantUML로 정의. Person.age에서 final 제거. 연습문제 노트 파일 추가. TIL에서 HashSet 예시 코드 수정(numbers→numberSet) 및 상속 학습 노트 신규 추가.

추정 코드 리뷰 노력

🎯 3 (Moderate) | ⏱️ ~20 minutes

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 2.86% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive 제목 '260616_02_김선진'은 날짜와 학생 이름만 포함하고 있어서 변경사항의 핵심 내용을 명확히 전달하지 못합니다. Pull Request의 주요 변경사항을 반영하는 구체적인 제목으로 수정하기를 권장합니다. 예: '상속 연습문제: SuperHero, GreatWizard, PoisonSlime 클래스 구현'으로 변경하면 더 명확합니다.
✅ Passed checks (3 passed)
Check name Status Explanation
Description check ✅ Passed PR 설명이 제공된 템플릿의 주요 섹션들을 포함하고 있습니다. 교육 주제(상속), 실행 결과(3개의 테스트 스크린샷), 어려웠던 점, 자체 평가 및 회고 섹션이 모두 작성되어 있습니다.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (3)
game2/src/main/java/com/survivalcoding/Person.java (1)

4-4: ⚡ Quick win

age 필드에서 final 제거로 인한 캡슐화 및 데이터 일관성 우려.

Line 4에서 final int ageint age로 변경되면서 다음과 같은 설계 문제가 발생합니다:

  1. 데이터 일관성 깨짐: 생성자(line 10)에서 age = 2026 - birthYear로 계산되지만, 이제 age를 직접 수정할 수 있어서 birthYear와의 관계가 보장되지 않습니다.
  2. 은닉 원칙 위반: age가 package-private 필드이므로 같은 패키지 내 코드에서 직접 수정 가능하며, 향후 public으로 노출되면 외부에서도 임의 수정 가능.

권장:

  • birthYear 변경 시 age를 함께 갱신하는 로직을 setBirthYear()에 추가하거나,
  • ageprivate로 유지하고 getAge() 메서드에서 2026 - birthYear 계산 후 반환하는 방식 검토
💡 대안: age를 계산 속성으로 변경
 public class Person {
-    int age;
     private String name;
     private int birthYear;

     Person(String name, int birthYear) {
         this.name = name;
-        this.age = 2026 - birthYear;
+        this.birthYear = birthYear;
     }

+    public int getAge() {
+        return 2026 - birthYear;
+    }

     // ...
     
     public static void main(String[] args) {
         Person person = new Person("Hong", 1998);
         System.out.println(person.getName());
-        System.out.println(person.age);
+        System.out.println(person.getAge());
     }
 }

또는 setBirthYear() 수정 시:

     public void setBirthYear(int birthYear) {
         this.birthYear = birthYear;
+        this.age = 2026 - birthYear;  // age도 함께 갱신
     }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@game2/src/main/java/com/survivalcoding/Person.java` at line 4, The `age`
field in the Person class needs to restore encapsulation and data consistency.
Either restore the `final` modifier to `age` and ensure it is only set in the
constructor, or change `age` to `private` and modify the `getAge()` method to
return the calculated value `2026 - birthYear` instead of storing it as a
mutable field. If `setBirthYear()` exists or is added, ensure it recalculates
`age` based on the new `birthYear` value to maintain consistency. This prevents
external code or other parts of the class from breaking the invariant
relationship between `birthYear` and `age`.
game2/game2.puml (1)

1-59: 💤 Low value

PlantUML 문법 및 메서드 시그니처 정확성 개선 필요.

다이어그램이 전체 클래스 계층을 잘 보여주나, 다음과 같은 문법과 계약 누락이 있습니다:

  1. 필드 표기 오류:

    • Line 8: - int hp 100 → 올바른 PlantUML 문법은 - int hp = 100
  2. 메서드 표기 불명확:

    • Line 5, 25: + run()+, +heal()+ → 끝의 +는 제거하고 반환 타입 추가: + void run(), + void heal()
    • Line 26: +superHeal()+ void superHeal()로 명확히, 그리고 실제 구현(game2/src/main/java/com/survivalcoding/GreatWizard.java:35-50)에 따르면 매개변수 Hero hero 필요
  3. 메서드 시그니처 완성도:

    • Line 34-35: + setWand(), + heal() → 실제 구현의 매개변수와 반환 타입 표기 누락. 정확한 시그니처: + void setWand(Wand), + void heal(Hero)
    • Line 55: +attack() (Slime) → + void attack(Hero) 또는 + void attack() 명확히
💡 제안: 메서드 시그니처 개선 예시
 class SuperHero extends Hero {
    +void setFlying(bool flying)
    +boolean isFlying()
-   + run()+
+   + void run()
 }
 
 class GreatWizard extends Wizard {
-   +heal()+
-   +superHeal()
+   + void heal(Hero)
+   + void superHeal(Hero)
 }
 
 class Wizard {
    - int hp
    - int mp = 100
    - Wand wand
    - String name
    + void setWand(Wand)
-   + heal()
+   + void heal(Hero)
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@game2/game2.puml` around lines 1 - 59, Fix the PlantUML syntax and method
signatures in the diagram. In the Hero class, correct the field initialization
on line 8 from `- int hp 100` to `- int hp = 100` using the equals sign. Remove
the trailing plus signs and add return types for methods: change `+ run()+` in
SuperHero to `+ void run()`, change `+heal()+` in GreatWizard to `+ void
heal()`, and change `+superHeal()` in GreatWizard to `+ void superHeal(Hero)` to
include the parameter. In the Wizard class, add complete method signatures:
change `+ setWand()` to `+ void setWand(Wand)` and change `+ heal()` to `+ void
heal(Hero)` to include parameters and return types. In the Slime class, clarify
the attack method signature from `+attack()` to `+ void attack(Hero)`.
game2/src/main/java/com/survivalcoding/SuperHero.java (1)

4-9: ⚡ Quick win

SuperHero 엔티티 내부의 main 실행 코드는 분리하는 편이 안전합니다.

Line [4]~Line [9]의 데모 실행 코드는 클래스 책임을 흐리고, 이후 실수로 운영 코드에 남기기 쉽습니다. main은 별도 실행용 클래스(예: App)나 테스트로 이동하는 것을 권장합니다.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@game2/src/main/java/com/survivalcoding/SuperHero.java` around lines 4 - 9,
The main method containing demo execution code should be removed from the
SuperHero entity class to maintain single responsibility principle and reduce
the risk of test/demo code leaking into production. Move the entire main method
(which creates a SuperHero instance with "홍길동" and 50 as parameters, then calls
attack(), run(), and setFlying(true)) to a separate execution class such as App
or to a test class. Remove the main method entirely from the SuperHero class.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@game2/src/main/java/com/survivalcoding/GreatWizard.java`:
- Around line 14-16: The setMp method in the GreatWizard class is not validating
that the mp parameter is non-negative, which violates the contract established
by the parent class Wizard.setMp(). To fix this, add the same negative value
validation in GreatWizard.setMp() that exists in the parent Wizard class - check
if mp is less than zero and throw an appropriate exception (such as
IllegalArgumentException) with a descriptive message, or alternatively call the
parent class's setMp method to leverage its existing validation logic. This
ensures type substitution safety and maintains consistent precondition
enforcement across the inheritance hierarchy.

In `@game2/src/main/java/com/survivalcoding/Hero.java`:
- Around line 30-33: The Hero constructor in the parameterized constructor
(lines 30-33) directly assigns hp with `this.hp = hp;` which bypasses the
validation logic in the setHp() method (lines 17-21) that prevents negative
values. Replace the direct assignment `this.hp = hp;` with a call to `setHp(hp)`
to ensure the same HP validation invariant is enforced during object
construction as well as when updating the value later.

In `@game2/src/main/java/com/survivalcoding/Wizard.java`:
- Line 41: The exception message in the Wizard class at line 41 uses incorrect
terminology. The message says "3문장 이상" (3 sentences or more) but the actual
validation rule checks for 3 characters using name.length() < 3. Update the
error message string to use "3문자" (3 characters) instead of "3문장" (3 sentences)
to match the actual validation logic and provide accurate feedback to users and
tests.

---

Nitpick comments:
In `@game2/game2.puml`:
- Around line 1-59: Fix the PlantUML syntax and method signatures in the
diagram. In the Hero class, correct the field initialization on line 8 from `-
int hp 100` to `- int hp = 100` using the equals sign. Remove the trailing plus
signs and add return types for methods: change `+ run()+` in SuperHero to `+
void run()`, change `+heal()+` in GreatWizard to `+ void heal()`, and change
`+superHeal()` in GreatWizard to `+ void superHeal(Hero)` to include the
parameter. In the Wizard class, add complete method signatures: change `+
setWand()` to `+ void setWand(Wand)` and change `+ heal()` to `+ void
heal(Hero)` to include parameters and return types. In the Slime class, clarify
the attack method signature from `+attack()` to `+ void attack(Hero)`.

In `@game2/src/main/java/com/survivalcoding/Person.java`:
- Line 4: The `age` field in the Person class needs to restore encapsulation and
data consistency. Either restore the `final` modifier to `age` and ensure it is
only set in the constructor, or change `age` to `private` and modify the
`getAge()` method to return the calculated value `2026 - birthYear` instead of
storing it as a mutable field. If `setBirthYear()` exists or is added, ensure it
recalculates `age` based on the new `birthYear` value to maintain consistency.
This prevents external code or other parts of the class from breaking the
invariant relationship between `birthYear` and `age`.

In `@game2/src/main/java/com/survivalcoding/SuperHero.java`:
- Around line 4-9: The main method containing demo execution code should be
removed from the SuperHero entity class to maintain single responsibility
principle and reduce the risk of test/demo code leaking into production. Move
the entire main method (which creates a SuperHero instance with "홍길동" and 50 as
parameters, then calls attack(), run(), and setFlying(true)) to a separate
execution class such as App or to a test class. Remove the main method entirely
from the SuperHero class.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: f1699240-a666-46ba-b131-66fad08109ad

📥 Commits

Reviewing files that changed from the base of the PR and between f455857 and aa9d756.

📒 Files selected for processing (17)
  • TIL/2026-06-10-캡슐화, 컬렉션.md
  • TIL/2026-06-11-상속.md
  • game2/game2.puml
  • game2/src/main/java/com/survivalcoding/260615_연습문제1
  • game2/src/main/java/com/survivalcoding/260616_연습문제
  • game2/src/main/java/com/survivalcoding/GreatWizard.java
  • game2/src/main/java/com/survivalcoding/Hero.java
  • game2/src/main/java/com/survivalcoding/ListExam.java
  • game2/src/main/java/com/survivalcoding/Person.java
  • game2/src/main/java/com/survivalcoding/PoisonSlime.java
  • game2/src/main/java/com/survivalcoding/Slime.java
  • game2/src/main/java/com/survivalcoding/SuperHero.java
  • game2/src/main/java/com/survivalcoding/Wizard.java
  • game2/src/test/java/com/survivalcoding/GreatWizardTest.java
  • game2/src/test/java/com/survivalcoding/HeroTest.java
  • game2/src/test/java/com/survivalcoding/PoisonSlimeTest.java
  • game2/src/test/java/com/survivalcoding/WizardTest.java
💤 Files with no reviewable changes (2)
  • game2/src/test/java/com/survivalcoding/HeroTest.java
  • game2/src/main/java/com/survivalcoding/ListExam.java

Comment on lines +14 to +16
public void setMp(int mp) {
Mp = mp;
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

setMp 오버라이드가 상위 클래스의 음수 MP 방어 계약을 깨고 있습니다.

Line 14-16은 음수 MP를 그대로 허용합니다. Wizard.setMp()는 음수 입력을 예외 처리하므로, 하위 클래스도 동일 제약을 유지해야 타입 대체가 안전합니다.

제안 수정안
 `@Override`
 public void setMp(int mp) {
-    Mp = mp;
+    if (mp < 0) {
+        throw new IllegalArgumentException("마법사의 MP는 0 이상이여야 한다");
+    }
+    Mp = mp;
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
public void setMp(int mp) {
Mp = mp;
}
public void setMp(int mp) {
if (mp < 0) {
throw new IllegalArgumentException("마법사의 MP는 0 이상이여야 한다");
}
Mp = mp;
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@game2/src/main/java/com/survivalcoding/GreatWizard.java` around lines 14 -
16, The setMp method in the GreatWizard class is not validating that the mp
parameter is non-negative, which violates the contract established by the parent
class Wizard.setMp(). To fix this, add the same negative value validation in
GreatWizard.setMp() that exists in the parent Wizard class - check if mp is less
than zero and throw an appropriate exception (such as IllegalArgumentException)
with a descriptive message, or alternatively call the parent class's setMp
method to leverage its existing validation logic. This ensures type substitution
safety and maintains consistent precondition enforcement across the inheritance
hierarchy.

Comment on lines +30 to 33
public Hero(String name, int hp) {
this.name = name;
this.hp = hp;
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

인자 생성자가 HP 음수 클램프 계약을 우회합니다.

Line 30-33에서 this.hp = hp;로 직접 대입하면, setHp()가 보장하는 음수 방어(Line 17-21)가 적용되지 않아 객체가 음수 HP로 생성될 수 있습니다. 생성 시점에도 동일한 불변식을 유지하도록 setter를 사용하세요.

제안 수정안
 public Hero(String name, int hp) {
     this.name = name;
-    this.hp = hp;
+    setHp(hp);
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@game2/src/main/java/com/survivalcoding/Hero.java` around lines 30 - 33, The
Hero constructor in the parameterized constructor (lines 30-33) directly assigns
hp with `this.hp = hp;` which bypasses the validation logic in the setHp()
method (lines 17-21) that prevents negative values. Replace the direct
assignment `this.hp = hp;` with a call to `setHp(hp)` to ensure the same HP
validation invariant is enforced during object construction as well as when
updating the value later.

}
if (name.length() < 3) {
throw new IllegalArgumentException("이름이 3단어 이상이여야 함");
throw new IllegalArgumentException("이름이 3문장 이상이여야 함");

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

예외 메시지 용어가 검증 규칙과 다릅니다(문장 → 문자).

Line 41의 "이름이 3문장 이상이여야 함"은 실제 검증(name.length() < 3) 의미와 어긋납니다. 사용자/테스트 가독성을 위해 "3문자"로 맞추는 편이 좋습니다.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@game2/src/main/java/com/survivalcoding/Wizard.java` at line 41, The exception
message in the Wizard class at line 41 uses incorrect terminology. The message
says "3문장 이상" (3 sentences or more) but the actual validation rule checks for 3
characters using name.length() < 3. Update the error message string to use "3문자"
(3 characters) instead of "3문장" (3 sentences) to match the actual validation
logic and provide accurate feedback to users and tests.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant