Skip to content
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
26 changes: 25 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1 +1,25 @@
# All-rounder Backend Study
# 🖨️ mission-printer 🖨

## 기능 명세

- 입출력
- 숫자로 구성된 문자열 입력
- 숫자 입력
- 안내 출력
- 여러 문자열 출력

- 아스키 아트 변환
- 문자열 -> 아스키아트 변환
- 아스키아트 병합

- 잉크 관리
- 잉크 확인 및 출력 제한
- 잉크 보충

## 구현 계획
AsciiGenerator
- 아스키아트 생성 및 변환

Printer
- 잉크 관리, 출력 요청

20 changes: 20 additions & 0 deletions src/main/java/mission/AppConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package mission;

import mission.controller.PrinterController;
import mission.model.Printer;
import mission.view.InputView;
import mission.view.OutputView;

public class AppConfig {
public InputView inputView() {
return new InputView();
}

public OutputView outputView() {
return new OutputView();
}

public PrinterController printerController() {
return new PrinterController(inputView(), outputView());
}
}
6 changes: 6 additions & 0 deletions src/main/java/mission/Application.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
package mission;

import mission.controller.PrinterController;

public class Application {
public static void main(String[] args) {
//Todo: 프로그램 구현
AppConfig appConfig = new AppConfig();
PrinterController printerController = appConfig.printerController();

printerController.run();
}
}
9 changes: 9 additions & 0 deletions src/main/java/mission/ProgramTerminateException.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package mission;

public class ProgramTerminateException extends RuntimeException {
public ProgramTerminateException() {}

public ProgramTerminateException(String message) {
super(message);
}
}
76 changes: 76 additions & 0 deletions src/main/java/mission/controller/PrinterController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
package mission.controller;

import mission.ProgramTerminateException;
import mission.interfaces.PrintInterface;
import mission.model.AsciiGenerator;
import mission.model.Printer;
import mission.utils.Utility;
import mission.utils.Validator;
import mission.view.InputView;
import mission.view.OutputView;

public class PrinterController {
InputView inputView;
OutputView outputView;
AsciiGenerator asciiGenerator;
Printer printer;

public PrinterController(InputView inputView, OutputView outputView) {
class PrintInterfaceImpl implements PrintInterface {
@Override
public void print(String body) {
outputView.printMessage(body);
}
}

this.inputView = inputView;
this.outputView = outputView;
asciiGenerator = new AsciiGenerator();
printer = new Printer(new PrintInterfaceImpl());
}

public void run() {
outputView.printerExecuteMessage();
while (true) {
try {
execute();
} catch (ProgramTerminateException exception) {
break;
} catch (Exception exception) {
outputView.printMessage(exception.getMessage());
}
}
outputView.printTerminateMessage();
}

private void execute() {
int selected = inputView.getFeatureSelection();
if (selected == 1) {
print();
return;
}
if (selected == 2) {
outputView.showInk(printer.getInk(), printer.getMaxInk());
return;
}
if (selected == 3) {
printer.setInk();
outputView.chargedInk();
return;
}
if (selected == 4) {
throw new ProgramTerminateException();
}
throw new IllegalArgumentException("[ERROR] 잘못된 입력입니다.");
Copy link

Choose a reason for hiding this comment

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

여기처럼 에러 메세지를 출력하는 부분에서 에러 메시지를 직접 하드코딩하는 것이 아닌 모든 메시지를 하나의 클래스에 상수로 정의한다면 어떨까 싶어요. 클래스에 정의해서 사용한다면 메시지 수정이 편해지고, 혹시 모를 실수를 방지할 수 있을 것 같아요

}

private void print() {
String line = inputView.getNumberLine();
Validator.composeNumeric(line);

int length = inputView.getLineLength();
Validator.positiveInteger(length);

printer.print(asciiGenerator.generateAsciiPrintout(Utility.stringToIntegers(line), length));
}
}
5 changes: 5 additions & 0 deletions src/main/java/mission/interfaces/PrintInterface.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package mission.interfaces;

public interface PrintInterface {
void print(String body);
}
74 changes: 74 additions & 0 deletions src/main/java/mission/model/AsciiGenerator.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
package mission.model;

import java.io.IOException;
import java.net.URISyntaxException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.stream.Stream;
import mission.utils.Utility;

