1 minute read

View는 유틸리티 클래스로? 싱글턴 패턴으로?

상태가 없는 클래스들은 모든 메서드를 static 으로 선언하여 유틸리티 클래스로 만들어준다.
하지만 static 메서드가 많아 지게 되면 메모리 측면에서 안 좋아진다.
static 메서드들은 프로그램이 종료할 때까지 static영역에 남아있다.

하지만 상태가 없다고 유틸리티 클래스로 만들기는 무리다. Controller도 무상태 객체이고 static은 객체 지향 보다는 절차 지향에 가까운 키워드라고 한다.

유틸리티 성격은 아닌데 인스턴스로 여러번 생성되기엔 성격이 적절하지 않을 때, 싱글턴 패턴을 사용해서 인스턴스 생성을 제한할 수 있다.


싱글턴 패턴

싱글턴 패턴이란 객체의 인스턴스가 오직 1개만 생성 되는 패턴을 의미한다. 싱글턴 패턴의 이점은 메모리 측면이 있다. 최초 한번의 new 연산자를 통해서 고정된 메모리 영역을 사용하기 때문에 해당 객체에 접근할 때 메모리 낭비를 방지할 수 있다. 그리고 이미 생성된 인스턴스를 활용하면서 속도 측면에서도 이점이 있다.

싱글턴 패턴은 데이터 공유가 쉽다. 싱글톤 인스턴스는 전역으로 사용되기 때문에 다른 클래스 인스턴스들이 접근하여 사용할 수 있다. 하지만 여러 클래스의 인스턴스에서 싱글톤 인스턴스의 데이터에 동시에 접근하게 되면 동시성 문제가 발생할 수 있다.

package view;

import utils.InputValidator;

import java.util.Arrays;
import java.util.List;
import java.util.Scanner;
import java.util.stream.Collectors;

public class InputView {

    private static final String PURCHASE_AMOUNT_INPUT_MESSAGE = "구입금액을 입력해 주세요.";
    private static final String WINNING_NUMBER_INPUT_MESSAGE = "지난 주 당첨 번호를 입력해 주세요.";
    private static final String BONUS_BALL_INPUT_MESSAGE = "보너스 볼을 입력해 주세요.";
    private static final String DELIMITER = ",";

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

    private static final InputView inputView = new InputView();

    private InputView() {
    }

    public static InputView getInstance() {
        return inputView;
    }

    private String input() {
        String input = scanner.nextLine();
        InputValidator.validateNull(input);
        InputValidator.validateEmpty(input);
        return input;
    }

    public int inputPurchaseAmount() {
        System.out.println(PURCHASE_AMOUNT_INPUT_MESSAGE);
        return Integer.parseInt(input());
    }

    public List<Integer> inputWinningNumber() {
        System.out.println(WINNING_NUMBER_INPUT_MESSAGE);
        List<String> numberValues = toStrings(input());
        return toNumbers(numberValues);
    }

    private List<String> toStrings(String stringArray) {
        return Arrays.stream(stringArray.split(DELIMITER))
                .map(String::trim)
                .collect(Collectors.toList());
    }

    private List<Integer> toNumbers(List<String> numberValues) {
        return numberValues.stream()
                .map(Integer::parseInt)
                .collect(Collectors.toList());
    }

    public int inputBonusBall() {
        System.out.println(BONUS_BALL_INPUT_MESSAGE);
        return Integer.parseInt(input());
    }
}

public class Application {
    public static void main(String[] args) {
        InputView inputView = InputView.getInstance();
        OutputView outputView = OutputView.getInstance();
        LottoController lottoController = new LottoController();

        LottosDto lottosDto = lottoController.purchase(inputView.inputPurchaseAmount());
        outputView.printPurchasedLotto(lottosDto);

        lottoController.determineWinningNumber(inputView.inputWinningNumber(), inputView.inputBonusBall());

        outputView.printResult(lottoController.makeResult());
    }
}

Categories:

Updated: