From 99765db70fb91bac5999a6956c8d0d2fe85fad31 Mon Sep 17 00:00:00 2001 From: MingyeomKim Date: Sat, 2 Dec 2023 20:47:11 +0900 Subject: [PATCH 01/18] =?UTF-8?q?docs:=20=EA=B8=B0=EB=8A=A5=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84=20=EB=AA=A9=EB=A1=9D=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/README.md | 45 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 docs/README.md diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 000000000..90821581a --- /dev/null +++ b/docs/README.md @@ -0,0 +1,45 @@ +## 사전 제공 정보 저장 + +크루 정보 저장 +크루 정보가 저장된 XML파일에서 크루 이름 목록을 불러온다. +List으로 변환하여 저장한다. +과정, 레벨, 미션 정보 저장 +과정, 레벨, 미션을 Enum class에서 정의한다. +정보를 그룹화하여 저장한다. + +## 실행할 기능을 선택하는 기능 + +`기능을 선택하세요.`를 출력한다. +`1. 페어 매칭 2. 페어 조회 3. 페어 초기화 Q. 종료`를 출력한다. +실행할 기능을 입력받는다. +1, 2, 3, Q에 해당하는 지 검증한다. + +## 페어 매칭 기능 + +과정, 레벨, 미션 정보를 출력한다. +`과정, 레벨, 미션을 선택하세요.\nex) 백엔드, 레벨1, 자동차경주`를 출력한다. +`프론트엔드, 레벨1, 자동차경주` 형식으로 입력 받는다. +빈 문자열인 경우를 검증한다. +올바른 구분자로 입력되었음을 검증한다. +과정이 백엔드 혹은 프론트엔드 임을 검증한다. +레벨이 레벨1, 레벨2, 레벨3, 레벨4, 레벨5 중 하나임을 검증한다. +미션이 존재하는 미션임을 검증한다. +이미 매칭 정보가 있는 경우 +`매칭 정보가 있습니다. 다시 매칭하시겠습니까?`를 출력한다. +`네` 입력 시 매칭 후 결과를 다시 저장한다. +`아니오` 입력 시 코스, 레벨, 미션을 다시 선택한다. +네/아니오 이외의 입력 시 예외를 발생한다. +크루 목록을 랜덤으로 섞는다. +앞에서부터 두 명씩 페어를 묶는다. +만약, 같은 레벨에서 만난 페어가 있다면 다시 섞고 매칭한다. (3회 반복) +3회 시도까지 매칭이 되지 않았다면 에러 메시지를 출력한다. +해당 레벨에서 짝지어진 페어의 목록을 저장한다. + +## 페어 조회 기능 + +과정, 레벨, 미션을 선택하면 해당 미션의 페어 정보를 출력한다. +매칭 이력이 없으면 `[ERROR] 매칭 이력이 없습니다.`를 출력한다. + +## 페어 초기화 기능 + +모든 미션에 대한 페어 매칭 정보를 초기화한다. From 19a49c15e6717635b8da59a17ff85c340c00a7d9 Mon Sep 17 00:00:00 2001 From: MingyeomKim Date: Sun, 3 Dec 2023 00:57:33 +0900 Subject: [PATCH 02/18] =?UTF-8?q?docs:=20=EA=B8=B0=EB=8A=A5=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84=20=EB=AA=A9=EB=A1=9D=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/README.md b/docs/README.md index 90821581a..f8bc196c0 100644 --- a/docs/README.md +++ b/docs/README.md @@ -32,6 +32,8 @@ List으로 변환하여 저장한다. 크루 목록을 랜덤으로 섞는다. 앞에서부터 두 명씩 페어를 묶는다. 만약, 같은 레벨에서 만난 페어가 있다면 다시 섞고 매칭한다. (3회 반복) +같은 레벨에 있는 모든 미션의 매칭 정보를 불러온다. +이미 매칭된 바가 있는 페어라면 재시도한다. 3회 시도까지 매칭이 되지 않았다면 에러 메시지를 출력한다. 해당 레벨에서 짝지어진 페어의 목록을 저장한다. From 8be899b17871f3932fa3516d32b5695a245f4ea7 Mon Sep 17 00:00:00 2001 From: MingyeomKim Date: Sun, 3 Dec 2023 00:57:57 +0900 Subject: [PATCH 03/18] =?UTF-8?q?feat:=20Application=EC=97=90=EC=84=9C=20?= =?UTF-8?q?=ED=95=A8=EC=88=98=20=EC=8B=A4=ED=96=89=20=EC=BD=94=EB=93=9C=20?= =?UTF-8?q?=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/pairmatching/Application.java | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/src/main/java/pairmatching/Application.java b/src/main/java/pairmatching/Application.java index 6f56e741c..4b7dcadc7 100644 --- a/src/main/java/pairmatching/Application.java +++ b/src/main/java/pairmatching/Application.java @@ -1,7 +1,23 @@ package pairmatching; +import org.xml.sax.SAXException; +import pairmatching.controller.PairController; +import pairmatching.domain.Crews; +import pairmatching.domain.Matching; +import pairmatching.service.CrewService; +import pairmatching.service.MatchingService; + +import javax.xml.parsers.ParserConfigurationException; +import java.io.IOException; + public class Application { - public static void main(String[] args) { - // TODO 구현 진행 + public static void main(String[] args) throws ParserConfigurationException, IOException, SAXException { + CrewService crewService = new CrewService(new Crews()); + PairController pairController = new PairController( + crewService, + new MatchingService(crewService, new Matching()) + ); + + pairController.run(); } } From 5ac97a3d72229cced286eb30c8d27492ac66f6a9 Mon Sep 17 00:00:00 2001 From: MingyeomKim Date: Sun, 3 Dec 2023 01:00:04 +0900 Subject: [PATCH 04/18] =?UTF-8?q?feat:=20=ED=8E=98=EC=96=B4=20=EC=A0=95?= =?UTF-8?q?=EB=B3=B4=EB=A5=BC=20=EC=A0=84=EB=8B=AC=ED=95=98=EB=8A=94=20DTO?= =?UTF-8?q?=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/dto/request/PairRequest.java | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 src/main/java/pairmatching/controller/dto/request/PairRequest.java diff --git a/src/main/java/pairmatching/controller/dto/request/PairRequest.java b/src/main/java/pairmatching/controller/dto/request/PairRequest.java new file mode 100644 index 000000000..327e125b9 --- /dev/null +++ b/src/main/java/pairmatching/controller/dto/request/PairRequest.java @@ -0,0 +1,23 @@ +package pairmatching.controller.dto.request; + +import pairmatching.domain.constants.Course; +import pairmatching.domain.constants.Level; +import pairmatching.domain.constants.Mission; + +public class PairRequest { + private Course course; + private Level level; + private Mission mission; + + public Course course() { + return course; + } + + public Level level() { + return level; + } + + public Mission mission() { + return mission; + } +} From 4365a404121f03207cdd7e071766c200d0ce63bd Mon Sep 17 00:00:00 2001 From: MingyeomKim Date: Sun, 3 Dec 2023 01:00:31 +0900 Subject: [PATCH 05/18] =?UTF-8?q?feat:=20=ED=8E=98=EC=96=B4=20=EC=A0=80?= =?UTF-8?q?=EC=9E=A5,=20=EC=A1=B0=ED=9A=8C,=20=EC=B4=88=EA=B8=B0=ED=99=94?= =?UTF-8?q?=ED=95=98=EB=8A=94=20=EC=BD=94=EB=93=9C=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/PairController.java | 95 +++++++++++++++++++ 1 file changed, 95 insertions(+) create mode 100644 src/main/java/pairmatching/controller/PairController.java diff --git a/src/main/java/pairmatching/controller/PairController.java b/src/main/java/pairmatching/controller/PairController.java new file mode 100644 index 000000000..670ced4f6 --- /dev/null +++ b/src/main/java/pairmatching/controller/PairController.java @@ -0,0 +1,95 @@ +package pairmatching.controller; + +import java.util.function.Supplier; + +import pairmatching.controller.dto.request.PairRequest; +import pairmatching.domain.Pairs; +import pairmatching.service.CrewService; +import pairmatching.service.MatchingService; +import pairmatching.view.ClearPairView; +import pairmatching.view.FunctionRequestView; +import pairmatching.view.PairRequestView; +import pairmatching.view.PairResponseView; +import pairmatching.view.RematchRequestView; +import pairmatching.view.console.ConsoleWriter; + +public class PairController { + private final CrewService crewService; + private final MatchingService matchingService; + + public PairController( + CrewService crewService, + MatchingService matchingService + ) { + this.crewService = crewService; + this.matchingService = matchingService; + } + + public void run() { + while (true) { + String input = FunctionRequestView.request(); + if (input == "Q") { + break; + } + if (input == "1") { + savePairs(); + } + if (input == "2") { + getPairs(); + } + if (input == "3") { + clearPairs(); + } + } + } + + // 페어 매칭 기능 + public void savePairs() { + PairRequest matchingRequest = getMatchingRequest(); + Pairs pairs = matchingService.generateMatching( + matchingRequest.course(), + matchingRequest.mission() + ); + PairResponseView.response(pairs); + } + + public PairRequest getMatchingRequest() { + while (true) { + PairRequest pairRequest = PairRequestView.request(); + if (matchingService.hasNoPairs(pairRequest.mission())) { + return pairRequest; + } + // 이미 매칭된 미션인 경우 + boolean rematch = RematchRequestView.request(); + if (rematch) { + return pairRequest; + } + } + } + + // 페어 조회 기능 + public void getPairs() { + Pairs pairs = retry(() -> { + return matchingService.getPairs( + PairRequestView.request().mission() + ); + }); + PairResponseView.response(pairs); + } + + // 페어 초기화 기능 + public void clearPairs() { + matchingService.clear(); + ClearPairView.response(); + } + + private static T retry(Supplier supplier) { + while (true) { + try { + return supplier.get(); + } catch (IllegalArgumentException e) { + ConsoleWriter.printlnMessage(e.getMessage()); + } + } + } +} From 04b7ef82a88941e8c128ee19811a68b5beb0e242 Mon Sep 17 00:00:00 2001 From: MingyeomKim Date: Sun, 3 Dec 2023 01:04:23 +0900 Subject: [PATCH 06/18] =?UTF-8?q?feat:=20=EA=B0=95=EC=9D=98=20=EC=A0=95?= =?UTF-8?q?=EB=B3=B4=EB=A5=BC=20=EC=A0=80=EC=9E=A5=ED=95=98=EB=8A=94=20?= =?UTF-8?q?=EC=83=81=EC=88=98=20=ED=81=B4=EB=9E=98=EC=8A=A4=20=EC=A0=95?= =?UTF-8?q?=EC=9D=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/pairmatching/Application.java | 3 +- .../controller/dto/request/PairRequest.java | 6 ++++ .../pairmatching/domain/constants/Course.java | 28 +++++++++++++++++++ 3 files changed, 35 insertions(+), 2 deletions(-) create mode 100644 src/main/java/pairmatching/domain/constants/Course.java diff --git a/src/main/java/pairmatching/Application.java b/src/main/java/pairmatching/Application.java index 4b7dcadc7..c8e43bfd7 100644 --- a/src/main/java/pairmatching/Application.java +++ b/src/main/java/pairmatching/Application.java @@ -2,7 +2,6 @@ import org.xml.sax.SAXException; import pairmatching.controller.PairController; -import pairmatching.domain.Crews; import pairmatching.domain.Matching; import pairmatching.service.CrewService; import pairmatching.service.MatchingService; @@ -12,7 +11,7 @@ public class Application { public static void main(String[] args) throws ParserConfigurationException, IOException, SAXException { - CrewService crewService = new CrewService(new Crews()); + CrewService crewService = new CrewService(); PairController pairController = new PairController( crewService, new MatchingService(crewService, new Matching()) diff --git a/src/main/java/pairmatching/controller/dto/request/PairRequest.java b/src/main/java/pairmatching/controller/dto/request/PairRequest.java index 327e125b9..09a052dd4 100644 --- a/src/main/java/pairmatching/controller/dto/request/PairRequest.java +++ b/src/main/java/pairmatching/controller/dto/request/PairRequest.java @@ -9,6 +9,12 @@ public class PairRequest { private Level level; private Mission mission; + public PairRequest(Course course, Level level, Mission mission) { + this.course = course; + this.level = level; + this.mission = mission; + } + public Course course() { return course; } diff --git a/src/main/java/pairmatching/domain/constants/Course.java b/src/main/java/pairmatching/domain/constants/Course.java new file mode 100644 index 000000000..365733c92 --- /dev/null +++ b/src/main/java/pairmatching/domain/constants/Course.java @@ -0,0 +1,28 @@ +package pairmatching.domain.constants; + +import pairmatching.global.exception.CustomException; +import pairmatching.global.exception.ErrorMessage; + +public enum Course { + BACKEND("백엔드"), + FRONTEND("프론트엔드"); + + private String name; + + Course(String name) { + this.name = name; + } + + public String getName() { + return name; + } + + public static Course getCourse(String name) { + for (Course course : Course.values()) { + if (course.name().equals(name)) { + return course; + } + } + throw CustomException.from(ErrorMessage.INVALID_PAIR_REQUEST); + } +} From 591d36ae0a375c716fe3ad915f986dd42e947b29 Mon Sep 17 00:00:00 2001 From: MingyeomKim Date: Sun, 3 Dec 2023 01:04:41 +0900 Subject: [PATCH 07/18] =?UTF-8?q?feat:=20=EB=A0=88=EB=B2=A8=EC=9D=84=20?= =?UTF-8?q?=EA=B4=80=EB=A6=AC=ED=95=98=EB=8A=94=20=EC=83=81=EC=88=98=20?= =?UTF-8?q?=ED=81=B4=EB=9E=98=EC=8A=A4=20=EC=A0=95=EC=9D=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../pairmatching/domain/constants/Level.java | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 src/main/java/pairmatching/domain/constants/Level.java diff --git a/src/main/java/pairmatching/domain/constants/Level.java b/src/main/java/pairmatching/domain/constants/Level.java new file mode 100644 index 000000000..e4f4fe7dd --- /dev/null +++ b/src/main/java/pairmatching/domain/constants/Level.java @@ -0,0 +1,27 @@ +package pairmatching.domain.constants; + +import pairmatching.global.exception.CustomException; +import pairmatching.global.exception.ErrorMessage; + +public enum Level { + LEVEL1("레벨1"), + LEVEL2("레벨2"), + LEVEL3("레벨3"), + LEVEL4("레벨4"), + LEVEL5("레벨5"); + + private String name; + + Level(String name) { + this.name = name; + } + + public static Level getLevel(String name) { + for (Level level : Level.values()) { + if (level.name().equals(name)) { + return level; + } + } + throw CustomException.from(ErrorMessage.INVALID_PAIR_REQUEST); + } +} From 468b5c97c30a0fc899667aa1429cbbcfbbb4232e Mon Sep 17 00:00:00 2001 From: MingyeomKim Date: Sun, 3 Dec 2023 01:04:57 +0900 Subject: [PATCH 08/18] =?UTF-8?q?feat:=20=EB=AF=B8=EC=85=98=EC=9D=84=20?= =?UTF-8?q?=EC=A0=80=EC=9E=A5=ED=95=98=EB=8A=94=20=EC=83=81=EC=88=98=20?= =?UTF-8?q?=ED=81=B4=EB=9E=98=EC=8A=A4=20=EC=A0=95=EC=9D=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/constants/Mission.java | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 src/main/java/pairmatching/domain/constants/Mission.java diff --git a/src/main/java/pairmatching/domain/constants/Mission.java b/src/main/java/pairmatching/domain/constants/Mission.java new file mode 100644 index 000000000..362607bd4 --- /dev/null +++ b/src/main/java/pairmatching/domain/constants/Mission.java @@ -0,0 +1,38 @@ +package pairmatching.domain.constants; + +import pairmatching.global.exception.CustomException; +import pairmatching.global.exception.ErrorMessage; + +public enum Mission { + RACING_CAR("자동차경주", Level.LEVEL1), + LOTTO("로또", Level.LEVEL1), + BASEBALL_GAME("숫자야구게임", Level.LEVEL1), + + SHOPPING_BASKET("장바구니", Level.LEVEL2), + PAYMENT("결제", Level.LEVEL2), + SUBWAY_MAP("지하철노선도", Level.LEVEL2), + + PERFORMANCE_IMPROVEMENT("성능개선", Level.LEVEL4), + DEPLOYMENT("배포", Level.LEVEL4); + + private final String name; + private final Level level; + + Mission(String name, Level level) { + this.name = name; + this.level = level; + } + + public Level getLevel() { + return level; + } + + public static Mission getMission(String name) { + for (Mission mission : Mission.values()) { + if (mission.name().equals(name)) { + return mission; + } + } + throw CustomException.from(ErrorMessage.INVALID_PAIR_REQUEST); + } +} From 42b2cf22d4a9f70691dc5a965947e4058edb942b Mon Sep 17 00:00:00 2001 From: MingyeomKim Date: Sun, 3 Dec 2023 01:05:09 +0900 Subject: [PATCH 09/18] =?UTF-8?q?feat:=20=ED=81=AC=EB=A3=A8=EC=9D=98=20?= =?UTF-8?q?=EC=A0=95=EB=B3=B4=EB=A5=BC=20=EC=A0=80=EC=9E=A5=ED=95=98?= =?UTF-8?q?=EB=8A=94=20=EB=8F=84=EB=A9=94=EC=9D=B8=20=EA=B0=9D=EC=B2=B4=20?= =?UTF-8?q?=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/pairmatching/domain/Crews.java | 35 ++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 src/main/java/pairmatching/domain/Crews.java diff --git a/src/main/java/pairmatching/domain/Crews.java b/src/main/java/pairmatching/domain/Crews.java new file mode 100644 index 000000000..638efaaf6 --- /dev/null +++ b/src/main/java/pairmatching/domain/Crews.java @@ -0,0 +1,35 @@ +package pairmatching.domain; + +import pairmatching.domain.constants.Course; + +import java.util.ArrayList; +import java.util.List; + +public class Crews { + private List backend; + private List frontend; + + public Crews() { + this.backend = new ArrayList<>(); + this.frontend = new ArrayList<>(); + } + + public void add(Course course, List names) { + if (course.equals(Course.BACKEND)) { + backend.addAll(names); + } + if (course.equals(Course.FRONTEND)) { + frontend.addAll(names); + } + } + + public List getCrews(Course course) { + if (course.equals(Course.BACKEND)) { + return backend; + } + if (course.equals(Course.FRONTEND)) { + return frontend; + } + throw new IllegalStateException("적합하지 않은 과정 입력입니다."); + } +} From e96fa49763afe181a4613d5178b6e4328fcb4ad6 Mon Sep 17 00:00:00 2001 From: MingyeomKim Date: Sun, 3 Dec 2023 01:05:30 +0900 Subject: [PATCH 10/18] =?UTF-8?q?feat:=20=ED=8C=8C=EC=9D=BC=EC=9D=84=20?= =?UTF-8?q?=EC=9D=BD=EC=96=B4=EC=99=80=20=ED=81=AC=EB=A3=A8=EC=9D=98=20?= =?UTF-8?q?=EC=A0=95=EB=B3=B4=EB=A5=BC=20=EC=83=9D=EC=84=B1=ED=95=98?= =?UTF-8?q?=EB=8A=94=20=EA=B8=B0=EB=8A=A5=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../pairmatching/service/CrewService.java | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 src/main/java/pairmatching/service/CrewService.java diff --git a/src/main/java/pairmatching/service/CrewService.java b/src/main/java/pairmatching/service/CrewService.java new file mode 100644 index 000000000..c259a1837 --- /dev/null +++ b/src/main/java/pairmatching/service/CrewService.java @@ -0,0 +1,34 @@ +package pairmatching.service; + +import org.xml.sax.SAXException; +import pairmatching.domain.Crews; +import pairmatching.domain.constants.Course; +import pairmatching.util.XMLParser; + +import javax.xml.parsers.ParserConfigurationException; +import java.io.IOException; +import java.util.List; + +public class CrewService { + private final Crews crews; + + public CrewService() throws ParserConfigurationException, IOException, SAXException { + this.crews = generateCrews(); + } + + public Crews generateCrews() throws ParserConfigurationException, IOException, SAXException { + XMLParser xmlParser = new XMLParser(); + List backend = xmlParser.parseName(Course.BACKEND); + List frontend = xmlParser.parseName(Course.FRONTEND); + + Crews crews = new Crews(); + crews.add(Course.BACKEND, backend); + crews.add(Course.FRONTEND, frontend); + + return crews; + } + + public List getCrews(Course course) { + return crews.getCrews(course); + } +} From 9b542b0b48376380305199e389a08dc0b1ea5d98 Mon Sep 17 00:00:00 2001 From: MingyeomKim Date: Sun, 3 Dec 2023 01:05:55 +0900 Subject: [PATCH 11/18] =?UTF-8?q?feat:=20=ED=8E=98=EC=96=B4=EB=A5=BC=20?= =?UTF-8?q?=EC=83=9D=EC=84=B1=ED=95=98=EA=B3=A0=20=EB=A7=A4=EC=B9=AD=20?= =?UTF-8?q?=EC=A0=95=EB=B3=B4=EB=A5=BC=20=EC=A0=80=EC=9E=A5=ED=95=98?= =?UTF-8?q?=EB=8A=94=20=EA=B8=B0=EB=8A=A5=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../pairmatching/service/MatchingService.java | 102 ++++++++++++++++++ 1 file changed, 102 insertions(+) create mode 100644 src/main/java/pairmatching/service/MatchingService.java diff --git a/src/main/java/pairmatching/service/MatchingService.java b/src/main/java/pairmatching/service/MatchingService.java new file mode 100644 index 000000000..447944fdc --- /dev/null +++ b/src/main/java/pairmatching/service/MatchingService.java @@ -0,0 +1,102 @@ +package pairmatching.service; + +import java.util.List; + +import camp.nextstep.edu.missionutils.Randoms; +import pairmatching.domain.Matching; +import pairmatching.domain.Pair; +import pairmatching.domain.Pairs; +import pairmatching.domain.constants.Course; +import pairmatching.domain.constants.Mission; +import pairmatching.global.exception.CustomException; +import pairmatching.global.exception.ErrorMessage; + +public class MatchingService { + private static final int MAX_MATCHING_COUNT = 3; + private final CrewService crewService; + private Matching matching; + + public MatchingService(CrewService crewService, Matching matching) { + this.crewService = crewService; + this.matching = matching; + } + + public Pairs getPairs(Mission mission) { + return matching.getPairs(mission); + } + + /** + * 주어진 미션에 대한 매칭 정보가 없음을 검증하는 메서드 + * @return 매칭 정보가 없는 상태인 미션이라면 true, 그렇지 않다면 false + */ + public boolean hasNoPairs(Mission enteredMission) { + return matching.isEmpty(enteredMission); + } + + /** + * 3회에 걸쳐 페어를 생성하고, 유효한 매칭 정보인 경우 매칭 정보를 저장하는 메서드 + * @param mission 페어를 생성할 미션 + * @return 새로 생성한 페어. 매칭에 실패하면 에러를 반환 + */ + public Pairs generateMatching(Course course, Mission mission) { + for (int i = 0; i < MAX_MATCHING_COUNT; i++) { + Pairs generatedPairs = generatePairs(course); + boolean canMatch = hasNotDuplicatedMatching(mission, generatedPairs); + if (canMatch) { + matching.save(mission, generatedPairs); + return generatedPairs; + } + } + throw CustomException.from(ErrorMessage.CANNOT_MATCHING_ERROR); + } + + public Pairs generatePairs(Course course) { + Pairs pairs = new Pairs(); + List crews = Randoms.shuffle(crewService.getCrews(course)); + + // 크루의 수가 홀수인 경우 + if (crews.size() % 2 == 1 && crews.size() >= 3) { + pairs.add(generateTripleCrew(crews)); + } + for (int i = 0; i < crews.size(); i += 2) { + pairs.add(generateCoupleCrew(crews.get(i), crews.get(i + 1))); + } + + return pairs; + } + + private Pair generateCoupleCrew(String crew1, String crew2) { + Pair pair = new Pair(); + pair.add(crew1); + pair.add(crew2); + return pair; + } + + private Pair generateTripleCrew(List crews) { + Pair pair = new Pair(); + for (int i = 0; i < 3; i++) { + int last = crews.size() - 1; + pair.add(crews.get(last)); + crews.remove(last); + } + return pair; + } + + /** + * 현재 미션의 레벨의 미션들과 중복되는 매칭 정보가 있는 지 확인하는 메서드 + * @return 중복되는 매칭 정보가 없다면 true, 중복되는 매칭 정보가 있다면 false + */ + private boolean hasNotDuplicatedMatching(Mission mission, Pairs pairs) { + List sameLevelPairs = matching.getSameLevelPairs(mission); + for (Pairs others : sameLevelPairs) { + if (pairs.duplicated(others)) { + return false; + } + } + return true; + } + + public void clear() { + matching.clear(); + } +} From bf66e5f458479eb7ed2010eea92c321c87ed1040 Mon Sep 17 00:00:00 2001 From: MingyeomKim Date: Sun, 3 Dec 2023 01:06:07 +0900 Subject: [PATCH 12/18] =?UTF-8?q?feat:=20=EB=A7=A4=EC=B9=AD=20=EC=A0=95?= =?UTF-8?q?=EB=B3=B4=EB=A5=BC=20=EC=A0=80=EC=9E=A5=ED=95=98=EA=B8=B0=20?= =?UTF-8?q?=EC=9C=84=ED=95=9C=20=EB=8F=84=EB=A9=94=EC=9D=B8=20=EA=B0=9D?= =?UTF-8?q?=EC=B2=B4=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/pairmatching/domain/Matching.java | 63 +++++++++++++++++++ 1 file changed, 63 insertions(+) create mode 100644 src/main/java/pairmatching/domain/Matching.java diff --git a/src/main/java/pairmatching/domain/Matching.java b/src/main/java/pairmatching/domain/Matching.java new file mode 100644 index 000000000..39bbde949 --- /dev/null +++ b/src/main/java/pairmatching/domain/Matching.java @@ -0,0 +1,63 @@ +package pairmatching.domain; + +import java.util.ArrayList; +import java.util.EnumMap; +import java.util.List; +import java.util.Map; + +import pairmatching.domain.constants.Mission; +import pairmatching.global.exception.CustomException; +import pairmatching.global.exception.ErrorMessage; + +public class Matching { + private Map matching; + + public Matching() { + matching = new EnumMap<>(Mission.class); + } + + /** + * 페어 생성 + */ + public void save(Mission mission, Pairs pairs) { + matching.put(mission, pairs); + } + + /** + * 페어 조회 + */ + public Pairs getPairs(Mission mission) { + if (matching.containsKey(mission)) { + return matching.get(mission); + } + throw CustomException.from(ErrorMessage.NO_MATCHING_HISTORY); + } + + /** + * 페어 초기화 + */ + public void clear() { + matching.clear(); + } + + /** + * 매칭 정보가 있음을 확인하는 메서드 + */ + public boolean isEmpty(Mission enteredMission) { + return !matching.containsKey(enteredMission); + } + + public List getSameLevelPairs(Mission mission) { + List pairs = new ArrayList<>(); + for (Mission others : matching.keySet()) { + if (others.equals(mission)) { + continue; + } + + if (others.getLevel() == mission.getLevel()) { + pairs.add(matching.get(mission)); + } + } + return pairs; + } +} From 72adbfd79fecc2b218675e651c9ebf235ba1332d Mon Sep 17 00:00:00 2001 From: MingyeomKim Date: Sun, 3 Dec 2023 01:06:24 +0900 Subject: [PATCH 13/18] =?UTF-8?q?feat:=20=ED=8E=98=EC=96=B4=EB=93=A4?= =?UTF-8?q?=EC=9D=98=20=EC=A7=91=ED=95=A9=EC=9D=84=20=EC=A0=80=EC=9E=A5?= =?UTF-8?q?=ED=95=98=EB=8A=94=20=EB=8F=84=EB=A9=94=EC=9D=B8=20=EA=B0=9D?= =?UTF-8?q?=EC=B2=B4=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/pairmatching/domain/Pair.java | 34 +++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 src/main/java/pairmatching/domain/Pair.java diff --git a/src/main/java/pairmatching/domain/Pair.java b/src/main/java/pairmatching/domain/Pair.java new file mode 100644 index 000000000..bb030cea3 --- /dev/null +++ b/src/main/java/pairmatching/domain/Pair.java @@ -0,0 +1,34 @@ +package pairmatching.domain; + +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; + +public class Pair { + private Set pair; + + public Pair() { + pair = new HashSet<>(); + } + + public void add(String name) { + pair.add(name); + } + + /** + * 두 페어가 중복 크루를 매칭하고 있음을 검증하는 메서드 + * @return 두 페어에 중복되는 크루가 두 명 이상 있으면 false, 그렇지 않다면 true + */ + public boolean duplicated(Pair other) { + Set combined = new HashSet<>(pair); + combined.retainAll(other.getPair()); + + return combined.size() >= 2; + } + + public Set getPair() { + return Collections.unmodifiableSet(pair); + } +} + + From f61cde75613d6de4480da91ead5810b73e3e4ddc Mon Sep 17 00:00:00 2001 From: MingyeomKim Date: Sun, 3 Dec 2023 01:06:43 +0900 Subject: [PATCH 14/18] =?UTF-8?q?feat:=20=ED=8E=98=EC=96=B4=EB=93=A4?= =?UTF-8?q?=EC=9D=84=20=EB=A6=AC=EC=8A=A4=ED=8A=B8=EB=A1=9C=20=EA=B4=80?= =?UTF-8?q?=EB=A6=AC=ED=95=98=EB=8A=94=20=EB=8F=84=EB=A9=94=EC=9D=B8=20?= =?UTF-8?q?=ED=81=B4=EB=9E=98=EC=8A=A4=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/pairmatching/domain/Pairs.java | 42 ++++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 src/main/java/pairmatching/domain/Pairs.java diff --git a/src/main/java/pairmatching/domain/Pairs.java b/src/main/java/pairmatching/domain/Pairs.java new file mode 100644 index 000000000..b6a4a869c --- /dev/null +++ b/src/main/java/pairmatching/domain/Pairs.java @@ -0,0 +1,42 @@ +package pairmatching.domain; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +public class Pairs { + private List pairs; + + public Pairs() { + this.pairs = new ArrayList<>(); + } + + public void add(Pair pair) { + pairs.add(pair); + } + + /** + * 서로 다른 미션의 매칭 정보를 비교하여, 중복되는 페어가 있는 지 확인 + */ + public boolean duplicated(Pairs others) { + for (Pair pair : pairs) { + if (duplicated(pair, others)) { + return false; + } + } + return true; + } + + private boolean duplicated(Pair pair, Pairs others) { + for (Pair other : others.getPairs()) { + if (pair.duplicated(other)) { + return false; + } + } + return true; + } + + public List getPairs() { + return Collections.unmodifiableList(pairs); + } +} From e678abefb6ef6a8bf593e6cddff0074d1e28f354 Mon Sep 17 00:00:00 2001 From: MingyeomKim Date: Sun, 3 Dec 2023 01:07:00 +0900 Subject: [PATCH 15/18] =?UTF-8?q?feat:=20=EC=98=88=EC=99=B8=EC=B2=98?= =?UTF-8?q?=EB=A6=AC=20=ED=81=B4=EB=9E=98=EC=8A=A4=EC=99=80=20=EC=98=88?= =?UTF-8?q?=EC=99=B8=EC=B2=98=EB=A6=AC=20=EB=A9=94=EC=8B=9C=EC=A7=80?= =?UTF-8?q?=EB=A5=BC=20=EC=A0=84=EC=97=AD=20=ED=81=B4=EB=9E=98=EC=8A=A4?= =?UTF-8?q?=EC=97=90=EC=84=9C=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../global/exception/CustomException.java | 13 +++++++++++++ .../global/exception/ErrorMessage.java | 19 +++++++++++++++++++ 2 files changed, 32 insertions(+) create mode 100644 src/main/java/pairmatching/global/exception/CustomException.java create mode 100644 src/main/java/pairmatching/global/exception/ErrorMessage.java diff --git a/src/main/java/pairmatching/global/exception/CustomException.java b/src/main/java/pairmatching/global/exception/CustomException.java new file mode 100644 index 000000000..32271d86d --- /dev/null +++ b/src/main/java/pairmatching/global/exception/CustomException.java @@ -0,0 +1,13 @@ +package pairmatching.global.exception; + +public class CustomException extends IllegalArgumentException { + private static final String PREFIX = "[ERROR] "; + + private CustomException(ErrorMessage errorMessage) { + super(PREFIX + errorMessage.getMessage()); + } + + public static CustomException from(ErrorMessage errorMessage) { + return new CustomException(errorMessage); + } +} diff --git a/src/main/java/pairmatching/global/exception/ErrorMessage.java b/src/main/java/pairmatching/global/exception/ErrorMessage.java new file mode 100644 index 000000000..50e0fb366 --- /dev/null +++ b/src/main/java/pairmatching/global/exception/ErrorMessage.java @@ -0,0 +1,19 @@ +package pairmatching.global.exception; + +public enum ErrorMessage { + NO_MATCHING_HISTORY("매칭 이력이 없습니다."), + BLANK_INPUT_ERROR("빈 문자열이 입력되었습니다."), + INVALID_PAIR_REQUEST("과정, 레벨, 미션을 다시 입력해주세요."), + INVALID_REMATCH_REQUEST("네 혹은 아니오를 입력해주세요."), + CANNOT_MATCHING_ERROR("페어 매칭에 실패하였습니다."), + INVALID_FUNCTION_REQUEST("잘못된 기능 번호를 입력하였습니다."); + private final String message; + + ErrorMessage(String message) { + this.message = message; + } + + public String getMessage() { + return this.message; + } +} From 0a96317072347f53065a9daa8c86f29eed1770dc Mon Sep 17 00:00:00 2001 From: MingyeomKim Date: Sun, 3 Dec 2023 01:07:28 +0900 Subject: [PATCH 16/18] =?UTF-8?q?feat:=20=EC=BD=98=EC=86=94=EC=97=90?= =?UTF-8?q?=EC=84=9C=20=ED=95=84=EC=9A=94=ED=95=9C=20=EC=9E=85=EC=B6=9C?= =?UTF-8?q?=EB=A0=A5=EC=9D=84=20=EA=B4=80=EB=A6=AC=ED=95=98=EB=8A=94=20?= =?UTF-8?q?=EB=B7=B0=20=ED=81=B4=EB=9E=98=EC=8A=A4=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/pairmatching/view/ClearPairView.java | 11 ++++ .../view/FunctionRequestView.java | 35 ++++++++++ .../pairmatching/view/PairRequestView.java | 66 +++++++++++++++++++ .../pairmatching/view/PairResponseView.java | 56 ++++++++++++++++ .../pairmatching/view/RematchRequestView.java | 29 ++++++++ .../view/console/ConsoleReader.java | 24 +++++++ .../view/console/ConsoleWriter.java | 15 +++++ 7 files changed, 236 insertions(+) create mode 100644 src/main/java/pairmatching/view/ClearPairView.java create mode 100644 src/main/java/pairmatching/view/FunctionRequestView.java create mode 100644 src/main/java/pairmatching/view/PairRequestView.java create mode 100644 src/main/java/pairmatching/view/PairResponseView.java create mode 100644 src/main/java/pairmatching/view/RematchRequestView.java create mode 100644 src/main/java/pairmatching/view/console/ConsoleReader.java create mode 100644 src/main/java/pairmatching/view/console/ConsoleWriter.java diff --git a/src/main/java/pairmatching/view/ClearPairView.java b/src/main/java/pairmatching/view/ClearPairView.java new file mode 100644 index 000000000..a11126ec7 --- /dev/null +++ b/src/main/java/pairmatching/view/ClearPairView.java @@ -0,0 +1,11 @@ +package pairmatching.view; + +import pairmatching.view.console.ConsoleWriter; + +public final class ClearPairView { + private static final String NOTICE = "초기화 되었습니다."; + + public static void response() { + ConsoleWriter.printlnMessage(NOTICE); + } +} diff --git a/src/main/java/pairmatching/view/FunctionRequestView.java b/src/main/java/pairmatching/view/FunctionRequestView.java new file mode 100644 index 000000000..fcb2fc1af --- /dev/null +++ b/src/main/java/pairmatching/view/FunctionRequestView.java @@ -0,0 +1,35 @@ +package pairmatching.view; + +import java.util.Arrays; +import java.util.List; + +import pairmatching.global.exception.CustomException; +import pairmatching.global.exception.ErrorMessage; +import pairmatching.view.console.ConsoleReader; +import pairmatching.view.console.ConsoleWriter; + +public final class FunctionRequestView { + private static final String NOTICE = "기능을 선택하세요."; + private static final String RESPONSE_TYPE = + "1. 페어 매칭\n" + + "2. 페어 조회\n" + + "3. 페어 초기화\n" + + "Q. 종료"; + private static final List RESPONSES = + Arrays.asList("1", "2", "3", "Q"); + + public static String request() { + ConsoleWriter.printlnMessage(NOTICE); + ConsoleWriter.printlnMessage(RESPONSE_TYPE); + return validate(ConsoleReader.enterMessage()); + } + + private static String validate(String enterMessage) { + for (String response : RESPONSES) { + if (response.equals(enterMessage)) { + return enterMessage; + } + } + throw CustomException.from(ErrorMessage.INVALID_FUNCTION_REQUEST); + } +} diff --git a/src/main/java/pairmatching/view/PairRequestView.java b/src/main/java/pairmatching/view/PairRequestView.java new file mode 100644 index 000000000..a7b81a1a2 --- /dev/null +++ b/src/main/java/pairmatching/view/PairRequestView.java @@ -0,0 +1,66 @@ +package pairmatching.view; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import pairmatching.controller.dto.request.PairRequest; +import pairmatching.domain.constants.Course; +import pairmatching.domain.constants.Level; +import pairmatching.domain.constants.Mission; +import pairmatching.global.exception.CustomException; +import pairmatching.global.exception.ErrorMessage; +import pairmatching.view.console.ConsoleReader; +import pairmatching.view.console.ConsoleWriter; + +/** + * 과정과 레벨, 미션을 출력하고 입력받는 뷰 + */ +public final class PairRequestView { + private static final String REQUEST_MESSAGE = "과정, 레벨, 미션을 선택하세요."; + private static final String REQUEST_EXAMPLE = "ex) 백엔드, 레벨1, 자동차경주"; + private static final String NOTICE = "" + + "#############################################\n" + + "과정: 백엔드 | 프론트엔드\n" + + "미션:\n" + + " - 레벨1: 자동차경주 | 로또 | 숫자야구게임\n" + + " - 레벨2: 장바구니 | 결제 | 지하철노선도\n" + + " - 레벨3: \n" + + " - 레벨4: 성능개선 | 배포\n" + + " - 레벨5: \n" + + "############################################"; + private static final String DIVISOR = ","; + + public static PairRequest request() { + ConsoleWriter.printlnMessage(NOTICE); + ConsoleWriter.printlnMessage(REQUEST_MESSAGE); + ConsoleWriter.printlnMessage(REQUEST_MESSAGE); + + return validate(ConsoleReader.enterMessage()); + } + + // 레벨과 미션의 입력이 맞지 않는 경우 예외처리 + private static PairRequest validate(String message) { + List input = split(message); + return new PairRequest( + Course.getCourse(input.get(0)), + Level.getLevel(input.get(1)), + Mission.getMission(input.get(2)) + ); + } + + private static List split(String message) { + String[] split = message.split(DIVISOR, -1); + if (split.length != 3) { + throw CustomException.from(ErrorMessage.INVALID_PAIR_REQUEST); + } + return new ArrayList<>( + Arrays.asList( + split[0].trim(), + split[1].trim(), + split[2].trim() + ) + ); + } + +} diff --git a/src/main/java/pairmatching/view/PairResponseView.java b/src/main/java/pairmatching/view/PairResponseView.java new file mode 100644 index 000000000..f0df2c78a --- /dev/null +++ b/src/main/java/pairmatching/view/PairResponseView.java @@ -0,0 +1,56 @@ +package pairmatching.view; + +import java.util.ArrayList; +import java.util.List; +import java.util.Set; + +import pairmatching.domain.Pair; +import pairmatching.domain.Pairs; +import pairmatching.view.console.ConsoleWriter; + +public final class PairResponseView { + private static final String NOTICE = "페어 매칭 결과입니다."; + private static final String COUPLE_PAIR_RESPONSE = "%s : %s"; + private static final String TRIPLE_PAIR_RESPONSE = "%s : %s : %s"; + + public static void response(Pairs pairs) { + ConsoleWriter.printlnMessage(NOTICE); + printPairs(pairs); + } + + private static void printPairs(Pairs pairs) { + for (Pair pair : pairs.getPairs()) { + printPair(pair); + } + } + + private static void printPair(Pair pair) { + List names = getNames(pair.getPair()); + if (names.size() == 2) { // 수정 + ConsoleWriter.printlnFormat( + COUPLE_PAIR_RESPONSE, + names.get(0), + names.get(1) + ); + return; + } + if (names.size() == 3) { + ConsoleWriter.printlnFormat( + TRIPLE_PAIR_RESPONSE, + names.get(0), + names.get(1), + names.get(2) + ); + } + + throw new IllegalStateException("페어에 속한 크루의 수가 2 혹은 3이 아닙니다."); + } + + private static List getNames(Set crews) { + List names = new ArrayList<>(); + for (String crew : crews) { + names.add(crew); + } + return names; + } +} diff --git a/src/main/java/pairmatching/view/RematchRequestView.java b/src/main/java/pairmatching/view/RematchRequestView.java new file mode 100644 index 000000000..a56c08f0e --- /dev/null +++ b/src/main/java/pairmatching/view/RematchRequestView.java @@ -0,0 +1,29 @@ +package pairmatching.view; + +import pairmatching.global.exception.CustomException; +import pairmatching.global.exception.ErrorMessage; +import pairmatching.view.console.ConsoleReader; +import pairmatching.view.console.ConsoleWriter; + +public final class RematchRequestView { + private static final String NOTICE = "매칭 정보가 있습니다. 다시 매칭하시겠습니까?"; + private static final String EXAMPLE_RESPONSE = "네 | 아니오"; + private static final String YES = "네"; + private static final String NO = "아니오"; + + public static boolean request() { + ConsoleWriter.printlnMessage(NOTICE); + ConsoleWriter.printlnMessage(EXAMPLE_RESPONSE); + return validate(ConsoleReader.enterMessage()); + } + + private static boolean validate(String input) { + if (input == YES) { + return true; + } + if (input == NO) { + return false; + } + throw CustomException.from(ErrorMessage.INVALID_REMATCH_REQUEST); + } +} diff --git a/src/main/java/pairmatching/view/console/ConsoleReader.java b/src/main/java/pairmatching/view/console/ConsoleReader.java new file mode 100644 index 000000000..a887b72e4 --- /dev/null +++ b/src/main/java/pairmatching/view/console/ConsoleReader.java @@ -0,0 +1,24 @@ +package pairmatching.view.console; + +import camp.nextstep.edu.missionutils.Console; +import pairmatching.global.exception.CustomException; +import pairmatching.global.exception.ErrorMessage; + +public final class ConsoleReader { + public static String enterMessage() { + return Validator.validate(Console.readLine()); + } + + private static class Validator { + public static String validate(String message) { + validateBlankInput(message); + return message; + } + + private static void validateBlankInput(String message) { + if (message.length() == 0) { + throw CustomException.from(ErrorMessage.BLANK_INPUT_ERROR); + } + } + } +} diff --git a/src/main/java/pairmatching/view/console/ConsoleWriter.java b/src/main/java/pairmatching/view/console/ConsoleWriter.java new file mode 100644 index 000000000..d6ddf4341 --- /dev/null +++ b/src/main/java/pairmatching/view/console/ConsoleWriter.java @@ -0,0 +1,15 @@ +package pairmatching.view.console; + +public final class ConsoleWriter { + public static void printlnMessage(String message) { + System.out.println(message); + } + + public static void printlnFormat(String message, Object... args) { + printlnMessage(String.format(message, args)); + } + + public static void println() { + System.out.println(); + } +} From 54a3129eabb3181e6390cbc3bab8f3d0c5991b9b Mon Sep 17 00:00:00 2001 From: MingyeomKim Date: Sun, 3 Dec 2023 01:07:45 +0900 Subject: [PATCH 17/18] =?UTF-8?q?refactor:=20=ED=85=8C=EC=8A=A4=ED=8A=B8?= =?UTF-8?q?=EC=BD=94=EB=93=9C=20=EC=98=88=EC=99=B8=EC=B2=98=EB=A6=AC=20?= =?UTF-8?q?=EA=B5=AC=EB=AC=B8=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/pairmatching/ApplicationTest.java | 76 +++++++++++-------- 1 file changed, 44 insertions(+), 32 deletions(-) diff --git a/src/test/java/pairmatching/ApplicationTest.java b/src/test/java/pairmatching/ApplicationTest.java index 2dff1e6d3..757cb008c 100644 --- a/src/test/java/pairmatching/ApplicationTest.java +++ b/src/test/java/pairmatching/ApplicationTest.java @@ -1,41 +1,53 @@ package pairmatching; -import static camp.nextstep.edu.missionutils.test.Assertions.assertShuffleTest; -import static camp.nextstep.edu.missionutils.test.Assertions.assertSimpleTest; -import static org.assertj.core.api.Assertions.assertThat; +import static camp.nextstep.edu.missionutils.test.Assertions.*; +import static org.assertj.core.api.Assertions.*; -import camp.nextstep.edu.missionutils.test.NsTest; +import java.io.IOException; import java.util.Arrays; + +import javax.xml.parsers.ParserConfigurationException; + import org.junit.jupiter.api.Test; -import pairmatching.Application; +import org.xml.sax.SAXException; + +import camp.nextstep.edu.missionutils.test.NsTest; class ApplicationTest extends NsTest { - private static final String ERROR_MESSAGE = "[ERROR]"; - - @Test - void 짝수_인원_페어_매칭() { - assertShuffleTest( - () -> { - run("1", "백엔드, 레벨1, 자동차경주", "Q"); - assertThat(output()).contains("태웅 : 백호", "치수 : 태섭"); - }, - Arrays.asList("태웅", "백호", "치수", "태섭") - ); - } - - @Test - void 없는_미션에_대한_예외_처리() { - assertSimpleTest( - () -> { - runException("1", "백엔드, 레벨1, 오징어게임"); - assertThat(output()).contains(ERROR_MESSAGE); - } - ); - } - - @Override - public void runMain() { - Application.main(new String[]{}); - } + private static final String ERROR_MESSAGE = "[ERROR]"; + + @Test + void 짝수_인원_페어_매칭() { + assertShuffleTest( + () -> { + run("1", "백엔드, 레벨1, 자동차경주", "Q"); + assertThat(output()).contains("태웅 : 백호", "치수 : 태섭"); + }, + Arrays.asList("태웅", "백호", "치수", "태섭") + ); + } + + @Test + void 없는_미션에_대한_예외_처리() { + assertSimpleTest( + () -> { + runException("1", "백엔드, 레벨1, 오징어게임"); + assertThat(output()).contains(ERROR_MESSAGE); + } + ); + } + + @Override + public void runMain() { + try { + Application.main(new String[] {}); + } catch (ParserConfigurationException e) { + throw new RuntimeException(e); + } catch (IOException e) { + throw new RuntimeException(e); + } catch (SAXException e) { + throw new RuntimeException(e); + } + } } From 12d29d50aee699e8bcb6b511abeae263b5e17403 Mon Sep 17 00:00:00 2001 From: MingyeomKim Date: Sun, 3 Dec 2023 01:11:35 +0900 Subject: [PATCH 18/18] =?UTF-8?q?feat:=20=EB=A7=88=ED=81=AC=EB=8B=A4?= =?UTF-8?q?=EC=9A=B4=20=ED=8C=8C=EC=9D=BC=EC=9D=84=20=EC=9D=BD=EC=96=B4?= =?UTF-8?q?=EC=99=80=EC=84=9C=20List=EC=9C=BC=EB=A1=9C=20=EB=B3=80?= =?UTF-8?q?=ED=99=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../pairmatching/service/CrewService.java | 8 +++--- .../pairmatching/util/MarkdownParser.java | 28 +++++++++++++++++++ 2 files changed, 32 insertions(+), 4 deletions(-) create mode 100644 src/main/java/pairmatching/util/MarkdownParser.java diff --git a/src/main/java/pairmatching/service/CrewService.java b/src/main/java/pairmatching/service/CrewService.java index c259a1837..17beaceba 100644 --- a/src/main/java/pairmatching/service/CrewService.java +++ b/src/main/java/pairmatching/service/CrewService.java @@ -3,7 +3,7 @@ import org.xml.sax.SAXException; import pairmatching.domain.Crews; import pairmatching.domain.constants.Course; -import pairmatching.util.XMLParser; +import pairmatching.util.MarkdownParser; import javax.xml.parsers.ParserConfigurationException; import java.io.IOException; @@ -17,9 +17,9 @@ public CrewService() throws ParserConfigurationException, IOException, SAXExcept } public Crews generateCrews() throws ParserConfigurationException, IOException, SAXException { - XMLParser xmlParser = new XMLParser(); - List backend = xmlParser.parseName(Course.BACKEND); - List frontend = xmlParser.parseName(Course.FRONTEND); + MarkdownParser markdownParser = new MarkdownParser(); + List backend = markdownParser.parseName(Course.BACKEND); + List frontend = markdownParser.parseName(Course.FRONTEND); Crews crews = new Crews(); crews.add(Course.BACKEND, backend); diff --git a/src/main/java/pairmatching/util/MarkdownParser.java b/src/main/java/pairmatching/util/MarkdownParser.java new file mode 100644 index 000000000..8a2ebf67a --- /dev/null +++ b/src/main/java/pairmatching/util/MarkdownParser.java @@ -0,0 +1,28 @@ +package pairmatching.util; + +import org.xml.sax.SAXException; +import pairmatching.domain.constants.Course; + +import javax.xml.parsers.ParserConfigurationException; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.List; +import java.util.Locale; + +public class MarkdownParser { + public List parseName(Course course) throws ParserConfigurationException, IOException, SAXException { + String filePath = String.format( + "src/main/resources/%s-crew.md", + course.name().toLowerCase(Locale.ROOT) + ); + + return readMarkdownFile(filePath); + } + + private static List readMarkdownFile(String filePath) throws IOException { + Path path = Paths.get(filePath); + return Files.readAllLines(path); + } +}