반응형

클린코드 작성하기 

public class Main {
    public static void main(String[] args) {
        System.out.println("숫자를 입력하세요 : ");
        Scanner scanner = new Scanner(System.in);
        int a = scanner.nextInt();
        
        int r1 = 0, r2 = 0, r3=0, r4=0, r5 = 0, r6 = 0;
        
        for(int i = 0; i < a; i++){
            double b = Math.random() * 6;
            if(b >=0 && b <1){
                r1 ++;
            }else if(b >= 1 && b < 2){
                r2 ++;
            }else if(b >= 2 && b < 3){
                r2 ++;
            }else if(b >= 3 && b < 4){
                r2 ++;
            }else if(b >= 4 && b < 5){
                r2 ++;
            }else if(b >= 5 && b < 6){
                r2 ++;
            }
        }

        System.out.printf("1은 %d번 나왔습니다.\n",r1);
        System.out.printf("2은 %d번 나왔습니다.\n",r2);
        System.out.printf("3은 %d번 나왔습니다.\n",r3);
        System.out.printf("4은 %d번 나왔습니다.\n",r4);
        System.out.printf("5은 %d번 나왔습니다.\n",r5);
        System.out.printf("6은 %d번 나왔습니다.\n",r6);
    }
}

 

이 코드를 리팩토링 하는게 5일차 미션이다. 

 

코드에서 역활을 분리해서 메서드를 추출.

public class TestClass {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int a = getA(scanner);

        int r1 = 0, r2 = 0, r3 = 0, r4 = 0, r5 = 0, r6 = 0;

        condition(a, r1, r2, r3, r4, r5, r6);
        print(r1, r2, r3, r4, r5, r6);
    }
	
    //주사위를 던질횟수를 입력받는다
    private static int getA(Scanner scanner) {
        System.out.println("숫자를 입력하세요 : ");
        return scanner.nextInt();
    }
	
    //주사위를 던져 1~6까지의 숫자가 몇번나왔는지 증가
    private static void condition(int a, int r1, int r2, int r3, int r4, int r5, int r6) {
        for (int i = 0; i < a; i++) {
            double b = Math.random() * 6;

            switch ((int) b) {
                case 0:
                    r1++;
                    break;
                case 1:
                    r2++;
                    break;
                case 2:
                    r3++;
                    break;
                case 3:
                    r4++;
                    break;
                case 4:
                    r5++;
                    break;
                case 5:
                    r6++;
                    break;
                default:
                    // 기본값 처리
                    break;
            }
        }
    }
	
    //주사위 결과 출력
    private static void print(int r1, int r2, int r3, int r4, int r5, int r6) {
        System.out.printf("1은 %d번 나왔습니다.\n", r1);
        System.out.printf("2은 %d번 나왔습니다.\n", r2);
        System.out.printf("3은 %d번 나왔습니다.\n", r3);
        System.out.printf("4은 %d번 나왔습니다.\n", r4);
        System.out.printf("5은 %d번 나왔습니다.\n", r5);
        System.out.printf("6은 %d번 나왔습니다.\n", r6);
    }
}

 

전체적인 코드는 길어졌지만 메인 메서드만 보면 이전보다는 가독성이 좋아지고

메서드의 이름을 통해 어떤동작을 하는지 간단하게 파악이 가능해졌다. 

 

이제 중복되는 과정들은 조건문과 반복문으로 줄이고 주사위의 횟수를 저장할값도 더 쉽게 만들어보자.

public class TestClass {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        Map<Integer, Integer> dice = createDice(6);

        int count = getCount(scanner);
        play(dice,count);
        print(dice);
    }

    private static Map<Integer, Integer> createDice(int a) {
        Map<Integer, Integer> dice = new HashMap<>();
        for (int i = 0; i < a; i++) {
            dice.put(i + 1, 0); // key(주사위번호) : value(해당번호가 나온 횟수)
        }
        return dice;
    }

    private static int getCount(Scanner scanner) {
        System.out.println("숫자를 입력하세요 : ");
        return scanner.nextInt();
    }

    private static void condition(Map<Integer, Integer> dice,int count) {
        for (int i = 0; i < count; i++) {
            int b = (int) (Math.random() * dice.size()) + 1;

            dice.put(b, dice.getOrDefault(b, 0) + 1);
        }
    }

    private static void print(Map<Integer, Integer> dice) {
        for (Entry<Integer, Integer> entry : dice.entrySet()) {
            System.out.printf("%d은 %d번 나왔습니다.\n", entry.getKey(),entry.getValue());
        }
    }
}

 

중간과정을 좀 많이 건너뛴 최종 리팩토링 코드이다. 

 

