Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

사다리 미션 제출합니다 :) #18

Open
wants to merge 4 commits into
base: jermany17
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 57 additions & 0 deletions src/main/java/controller/Application.java
Copy link

Choose a reason for hiding this comment

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

controller 패키지에는 Controller 파일만 두고, Application 파일은 controller가 아닌 다른 위치에 두는게 좋을 것 같아요!(다른 분들 코드를 읽어보니, main 패키지를 하신분도 있었고 저는 패키지를 따로 두지 않고 java 패키지 밑에 두었습니다.
Application 클래스에는 Controller 클래스를 불러와서 게임을 진행하는 메서드를 실행시키면 될 것 같습니다. 저는 아래와 같이 작성했습니다:)

public class LadderApplication {

    public static void main(String[] args){

        LadderController controller = new LadderController();
        controller.run();
    }
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package controller;

import domain.LadderArray;
import domain.Participant;
import view.Input;
import view.Output;

import java.util.ArrayList;

public class Application {
Comment on lines +1 to +10

Choose a reason for hiding this comment

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

[Comment]

java 프로그램에서 main 함수를 갖고 있는 클래스는 어플리케이션을 실행(run) 시키기 위해 많이 사용하는데요.

이 Application 클래스를 controller 패키지 밑에 위치 시킨데에 이유가 있을까요?

  • Application
    • 어플리케이션을 실행 시키기 위한 클래스
  • controller
    • view와 domain을 연결

저는 이 두가지로 이해하고 있는데요.
제 생각에도 Application을 저 두가지의 역할을 하도록 설계해도 전혀 문제될 것은 없다고 생각합니다.

하지만 지금 이 Application의 main 메서드가 너무 길어지고 view와 도메인을 오가서 프로그램의 flow를 한눈에 보기 쉽지 않은데요.
정리해보면 어떨까요?

public static void main(String[] args) {

// 참여자 입력
ArrayList<Participant> participants = Input.inputParticipants();
Copy link

Choose a reason for hiding this comment

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

List가 아니라 ArrayList를 사용한 이유가 있을까요?


// 실행 결과 입력
ArrayList<String> results = Input.inputResults();

// 사다리 높이 입력
int height = Input.inputHeight();

// 참여자 출력
Output.printParticipants(participants);

// 가로 사다리 배열 만들기
ArrayList<ArrayList<Integer>> array = LadderArray.createLadderArray(participants.size()-1, height);
Copy link

@haeyoon1 haeyoon1 Oct 31, 2024

Choose a reason for hiding this comment

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

ArrayList< ArrayList> 를 사용하지 않게, LadderArray 클래스를 Ladder과 각 줄을 나타내는 Line 클래스로 나누어서 구현해도 좋을 것 같습니다!
1단계-사다리출력힌트의 내용을 참고하시면 될 것 같아요.


// 사다리 출력
Output.printLadder(array);

// 실행 결과 출력
Output.printResults(results);

// 각 참가자의 최종 결과 구하기
LadderArray.setResultsForParticipants(participants, results, array);

// 반복 검색
while(true){
// 검색
search(participants);
}
Comment on lines +38 to +41

Choose a reason for hiding this comment

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

[Request Change]

break 조건이 없는 반복문은 예외가 터져야만 멈추겠네요 ㅠㅠㅠㅠ

Comment on lines +37 to +41
Copy link

Choose a reason for hiding this comment

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

탈출 조건이 문제에 나와있지 않아 저도 적어야하나 많이 고민했는데요... 그래도 코드가 계속 돌아가는 문제를 막기 위해서는 while(true)문 탈출조건을 적어주는 것이 좋을 것 같습니다!

}

// 검색
private static void search(ArrayList<Participant> participants) {
// 결과 검색
String search = Input.searchResult();
if (search.equalsIgnoreCase("all")) {
// 모든 참가자의 결과 출력
Output.printAllResults(participants);
}
if (! search.equalsIgnoreCase("all")) {
// 개별 참가자의 결과 출력
Output.printResultForParticipant(participants, search);
}
}
Comment on lines +44 to +56

Choose a reason for hiding this comment

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

출력하는 메서드는 Output 클래스로 옮기고, Application 클래스에는 controller의 역할만 수행하면 좋을 것 같습니다:)

}
75 changes: 75 additions & 0 deletions src/main/java/domain/LadderArray.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
package domain;

