Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
99765db
docs: 기능 구현 목록 작성
Mingyum-Kim Dec 2, 2023
19a49c1
docs: 기능 구현 목록 수정
Mingyum-Kim Dec 2, 2023
8be899b
feat: Application에서 함수 실행 코드 작성
Mingyum-Kim Dec 2, 2023
5ac97a3
feat: 페어 정보를 전달하는 DTO 생성
Mingyum-Kim Dec 2, 2023
4365a40
feat: 페어 저장, 조회, 초기화하는 코드 작성
Mingyum-Kim Dec 2, 2023
04b7ef8
feat: 강의 정보를 저장하는 상수 클래스 정의
Mingyum-Kim Dec 2, 2023
591d36a
feat: 레벨을 관리하는 상수 클래스 정의
Mingyum-Kim Dec 2, 2023
468b5c9
feat: 미션을 저장하는 상수 클래스 정의
Mingyum-Kim Dec 2, 2023
42b2cf2
feat: 크루의 정보를 저장하는 도메인 객체 생성
Mingyum-Kim Dec 2, 2023
e96fa49
feat: 파일을 읽어와 크루의 정보를 생성하는 기능 구현
Mingyum-Kim Dec 2, 2023
9b542b0
feat: 페어를 생성하고 매칭 정보를 저장하는 기능 구현
Mingyum-Kim Dec 2, 2023
bf66e5f
feat: 매칭 정보를 저장하기 위한 도메인 객체 생성
Mingyum-Kim Dec 2, 2023
72adbfd
feat: 페어들의 집합을 저장하는 도메인 객체 생성
Mingyum-Kim Dec 2, 2023
f61cde7
feat: 페어들을 리스트로 관리하는 도메인 클래스 구현
Mingyum-Kim Dec 2, 2023
e678abe
feat: 예외처리 클래스와 예외처리 메시지를 전역 클래스에서 구현
Mingyum-Kim Dec 2, 2023
0a96317
feat: 콘솔에서 필요한 입출력을 관리하는 뷰 클래스 생성
Mingyum-Kim Dec 2, 2023
54a3129
refactor: 테스트코드 예외처리 구문 추가
Mingyum-Kim Dec 2, 2023
12d29d5
feat: 마크다운 파일을 읽어와서 List<String>으로 변환
Mingyum-Kim Dec 2, 2023
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
47 changes: 47 additions & 0 deletions docs/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
## 사전 제공 정보 저장

크루 정보 저장
크루 정보가 저장된 XML파일에서 크루 이름 목록을 불러온다.
List<String>으로 변환하여 저장한다.
과정, 레벨, 미션 정보 저장
과정, 레벨, 미션을 Enum class에서 정의한다.
정보를 그룹화하여 저장한다.

## 실행할 기능을 선택하는 기능

`기능을 선택하세요.`를 출력한다.
`1. 페어 매칭 2. 페어 조회 3. 페어 초기화 Q. 종료`를 출력한다.
실행할 기능을 입력받는다.
1, 2, 3, Q에 해당하는 지 검증한다.

## 페어 매칭 기능

과정, 레벨, 미션 정보를 출력한다.
`과정, 레벨, 미션을 선택하세요.\nex) 백엔드, 레벨1, 자동차경주`를 출력한다.
`프론트엔드, 레벨1, 자동차경주` 형식으로 입력 받는다.
빈 문자열인 경우를 검증한다.
올바른 구분자로 입력되었음을 검증한다.
과정이 백엔드 혹은 프론트엔드 임을 검증한다.
레벨이 레벨1, 레벨2, 레벨3, 레벨4, 레벨5 중 하나임을 검증한다.
미션이 존재하는 미션임을 검증한다.
이미 매칭 정보가 있는 경우
`매칭 정보가 있습니다. 다시 매칭하시겠습니까?`를 출력한다.
`네` 입력 시 매칭 후 결과를 다시 저장한다.
`아니오` 입력 시 코스, 레벨, 미션을 다시 선택한다.
네/아니오 이외의 입력 시 예외를 발생한다.
크루 목록을 랜덤으로 섞는다.
앞에서부터 두 명씩 페어를 묶는다.
만약, 같은 레벨에서 만난 페어가 있다면 다시 섞고 매칭한다. (3회 반복)
같은 레벨에 있는 모든 미션의 매칭 정보를 불러온다.
이미 매칭된 바가 있는 페어라면 재시도한다.
3회 시도까지 매칭이 되지 않았다면 에러 메시지를 출력한다.
해당 레벨에서 짝지어진 페어의 목록을 저장한다.