1.  r1 , r2 로 주사위의 눈금을 받아주던 변수를 확장성있게 map으로 변경


int r1 = 0, r2 = 0, r3 = 0, r4 = 0, r5 = 0, r6 = 0; 
//이제 눈금갯수를 수정해도 변수의 갯수가 바뀌지 않고 변수를 여러개 선언하지않아도 된다.
Map<Integer, Integer> dice = createDice(6);

//Array나 배열을 사용하면 이 메서드를 생성하지 않아도 된다.
private static Map<Integer, Integer> createDice(int a) {
        Map<Integer, Integer> dice = new HashMap<>();
        for (int i = 0; i < a; i++) {
            dice.put(i + 1, 0); // key(주사위번호) : value(해당번호가 나온 횟수)
        }
        return dice;
    }

 

맵말고 Array나 그냥 일반배열로 해도 index를 통해서 눈금을 나타낼수있어서 그쪽이 더 간단할것같다. 

이번에는 그냥 Map타입을 사용해보고싶어서 Map으로 주사위를 지정했지만

이후 다른 기능이 추가될때 특성에따라 타입을 수정해야 할수도 있을것같다.

 

2.조건 부분을 반복문과 조건문으로 수정

private static void condition(int a, int r1, int r2, int r3, int r4, int r5, int r6) {
        for (int i = 0; i < a; i++) {
            double b = Math.random() * 6;

            switch ((int) b) {
                case 0:
                    r1++;
                    break;
                case 1:
                    r2++;
                    break;
                case 2:
                    r3++;
                    break;
                case 3:
                    r4++;
                    break;
                case 4:
                    r5++;
                    break;
                case 5:
                    r6++;
                    break;
                default:
                    // 기본값 처리
                    break;
            }
        }
    }
// if else조건문을 switch문으로 변경했을때 가독성은 더 좋아졌지만 반복되고 코드가 길어지는 문제가있었다
// 이를 반복과 조건문으로 변경하고 r1,r2같이 파라미터가 여러개이던 문제도 dice를 Map타입으로 만들면서 해결되었다.
// a라는 이름으로 들어오던 파라미터도 의미를 알기쉽게 count라는 이름으로 변경해주었다.
private static void play(Map<Integer, Integer> dice,int count) {
        for (int i = 0; i < count; i++) {
            int b = (int) (Math.random() * dice.size()) + 1;

            dice.put(b, dice.getOrDefault(b, 0) + 1);
        }
    }

이제 누가봐도 파라미터로 받는 count만큼 주사위를 굴려서 dice에 매칭 시켜주는 함수라는 걸 알기 쉬워졌다.

메서드이름은 condition보다는 주사위를 굴린다는 의미로 바꾸어주는게 좋을것같다. condition => play

 

3.출력부분을 반복문으로 수정

//주사위 결과 출력
    private static void print(int r1, int r2, int r3, int r4, int r5, int r6) {
        System.out.printf("1은 %d번 나왔습니다.\n", r1);
        System.out.printf("2은 %d번 나왔습니다.\n", r2);
        System.out.printf("3은 %d번 나왔습니다.\n", r3);
        System.out.printf("4은 %d번 나왔습니다.\n", r4);
        System.out.printf("5은 %d번 나왔습니다.\n", r5);
        System.out.printf("6은 %d번 나왔습니다.\n", r6);
    }
    
    private static void print(Map<Integer, Integer> dice) {
        for (Entry<Integer, Integer> entry : dice.entrySet()) {
            System.out.printf("%d은 %d번 나왔습니다.\n", entry.getKey(),entry.getValue());
        }
    }

 

이전에는 출력해주던 메서드도 반복되고 파라미터가 많아서 주사위의 눈금이 늘어나면 그만큼 파라미터도 늘어나야하고 코드도 길어져야 하는 문제가 있었다. 이것 또한 dice로 타입이 변경되면서 반복문이 사용가능해면서 해결되었다.

 

이 부분은 주사위를 map, 배열 , Array로 변경하면서 해결했다.

주사위 자체를 따로 Dice클래스로 만들고 그 안에 주사위의 눈금과 몇번나왔는지 지정해주는 필드를 생성해도 될것같고 

더 다양한 방법도 있을것같다.

 

<클린코드>

이 개념에 대해서 배워보았는데 이전에 우테코를 하면서 코드 컨벤션이라는 개념을 배워본적이있었다.

코드를 작성하기위한 약속이었는데 코드 컨벤션만 준수하면서 작성해도 어느정도 가독성이 좋고

모두가 이해하기 쉬운 코드를 작성할수있다고 생각한다. 가장 좋은 코드는 책 처럼 읽어지는 코드가 아닐까?

반응형

+ Recent posts