import java.util.ArrayList;
import java.util.Random;

public class LadderArray {

// 가로 사다리 배열 만들기 1
public static ArrayList<ArrayList<Integer>> createLadderArray(int x, int y) {
Comment on lines +6 to +9

Choose a reason for hiding this comment

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

[Request Change]

준민님은 객체 지향 프로그래밍의 가장 큰 정체성은 무엇이라고 생각하시나요?
저는 객체가 상태(state)를 가진는 것이라고 생각해요!

LadderArray가 모두 static 메서드로 유틸 클래스로 선언되어있네요!!
유틸 클래스는 이곳 저곳에서 공용으로 사용할 수 있다는 특징이 있는데요.

LadderArray같은 도메인 모델이 상태를 갖도록 해보는 것은 어떨까요?

당장 왜 그래야되는지 상상이 어렵다면, 두가지 요구사항이 추가된다고 가정을 해보면 좋을 것 같아요

  1. 동시에 여러사람이 접속할 수 있는 게임이다. 여러ladderArray가 존재할 수 있다.
  2. 게임을 저장할 수 있다 이전에 사용한던 LadderArray를 불러와야 한다.

Copy link

Choose a reason for hiding this comment

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

기본 프로그래밍 요구사항에 "줄여 쓰지 않는다(축약 금지)" 라는 부분이 이 있는데요 명확한 변수를 사용하면, 코드의 가독성을 높이고, 협업시 혼란을 주는 것을 방지한다고 하네요!
x와 y라는 변수명도 좋지만, 조금 더 명확한 변수명을 사용하시는걸 추천드려요!

System.out.println();

Choose a reason for hiding this comment

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

[Request Change]

현재 저희는 MVC 패턴을 이용해서 어플리케이션을 설계하고 있는데요.
MVC 패턴의 가장 큰 특징이라하면, 도메인 로직을 담당하는 Model유저와 맞닿아있는 View를 관리를 따로 하는 것인데요.

지금 LadderArray는 Model로서 작성된 코드로 보여지는데, View에 대한 코드가 있는 것 같아요.

지금은 View가 console이지만 웹 어플리케이션으로 변경된다는 View의 변경사항이 생기면 이 부분의 코드도 변경해야겠죠?

변경 사항이 전파된다는 것은 의존한다라고 볼 수 있는데요. 모델이 뷰를 의존하면 안될 것 같아요. 확실하게 나눠보죠!

ArrayList<ArrayList<Integer>> array2D = new ArrayList<>();
Comment on lines +9 to +11
Copy link

@haeyoon1 haeyoon1 Oct 31, 2024

Choose a reason for hiding this comment

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

위에서 말씀드렸던 것 처럼

// AS-IS
public class Ladder {
    private final List<List<Boolean>> lines;
} 

이렇게 이차원 배열을 사용하는 것 보다

// TO-BE
public class Ladder {
    private final List<Line> lines;
}
public class Line {
    private final List<Boolean> points;
}

이렇게 사용하면 좋을 것 같습니다!

Choose a reason for hiding this comment

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

[Request Change]

위에서 리뷰 해주신 것처럼,
연결다리(Intger), 라인(List<Integer>), 사다리(List<List<Integer>>)가 각각 역할을 가질 수 있도록 클래스로 래핑해보면 어떨까요?

연결다리(Integer)

  • 1일 때는 건널 수 있다.
  • 0일 때는 건널 수 없다.
  • 0과 1의 값만 가진다.
  • 0과 1의 값중 랜덤하게 생성된다.

라인(List)

  • 연결다리를 사람수만큼 갖는다.
  • 연속해서 건널 수 있는 연결다리는 가질 수 없다.
  • 참가자는 매 라인마다 건널 수있는 연결다리가 있으면 이동 / 없으면 이동 X

사다리(List<List>)

  • 사다리 높이만큼 라인을 갖는다.
  • 높이는 2 이상이여야한된다.
  • 참가자는 매 라인 이동이 끝나면 다음 라인으로 넘어간다.

이런 요구사항들을 도출해볼 수 있겠죠?

위의 예시는 제가 README를 작성한다면 뽑아내볼 요구사항을 간략히 적어본 것이고 저렇게 하라고 적은 것은 당연히 아닙니다.

아무래도 객체의 책임 분리에 대해서 어려움이 있으실 것 같아 예시를 남겨드린것이니,
준민님만의 요구사항을 도출해보고 객체를 나눠보는 것은 어떨까요?

  1. README를 통해 필요한 객체(모델, ...)의 역할 및 기능 나열
  2. README를 토대로 class 설계 및 작성
  3. 리팩터링하며, 책임분리 더 명확히 하기
    이런 방식으로 연습해보면 좋을 것 같아요


for (int i = 0; i < y; i++) {
array2D.add(generateRow(x));

Choose a reason for hiding this comment

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

[RequestChange]

array2D와 같은 변수명은 코드를 짠 당시의 본인을 제외한 타인(미래의 본인, 팀원, 리뷰어)이 의도를 파악하기 힘들게 합니다.
도메인에 연관된 네이밍을 해주세요. (참고, 유비쿼터스 언어)

}

return array2D;
}

// 가로 사다리 배열 만들기 2
private static ArrayList<Integer> generateRow(int x) {
ArrayList<Integer> row = new ArrayList<>();
jermany17 marked this conversation as resolved.
Show resolved Hide resolved
Random random = new Random();

int previousValue = 0;
for (int j = 0; j < x; j++) {
int currentValue = generateValue(random, previousValue);
row.add(currentValue);
previousValue = currentValue;
}

return row;
}

// 가로 사다리 배열 만들기 3
private static int generateValue(Random random, int previousValue) {
int value = random.nextInt(2);
if (previousValue == 1 && value == 1) {
value = 0;
}
Comment on lines +38 to +40
Copy link

Choose a reason for hiding this comment

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

previousValue가 두가지(0과 1)의 값만 가진다면, boolean형으로 바꿔도 될 것 같아요!

return value;
}

// 각 참가자의 최종 결과를 구하기 1
public static void setResultsForParticipants(ArrayList<Participant> participants, ArrayList<String> results, ArrayList<ArrayList<Integer>> array) {
for (int i = 0; i < participants.size(); i++) {
int finalPosition = findFinalPosition(i, array);
participants.get(i).setResult(results.get(finalPosition));
}
}

// 각 참가자의 최종 결과 구하기 2
private static int findFinalPosition(int startIndex, ArrayList<ArrayList<Integer>> array) {
int position = startIndex;

for (ArrayList<Integer> row : array) {
position = findFinalPosition2(row, position);
}

return position;
}

// 각 참가자의 최종 결과 구하기 3
private static int findFinalPosition2(ArrayList<Integer> row, int position){
if (position > 0 && row.get(position - 1) == 1) {
position--;
return position;
}
if (position < row.size() && row.get(position) == 1) {
position++;
return position;
}
return position;
}
Comment on lines +44 to +74
Copy link

@haeyoon1 haeyoon1 Oct 31, 2024

Choose a reason for hiding this comment

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

모든 엔티티를 작게 유지하기 위해, 최종 결과를 구하는 메서드들은 따로 새로운 클래스에 넣어도 될 것 같아요!

}
22 changes: 22 additions & 0 deletions src/main/java/domain/Participant.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package domain;

