Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[BE] 참여자 정산 현황 로직 리펙토링 #110

Merged
merged 2 commits into from
Jul 26, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
import server.haengdong.domain.action.BillActionRepository;
import server.haengdong.domain.action.MemberAction;
import server.haengdong.domain.action.MemberActionRepository;
import server.haengdong.domain.action.MemberBillReports;
import server.haengdong.domain.action.MemberBillReport;
import server.haengdong.domain.event.Event;
import server.haengdong.domain.event.EventRepository;
import server.haengdong.exception.HaengdongErrorCode;
Expand All @@ -29,10 +29,10 @@ public List<MemberBillReportAppResponse> getMemberBillReports(String token) {
List<BillAction> billActions = billActionRepository.findByAction_Event(event);
List<MemberAction> memberActions = memberActionRepository.findAllByEvent(event);

MemberBillReports memberBillReports = MemberBillReports.createByActions(billActions, memberActions);
MemberBillReport memberBillReport = MemberBillReport.createByActions(billActions, memberActions);

List<MemberBillReportAppResponse> memberBillReportResponses = new ArrayList<>();
memberBillReports.getReports().forEach(
memberBillReport.getReports().forEach(
(member, price) -> memberBillReportResponses.add(new MemberBillReportAppResponse(member, price))
);
return memberBillReportResponses;
Copy link
Contributor

Choose a reason for hiding this comment

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

return memberBillReport.getReports().entrySet().stream()
                .map(entry -> new MemberBillReportAppResponse(entry.getKey(), entry.getValue()))
                .toList();

r: forEach 사용하는 것 보다 바로 리스트를 반환하는게 더 좋을 것 같아요.

Expand Down
Original file line number Diff line number Diff line change
@@ -1,19 +1,23 @@
package server.haengdong.domain.action;

import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.RequiredArgsConstructor;

@Getter
@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
public class CurrentMembers {

private final Set<String> members;

public CurrentMembers() {
this(new HashSet<>());
}

private CurrentMembers(Set<String> members) {
this.members = members;
}

public static CurrentMembers of(List<MemberAction> memberActions) {
List<MemberAction> sortedMemberActions = getSortedMemberActions(memberActions);
Set<String> members = new HashSet<>();
Expand All @@ -34,4 +38,29 @@ private static List<MemberAction> getSortedMemberActions(List<MemberAction> memb
.sorted(Comparator.comparing(MemberAction::getSequence))
.toList();
}

public CurrentMembers addMemberAction(MemberAction memberAction) {
String memberName = memberAction.getMemberName();

Set<String> currentMembers = new HashSet<>(members);

if (memberAction.isIn()) {
currentMembers.add(memberName);
} else {
currentMembers.remove(memberName);
}
return new CurrentMembers(currentMembers);
}
Comment on lines +42 to +53
Copy link
Contributor

Choose a reason for hiding this comment

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

곰곰이 생각해보니 불변 객체로 반환하는 것이 함수형 프로그래밍 스타일이어서 좋은 것 같아요. 💯


public boolean isEmpty() {
return members.isEmpty();
}

public int size() {
return members.size();
}

public Set<String> getMembers() {
return Collections.unmodifiableSet(members);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,10 @@ public boolean isSameName(String name) {
return memberName.equals(name);
}

public boolean isIn() {
return status == MemberActionStatus.IN;
}

public boolean isSameStatus(MemberActionStatus memberActionStatus) {
return status == memberActionStatus;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,33 +2,31 @@

import static java.util.stream.Collectors.toMap;

import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.PriorityQueue;
import java.util.Set;
import java.util.function.Function;
import lombok.Getter;

@Getter
public class MemberBillReports {
public class MemberBillReport {

private final Map<String, Long> reports;

private MemberBillReports(Map<String, Long> reports) {
private MemberBillReport(Map<String, Long> reports) {
this.reports = reports;
}

public static MemberBillReports createByActions(List<BillAction> billActions, List<MemberAction> memberActions) {
public static MemberBillReport createByActions(List<BillAction> billActions, List<MemberAction> memberActions) {
PriorityQueue<BillAction> sortedBillActions = new PriorityQueue<>(billActions);
PriorityQueue<MemberAction> sortedMemberActions = new PriorityQueue<>(memberActions);

Map<String, Long> memberBillReports = initReports(memberActions);
Set<String> currentMembers = new HashSet<>();

CurrentMembers currentMembers = new CurrentMembers();
while (!sortedBillActions.isEmpty() && !sortedMemberActions.isEmpty()) {
if (isMemberActionTurn(sortedMemberActions, sortedBillActions)) {
addMemberAction(sortedMemberActions, currentMembers);
MemberAction memberAction = sortedMemberActions.poll();
currentMembers = currentMembers.addMemberAction(memberAction);
continue;
}
addBillAction(sortedBillActions, currentMembers, memberBillReports);
Expand All @@ -38,7 +36,7 @@ public static MemberBillReports createByActions(List<BillAction> billActions, Li
addBillAction(sortedBillActions, currentMembers, memberBillReports);
}

return new MemberBillReports(memberBillReports);
return new MemberBillReport(memberBillReports);
}

private static Map<String, Long> initReports(List<MemberAction> memberActions) {
Expand All @@ -58,25 +56,19 @@ private static boolean isMemberActionTurn(
return memberAction.getSequence() < billAction.getSequence();
}

private static void addMemberAction(PriorityQueue<MemberAction> sortedMemberActions, Set<String> currentMembers) {
MemberAction memberAction = sortedMemberActions.poll();
String memberName = memberAction.getMemberName();
if (memberAction.isSameStatus(MemberActionStatus.IN)) {
currentMembers.add(memberName);
return;
}
currentMembers.remove(memberAction.getMemberName());
}

private static void addBillAction(
PriorityQueue<BillAction> sortedBillActions,
Set<String> currentMembers,
CurrentMembers currentMembers,
Map<String, Long> memberBillReports
) {
BillAction billAction = sortedBillActions.poll();
if (currentMembers.isEmpty()) {
return;
}

Long pricePerMember = billAction.getPrice() / currentMembers.size();
for (String currentMember : currentMembers) {
Long price = memberBillReports.getOrDefault(currentMember, 0L) + pricePerMember;
for (String currentMember : currentMembers.getMembers()) {
Long price = memberBillReports.get(currentMember) + pricePerMember;
memberBillReports.put(currentMember, price);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import static server.haengdong.domain.action.MemberActionStatus.OUT;

import java.util.List;
import java.util.Set;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import server.haengdong.domain.event.Event;
Expand All @@ -27,4 +28,31 @@ void of() {
assertThat(currentMembers.getMembers())
.containsExactlyInAnyOrder("망쵸", "웨디");
}

@DisplayName("인원 변동 액션의 상태가 IN이면 현재 인원에 추가한다.")
@Test
void addMemberAction1() {
CurrentMembers currentMembers = new CurrentMembers();
Event event = new Event("이벤트", "token");
MemberAction memberAction = new MemberAction(new Action(event, 1L), "웨디", IN, 1L);

CurrentMembers addedCurrentMembers = currentMembers.addMemberAction(memberAction);
Set<String> members = addedCurrentMembers.getMembers();

assertThat(members).hasSize(1)
.containsExactly("웨디");
}

@DisplayName("인원 변동 액션의 상태가 OUT이면 현재 인원에서 제외한다.")
@Test
void addMemberAction2() {
Event event = new Event("이벤트", "token");
MemberAction memberAction1 = new MemberAction(new Action(event, 1L), "웨디", IN, 1L);
CurrentMembers currentMembers = new CurrentMembers().addMemberAction(memberAction1);
MemberAction memberAction2 = new MemberAction(new Action(event, 1L), "웨디", OUT, 1L);

CurrentMembers addedCurrentMembers = currentMembers.addMemberAction(memberAction2);

assertThat(addedCurrentMembers.getMembers()).hasSize(0);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
import org.junit.jupiter.api.Test;
import server.haengdong.domain.event.Event;

class MemberBillReportsTest {
class MemberBillReportTest {

@DisplayName("액션 목록으로 참가자 정산 리포트를 생성한다.")
@Test
Expand All @@ -29,9 +29,9 @@ void createByActions() {
new MemberAction(new Action(event, 5L), "감자", OUT, 2L)
);

MemberBillReports memberBillReports = MemberBillReports.createByActions(billActions, memberActions);
MemberBillReport memberBillReport = MemberBillReport.createByActions(billActions, memberActions);

assertThat(memberBillReports.getReports())
assertThat(memberBillReport.getReports())
.containsAllEntriesOf(
Map.of(
"감자", 20_000L,
Expand Down
Loading