This repository was archived by the owner on May 18, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 83
Design Splitwise app #8
Open
arpit728
wants to merge
3
commits into
workattech:master
Choose a base branch
from
arpit728:master
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
3 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,3 @@ | ||
| .idea/ | ||
| docs/ | ||
| docs/ |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,2 @@ | ||
| EXPENSE u4 1200 4 u1 u2 u3 u4 PERCENT 20 20 20 20 20 | ||
| SHOW u1 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,33 @@ | ||
| <?xml version="1.0" encoding="UTF-8"?> | ||
| <project xmlns="http://maven.apache.org/POM/4.0.0" | ||
| xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | ||
| xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> | ||
| <modelVersion>4.0.0</modelVersion> | ||
|
|
||
| <groupId>com.arpit</groupId> | ||
| <artifactId>mock-machine-coding-2</artifactId> | ||
| <version>1.0-SNAPSHOT</version> | ||
|
|
||
| <build> | ||
| <plugins> | ||
| <plugin> | ||
| <groupId>org.apache.maven.plugins</groupId> | ||
| <artifactId>maven-compiler-plugin</artifactId> | ||
| <configuration> | ||
| <source>8</source> | ||
| <target>8</target> | ||
| </configuration> | ||
| </plugin> | ||
| </plugins> | ||
| </build> | ||
|
|
||
| <dependencies> | ||
| <dependency> | ||
| <groupId>org.projectlombok</groupId> | ||
| <artifactId>lombok</artifactId> | ||
| <version>1.18.10</version> | ||
| <scope>provided</scope> | ||
| </dependency> | ||
| </dependencies> | ||
|
|
||
| </project> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,17 @@ | ||
| package com; | ||
|
|
||
| import com.core.InputProcessor; | ||
| import java.io.BufferedReader; | ||
| import java.io.FileReader; | ||
| import java.io.IOException; | ||
|
|
||
| /** | ||
| * Created by bugkiller on 21/09/19. | ||
| */ | ||
| public class SplitWiseRunner { | ||
|
|
||
| public static void main(String[] args) throws IOException { | ||
| BufferedReader br = new BufferedReader(new FileReader("input.txt")); | ||
| br.lines().forEach(new InputProcessor()); | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,32 @@ | ||
| package com.core; | ||
|
|
||
| import com.dao.ExpenseDao; | ||
| import com.dao.impl.InMemoryExpenseDao; | ||
| import com.factory.SplitStrategyFactory; | ||
| import com.models.Transaction; | ||
| import com.split.SplitStrategy; | ||
| import java.util.function.Consumer; | ||
|
|
||
| /** | ||
| * Created by bugkiller on 21/09/19. | ||
| */ | ||
| public class InputProcessor implements Consumer<String> { | ||
|
|
||
| private ExpenseDao expenseDao; | ||
|
|
||
| public InputProcessor() { | ||
| expenseDao = InMemoryExpenseDao.getInstance(); | ||
| } | ||
|
|
||
| @Override | ||
| public void accept(String inputLine) { | ||
| if (!inputLine.contains("SHOW")) { | ||
| SplitStrategy splitStrategy = SplitStrategyFactory.provide(inputLine); | ||
| Transaction transaction = splitStrategy.split(inputLine); | ||
| expenseDao.addTransaction(transaction); | ||
| } else { | ||
| String[] showForUser = inputLine.split("\\s"); | ||
| System.out.println(expenseDao.showUserBalance(showForUser[1])); | ||
| } | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,10 @@ | ||
| package com.dao; | ||
|
|
||
| import com.models.Transaction; | ||
|
|
||
| public interface ExpenseDao { | ||
|
|
||
| void addTransaction(Transaction transaction); | ||
|
|
||
| String showUserBalance(String userId); | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,49 @@ | ||
| package com.dao.impl; | ||
|
|
||
| import com.dao.ExpenseDao; | ||
| import com.models.Borrow; | ||
| import com.models.Transaction; | ||
| import com.models.UserBalance; | ||
| import java.util.HashMap; | ||
| import java.util.List; | ||
| import java.util.Map; | ||
|
|
||
| /** | ||
| * Created by bugkiller on 21/09/19. | ||
| */ | ||
| public class InMemoryExpenseDao implements ExpenseDao { | ||
|
|
||
| private static final InMemoryExpenseDao IN_MEMORY_EXPENSE_DAO = new InMemoryExpenseDao(); | ||
|
|
||
| private Map<String, UserBalance> userBalanceData = new HashMap<>(); | ||
|
|
||
| private InMemoryExpenseDao() { } | ||
|
|
||
| public static ExpenseDao getInstance() { | ||
| return IN_MEMORY_EXPENSE_DAO; | ||
| } | ||
|
|
||
| @Override | ||
| public void addTransaction(Transaction transaction) { | ||
| List<Borrow> borrowList = transaction.getBorrowList(); | ||
| for (Borrow borrow : borrowList) { | ||
| UserBalance lenderBalanceData = userBalanceData.getOrDefault(borrow.getLender(), new UserBalance(borrow.getLender())); | ||
| UserBalance borrowerBalanceData = userBalanceData.getOrDefault(borrow.getBorrower(), new UserBalance(borrow.getBorrower())); | ||
| lenderBalanceData.receiveFrom(borrow.getBorrower(), borrow.getAmount()); | ||
| borrowerBalanceData.payTo(borrow.getLender(), borrow.getAmount()); | ||
| userBalanceData.putIfAbsent(lenderBalanceData.getUserId(), lenderBalanceData); | ||
| userBalanceData.putIfAbsent(borrowerBalanceData.getUserId(), borrowerBalanceData); | ||
| } | ||
| } | ||
|
|
||
| @Override | ||
| public String showUserBalance(String userId) { | ||
| UserBalance userBalance = userBalanceData.get(userId); | ||
| List<Borrow> debitList = userBalance.getAllPayTo(); | ||
| List<Borrow> creditList = userBalance.getAllReceiveFrom(); | ||
| StringBuilder sbr = new StringBuilder(); | ||
| debitList.forEach(borrow -> sbr.append(borrow.formattedOutput()).append("\n")); | ||
| creditList.forEach(borrow -> sbr.append(borrow.formattedOutput()).append("\n")); | ||
| return sbr.toString(); | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,32 @@ | ||
| package com.factory; | ||
|
|
||
| import com.split.SplitStrategy; | ||
| import com.split.impl.EqualSplitStrategy; | ||
| import com.split.impl.ExactSplitStrategy; | ||
| import com.split.impl.PercentSplitStrategy; | ||
|
|
||
| /** | ||
| * Created by bugkiller on 21/09/19. | ||
| */ | ||
| public class SplitStrategyFactory { | ||
| private static final SplitStrategy EQUAL_SPLIT_STRATEGY; | ||
| private static final SplitStrategy PERCENT_SPLIT_STRATEGY; | ||
| private static final SplitStrategy EXACT_SPLIT_STRATEGY; | ||
|
|
||
| static { | ||
| EQUAL_SPLIT_STRATEGY = new EqualSplitStrategy(); | ||
| EXACT_SPLIT_STRATEGY = new ExactSplitStrategy(); | ||
| PERCENT_SPLIT_STRATEGY = new PercentSplitStrategy(); | ||
| } | ||
|
|
||
| public static SplitStrategy provide(String inputLine) { | ||
| if (inputLine.contains("EXACT")) { | ||
| return EXACT_SPLIT_STRATEGY; | ||
| } else if (inputLine.contains("EQUAL")) { | ||
| return EQUAL_SPLIT_STRATEGY; | ||
| } else if (inputLine.contains("PERCENT")) { | ||
| return PERCENT_SPLIT_STRATEGY; | ||
| } | ||
| throw new IllegalArgumentException("Invalid Input"); | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,20 @@ | ||
| package com.models; | ||
|
|
||
| import lombok.Builder; | ||
| import lombok.Getter; | ||
|
|
||
| /** | ||
| * Created by bugkiller on 21/09/19. | ||
| */ | ||
| @Builder | ||
| @Getter | ||
| public class Borrow { | ||
|
|
||
| private String borrower; | ||
| private String lender; | ||
| private double amount; | ||
|
|
||
| public String formattedOutput() { | ||
| return String.format("%s Owes %s : %f", borrower, lender, amount); | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,20 @@ | ||
| package com.models; | ||
|
|
||
| import java.util.List; | ||
| import lombok.Builder; | ||
| import lombok.Getter; | ||
|
|
||
| /** | ||
| * Created by bugkiller on 21/09/19. | ||
| */ | ||
| @Builder | ||
| @Getter | ||
| public class Transaction { | ||
|
|
||
| private String spentBy; | ||
| private List<Borrow> borrowList; | ||
|
|
||
| public String getSpentBy() { | ||
| return spentBy; | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,66 @@ | ||
| package com.models; | ||
|
|
||
| import java.util.ArrayList; | ||
| import java.util.HashMap; | ||
| import java.util.List; | ||
| import java.util.Map; | ||
| import lombok.Getter; | ||
|
|
||
| /** | ||
| * Created by bugkiller on 21/09/19. | ||
| */ | ||
|
|
||
| public class UserBalance { | ||
|
|
||
| @Getter | ||
| private String userId; | ||
| private Map<String, Double> payTo; | ||
| private Map<String, Double> receiveFrom; | ||
|
|
||
| public UserBalance(String userId) { | ||
| this.userId = userId; | ||
| payTo = new HashMap<>(); | ||
| receiveFrom = new HashMap<>(); | ||
| } | ||
|
|
||
| public void receiveFrom(String userId, double amount) { | ||
| receiveFrom.merge(userId, amount, (oldValue, newValue) -> oldValue + amount); | ||
| settle(userId); | ||
| } | ||
|
|
||
| public void payTo(String userId, double amount) { | ||
| payTo.merge(userId, amount, (oldValue, newValue) -> oldValue + amount); | ||
| settle(userId); | ||
| } | ||
|
|
||
| private void settle(String externalUserId) { | ||
| Double payToUser = payTo.getOrDefault(externalUserId, (double) 0); | ||
| Double receiveFromUser = receiveFrom.getOrDefault(externalUserId, (double) 0); | ||
| if (payToUser > receiveFromUser) { | ||
| payTo.put(externalUserId, payToUser - receiveFromUser); | ||
| receiveFrom.remove(externalUserId); | ||
| } else if (payToUser < receiveFromUser) { | ||
| receiveFrom.put(externalUserId, receiveFromUser - payToUser); | ||
| payTo.remove(externalUserId); | ||
| } else { | ||
| receiveFrom.remove(externalUserId); | ||
| payTo.remove(externalUserId); | ||
| } | ||
| } | ||
|
|
||
| public List<Borrow> getAllReceiveFrom() { | ||
| List<Borrow> allReceiveFrom = new ArrayList<>(); | ||
| receiveFrom.forEach((key, value) -> { | ||
| allReceiveFrom.add(Borrow.builder().lender(userId).borrower(key).amount(value).build()); | ||
| }); | ||
| return allReceiveFrom; | ||
| } | ||
|
|
||
| public List<Borrow> getAllPayTo() { | ||
| List<Borrow> allPayTo = new ArrayList<>(); | ||
| payTo.forEach((key, value) -> { | ||
| allPayTo.add(Borrow.builder().lender(key).borrower(userId).amount(value).build()); | ||
| }); | ||
| return allPayTo; | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,8 @@ | ||
| package com.split; | ||
|
|
||
| import com.models.Transaction; | ||
|
|
||
| public interface SplitStrategy { | ||
|
|
||
| Transaction split(String inputLine); | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,15 @@ | ||
| package com.split.impl; | ||
|
|
||
| import com.models.Transaction; | ||
| import com.split.SplitStrategy; | ||
|
|
||
| /** | ||
| * Created by bugkiller on 21/09/19. | ||
| */ | ||
| public class EqualSplitStrategy implements SplitStrategy { | ||
|
|
||
| @Override | ||
| public Transaction split(String inputLine) { | ||
| return null; | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,16 @@ | ||
| package com.split.impl; | ||
|
|
||
| import com.models.Transaction; | ||
| import com.split.SplitStrategy; | ||
|
|
||
| /** | ||
| * Created by bugkiller on 21/09/19. | ||
| */ | ||
| public class ExactSplitStrategy implements SplitStrategy { | ||
|
|
||
| @Override | ||
| public Transaction split(String inputLine) { | ||
|
|
||
| return null; | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,56 @@ | ||
| package com.split.impl; | ||
|
|
||
| import com.models.Borrow; | ||
| import com.models.Transaction; | ||
| import com.split.SplitStrategy; | ||
| import java.math.RoundingMode; | ||
| import java.text.DecimalFormat; | ||
| import java.util.ArrayList; | ||
| import java.util.List; | ||
|
|
||
| /** | ||
| * Created by bugkiller on 21/09/19. | ||
| */ | ||
| public class PercentSplitStrategy implements SplitStrategy { | ||
|
|
||
| private static DecimalFormat decimalFormat = new DecimalFormat(".##"); | ||
|
|
||
| public PercentSplitStrategy() { | ||
| decimalFormat.setRoundingMode(RoundingMode.UP); | ||
| } | ||
|
|
||
| @Override | ||
| public Transaction split(String inputLine) { | ||
| String split[] = inputLine.split("PERCENT"); | ||
| String spenderUsersAndAmount[] = split[0].split("\\s"); | ||
| String shareList[] = split[1].split("\\s"); | ||
| validateShareList(shareList); | ||
| String spender = spenderUsersAndAmount[1]; | ||
| double amount = Double.parseDouble(spenderUsersAndAmount[2]); | ||
| List<Borrow> borrowList = new ArrayList<>(); | ||
| for (int i = 4, j = 1; i < spenderUsersAndAmount.length; i++) { | ||
| double share = Double.parseDouble(shareList[j]); | ||
| double borrowAmount = amount * (share / 100); | ||
| borrowList.add(Borrow.builder() | ||
| .lender(spender) | ||
| .borrower(spenderUsersAndAmount[i]) | ||
| .amount(borrowAmount) | ||
| .build()); | ||
| } | ||
| return Transaction.builder() | ||
| .borrowList(borrowList) | ||
| .spentBy(spender) | ||
| .build(); | ||
| } | ||
|
|
||
| private void validateShareList(String[] shareList) { | ||
| double percentSum = 0; | ||
| for (int i = 1; i < shareList.length; i++) { | ||
| String percent = shareList[i]; | ||
| percentSum += Double.parseDouble(percent); | ||
| } | ||
| if (percentSum != 100) { | ||
| throw new IllegalArgumentException("Percent don't add up to 100"); | ||
| } | ||
| } | ||
| } | ||
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should have parsed input format outside the core design. You could have parsed and created an expense object and passed it inside the split method.