public class Participant {
String name;
String result;

public Participant(String name){
this.name = name;
}

public String getName(){
return this.name;
}

public String getResult() {
return this.result;
}

public void setResult(String result) {
this.result = result;
}
}
61 changes: 61 additions & 0 deletions src/main/java/view/Input.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package view;
import domain.Participant;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Scanner;

public class Input {

private static Scanner scanner = new Scanner(System.in);

// 참여자 입력
public static ArrayList<Participant> inputParticipants(){
System.out.println("참여할 사람 이름을 입력하세요. (이름은 쉼표(,)로 구분하세요)");
String participantsInput = scanner.nextLine();

ArrayList<String> names = new ArrayList<>(Arrays.asList(participantsInput.split(",")));

ArrayList<Participant> participants = new ArrayList<>();
for (String name : names) {
participants.add(new Participant(name));
}
Comment on lines +19 to +22
Copy link

Choose a reason for hiding this comment

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

Input 클래스에서 Participant 객체를 생성하고 있네요!
View 계층에서 도메인 객체 생성 역할을 수행하지 않도록 다른 클래스로 옮기고, Input 클래스에서는 단순히 이름을 String 리스트로 반환하도록 수정하는건 어떨까요?


System.out.println();

return participants;
}

// 실행 결과 입력
public static ArrayList<String> inputResults(){
System.out.println("실행 결과를 입력하세요. (결과는 쉼표(,)로 구분하세요)");
String participantsInput = scanner.nextLine();

ArrayList<String> results = new ArrayList<>(Arrays.asList(participantsInput.split(",")));

System.out.println();

return results;
}

// 사다리 높이 입력
public static int inputHeight(){
System.out.println("최대 사다리 높이는 몇 개인가요?");
int height = scanner.nextInt();
scanner.nextLine();
Comment on lines +44 to +45
Copy link

Choose a reason for hiding this comment

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

int height = Integer.parseInt(scanner.nextLine()); 로 작성하면 한줄로 줄일 수 있습니다!


System.out.println();

return height;
}

// 결과 검색
public static String searchResult() {
System.out.println("결과를 보고 싶은 사람은?");
String search = scanner.nextLine();

System.out.println();

return search;
}
}
75 changes: 75 additions & 0 deletions src/main/java/view/Output.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
package view;