## 페어 조회 기능

과정, 레벨, 미션을 선택하면 해당 미션의 페어 정보를 출력한다.
매칭 이력이 없으면 `[ERROR] 매칭 이력이 없습니다.`를 출력한다.

## 페어 초기화 기능

모든 미션에 대한 페어 매칭 정보를 초기화한다.
19 changes: 17 additions & 2 deletions src/main/java/pairmatching/Application.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,22 @@
package pairmatching;

import org.xml.sax.SAXException;
import pairmatching.controller.PairController;
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();
PairController pairController = new PairController(
crewService,
new MatchingService(crewService, new Matching())
);

pairController.run();
}
}
95 changes: 95 additions & 0 deletions src/main/java/pairmatching/controller/PairController.java
Original file line number Diff line number Diff line change
@@ -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> T retry(Supplier<T> supplier) {
while (true) {
try {
return supplier.get();
} catch (IllegalArgumentException e) {
ConsoleWriter.printlnMessage(e.getMessage());
}
}
}
}
29 changes: 29 additions & 0 deletions src/main/java/pairmatching/controller/dto/request/PairRequest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
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 PairRequest(Course course, Level level, Mission mission) {
this.course = course;
this.level = level;
this.mission = mission;
}

public Course course() {
return course;
}

public Level level() {
return level;
}

public Mission mission() {
return mission;
}
}
35 changes: 35 additions & 0 deletions src/main/java/pairmatching/domain/Crews.java
Original file line number Diff line number Diff line change
@@ -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<String> backend;
private List<String> frontend;

public Crews() {
this.backend = new ArrayList<>();
this.frontend = new ArrayList<>();
}

public void add(Course course, List<String> names) {
if (course.equals(Course.BACKEND)) {
backend.addAll(names);
}
if (course.equals(Course.FRONTEND)) {
frontend.addAll(names);
}
}

public List<String> getCrews(Course course) {
if (course.equals(Course.BACKEND)) {
return backend;
}
if (course.equals(Course.FRONTEND)) {
return frontend;
}
throw new IllegalStateException("적합하지 않은 과정 입력입니다.");
}
}
63 changes: 63 additions & 0 deletions src/main/java/pairmatching/domain/Matching.java
Original file line number Diff line number Diff line change
@@ -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<Mission, Pairs> 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<Pairs> getSameLevelPairs(Mission mission) {
List<Pairs> 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;
}
}
34 changes: 34 additions & 0 deletions src/main/java/pairmatching/domain/Pair.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package pairmatching.domain;

import java.util.Collections;
import java.util.HashSet;
import java.util.Set;

public class Pair {
private Set<String> pair;

public Pair() {
pair = new HashSet<>();
}

public void add(String name) {
pair.add(name);
}

/**
* 두 페어가 중복 크루를 매칭하고 있음을 검증하는 메서드
* @return 두 페어에 중복되는 크루가 두 명 이상 있으면 false, 그렇지 않다면 true
*/
public boolean duplicated(Pair other) {
Set<String> combined = new HashSet<>(pair);
combined.retainAll(other.getPair());

return combined.size() >= 2;
}

public Set<String> getPair() {
return Collections.unmodifiableSet(pair);
}
}


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

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

public class Pairs {
private List<Pair> 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<Pair> getPairs() {
return Collections.unmodifiableList(pairs);
}
}
Loading