public class AsciiGenerator {
private final List<List<String>> data;

static private final List<String> fileNames = List.of(
"zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine"
);
static private final int ASCII_HEIGHT = 5;

public AsciiGenerator() {
data = new ArrayList<>();
fileNames.forEach(fileName -> {
try {
Path path = Paths.get(Objects.requireNonNull(
getClass().getClassLoader().getResource("numberAsciiDesign/" + fileName + ".txt")
).toURI());
String content = Files.readString(path);

List<String> paddedLines = Arrays.stream(content.split("\n"))
.map(line -> String.format("%-3s", line))
.toList();

data.add(paddedLines);
} catch (URISyntaxException | IOException e) {
throw new IllegalStateException("[ERROR] 아스키아트를 로드하지 못했습니다.");
}
});
}

public List<String> getNumberAsciiDesign(int number) {
try {
return data.get(number);
} catch (IndexOutOfBoundsException e) {
throw new IllegalStateException("[ERROR] 범위를 초과했습니다. ");
}
}

private List<List<String>> getNumberAsciiDesign(List<Integer> numbers) {
return numbers.stream().map(this::getNumberAsciiDesign).toList();
}

private List<String> concatAsciiLine(List<List<String>> lines) {
return IntStream.range(0, ASCII_HEIGHT)
.mapToObj(lineIndex -> {
List<String> line = new ArrayList<>();
lines.forEach(ascii -> line.add(ascii.get(lineIndex)));
return String.join(" ", line);
})
.toList();
}

public List<String> generateAsciiPrintout(List<Integer> numbers, int width) {
return Utility.chunkList(numbers, width).stream()
.map(this::getNumberAsciiDesign)
.map(this::concatAsciiLine)
.flatMap(list -> Stream.concat(list.stream(), Stream.of("")))
.toList();
}
}
46 changes: 46 additions & 0 deletions src/main/java/mission/model/Printer.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package mission.model;

import java.util.List;
import mission.interfaces.PrintInterface;
import mission.utils.Utility;

public class Printer {
private static final int MAX_INK = 1000;

PrintInterface printInterface;
int ink;

public Printer(PrintInterface printInterface) {
this.printInterface = printInterface;
ink = MAX_INK;
}

public int getMaxInk() {
return MAX_INK;
}

public int getInk() {
return ink;
}

public void setInk() {
this.ink = MAX_INK;
}

public void print(List<String> lines) {
lines.forEach(line -> {
int consume = Utility.countNonWhitespaceChars(line);
if (consume > ink) {
lastPrint(line);
throw new IllegalStateException("잉크가 부족해 출력이 중단되었습니다.");
}
ink -= consume;
printInterface.print(line);
Copy link

Choose a reason for hiding this comment

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

Printer클래스에서 직접 출력하는 부분은 Controller 또는 View에서 담당하는 것이 책임이 명확하게 분리되어 유지보수가 편할 것 같습니다

});
}

public void lastPrint(String line) {
printInterface.print(Utility.substringUntilNthChar(line, '◼', ink));
ink = 0;
}
}
41 changes: 0 additions & 41 deletions src/main/java/mission/utils/AsciiGenerator.java

This file was deleted.

43 changes: 43 additions & 0 deletions src/main/java/mission/utils/Utility.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package mission.utils;

import java.util.ArrayList;
import java.util.List;

public class Utility {
public static <T> List<List<T>> chunkList(List<T> list, int chunkSize) {
int size = list.size();
List<List<T>> result = new ArrayList<>();

for (int i = 0; i < size; i += chunkSize) {
result.add(list.subList(i, Math.min(size, i + chunkSize)));
}

return result;
}

public static List<Integer> stringToIntegers(String line) {
return line.chars().map(c -> c - '0').boxed().toList();
}

public static int countNonWhitespaceChars(String line) {
if (line == null) return 0;
return (int) line.chars()
.filter(ch -> !Character.isWhitespace(ch))
.count();
}

public static String substringUntilNthChar(String str, char target, int n) {
int count = 0;

for (int i = 0; i < str.length(); i++) {
if (str.charAt(i) == target) {
count++;
if (count == n) {
return str.substring(0, i);
}
}
}

return str;
}
}
15 changes: 15 additions & 0 deletions src/main/java/mission/utils/Validator.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package mission.utils;

public class Validator {
public static void composeNumeric(String input) {
if (!input.matches("^[0-9]+$")) {
throw new IllegalStateException("[ERROR] 숫자가 아닌 문자가 포함되어 있습니다.");
}
}

public static void positiveInteger(int value) {
if (value <= 0) {
throw new IllegalStateException("[ERROR] 양수가 아닙니다.");
}
}
}
Loading