import domain.Participant;

import java.util.ArrayList;

public class Output {

// 참여자 출력
public static void printParticipants(ArrayList<Participant> participants){
System.out.println("사다리 결과\n");
for(Participant p : participants){
System.out.print(" " + p.getName());
}
}

// 실행 결과 출력
public static void printResults(ArrayList<String> results){
for(String r : results){
System.out.print(" " + r);
}
System.out.println();
System.out.println();
}

// 사다리 출력 1
public static void printLadder(ArrayList<ArrayList<Integer>> array2D) {
for (ArrayList<Integer> row : array2D) {
printRow(row);
}
}

// 사다리 출력 2
private static void printRow(ArrayList<Integer> row) {
System.out.print(" |");
for (int val : row) {
printRowLadder(val);
System.out.print("|");
}
System.out.println();
}

// 사다리 출력 3
private static void printRowLadder(int val) {
if(val == 1)
System.out.print("-----");
if(val == 0)
System.out.print(" ");
Comment on lines +45 to +48
Copy link

Choose a reason for hiding this comment

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

이 부분은 삼항연산자를 사용하면 줄일 수 있을 것 같습니다!

}

// 개별 참가자의 결과 출력 1
public static void printResultForParticipant(ArrayList<Participant> participants, String name) {
System.out.println("실행 결과");
for (Participant p : participants) {
printResultForParticipant2(p, name);
}
System.out.println();
}

// 개별 참가자의 결과 출력 2
public static void printResultForParticipant2 (Participant p, String name){
Copy link

Choose a reason for hiding this comment

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

위에서 말씀드렸던 것 처럼, p라는 변수보다 더 명확한 변수명을 사용하시는걸 추천드려요!

if (p.getName().equalsIgnoreCase(name)) {
System.out.println(p.getResult());
}
}

// 모든 참가자의 결과 출력
public static void printAllResults(ArrayList<Participant> participants) {
System.out.println("실행 결과");
for (Participant p : participants) {
System.out.println(p.getName() + " : " + p.getResult());
}
System.out.println();
}
}