Refactor the code

This commit is contained in:
2020-03-29 10:51:55 +11:00
parent 65cacc22bd
commit 28681ea06f
@@ -11,10 +11,11 @@ public class FraudChecker {
public static final int TWENTY_FOUR_HOURS = 24;
private final TransactionRecordParser parser;
Map<String, Boolean> fraudulentCards = new HashMap<String, Boolean>();
Map<String, Boolean> fraudulentCards;
public FraudChecker(TransactionRecordParser parser) {
this.parser = parser;
this.fraudulentCards = new HashMap<>();
}
/**
@@ -26,60 +27,60 @@ public class FraudChecker {
*/
public List<String> fraudulentCreditCards(List<String> transactionStrings, BigDecimal threshold) {
List<TransactionEntry> transactionEntries = parser.parseTransactionEntries(transactionStrings);
Map<String, List<TransactionEntry>> transactionsGroupByCard = new HashMap<String, List<TransactionEntry>>();
for (TransactionEntry entry : transactionEntries) {
Map<String, List<TransactionEntry>> transactionsGroupByCard = new HashMap<>();
String hashedCreditCard = entry.getHashedCreditCard();
transactionEntries.forEach(entry -> processTransactionEntry(threshold, transactionsGroupByCard, entry));
List<TransactionEntry> entriesForCard = transactionsGroupByCard.get(hashedCreditCard);
if (entriesForCard == null) {
entriesForCard = new ArrayList<TransactionEntry>();
}
entriesForCard.add(entry);
transactionsGroupByCard.put(hashedCreditCard, entriesForCard);
if (!fraudulentCards.containsKey(hashedCreditCard)) {
analyse(entriesForCard, hashedCreditCard, threshold);
}
}
return collectFraudulentCards();
return getFraudulentCards();
}
private void analyse(List<TransactionEntry> entriesForCard, String hashedCard, BigDecimal threshold) {
int entriesSize = entriesForCard.size();
TransactionEntry oldestEntry = entriesForCard.get(0);
TransactionEntry latestEntry = entriesForCard.get(entriesSize - 1);
private void processTransactionEntry(BigDecimal threshold, Map<String, List<TransactionEntry>> transactionsByCard, TransactionEntry entry) {
String hashedCreditCard = entry.getHashedCreditCard();
if (latestEntry.getDateTime().minusHours(TWENTY_FOUR_HOURS).isAfter(oldestEntry.getDateTime())) {
entriesForCard = filterEntriesBySlidingWindow(entriesForCard, latestEntry).collect(Collectors.toList());
addTransactionEntryToMap(transactionsByCard, entry, transactionsByCard.get(hashedCreditCard));
if (!isTheCreditCardMarkedAsFraudulent(hashedCreditCard)) {
analyseCreditCardAgainstTheCurrentTimeWindow(transactionsByCard.get(hashedCreditCard), hashedCreditCard, threshold);
}
}
private void analyseCreditCardAgainstTheCurrentTimeWindow(List<TransactionEntry> entriesForCard, String hashedCard, BigDecimal threshold) {
TransactionEntry oldestEntry = entriesForCard.get(0);
TransactionEntry latestEntry = entriesForCard.get(entriesForCard.size() - 1);
if (areTheEntriesOverCurrentTimeWindow(oldestEntry, latestEntry)) {
entriesForCard = filterEntriesBySlidingTimeWindow(entriesForCard, latestEntry).collect(Collectors.toList());
}
if (ifCreditCardExceedsThreshold(entriesForCard, threshold)) {
fraudulentCards.put(hashedCard, true);
markFraudulentCreditCard(hashedCard);
}
}
/**
* Check if the total money from all the records a single credit card exceeds the threshold
*
* @param transactionsOfACard
* @param threshold
* @return
*/
private List<String> getFraudulentCards() {
return fraudulentCards.keySet().stream().collect(Collectors.toList());
}
private boolean areTheEntriesOverCurrentTimeWindow(TransactionEntry oldestEntry, TransactionEntry latestEntry) {
return latestEntry.getDateTime().minusHours(TWENTY_FOUR_HOURS).isAfter(oldestEntry.getDateTime());
}
private void markFraudulentCreditCard(String hashedCard) {
fraudulentCards.put(hashedCard, true);
}
private boolean ifCreditCardExceedsThreshold(List<TransactionEntry> transactionsOfACard, BigDecimal threshold) {
return ifExceedsThreshold(threshold, calculateTotalMoney(transactionsOfACard.stream()));
}
private Stream<TransactionEntry> filterEntriesBySlidingWindow(List<TransactionEntry> transactionsOfACard, TransactionEntry latestEntry) {
private Stream<TransactionEntry> filterEntriesBySlidingTimeWindow(List<TransactionEntry> transactionsOfACard, TransactionEntry latestEntry) {
return transactionsOfACard
.stream()
.filter(entry -> isTheEntryWithinTwentyHourWindow(latestEntry, entry));
}
private BigDecimal calculateTotalMoney(Stream<TransactionEntry> filteredTransactions) {
return filteredTransactions
private BigDecimal calculateTotalMoney(Stream<TransactionEntry> transactionEntries) {
return transactionEntries
.map(entry -> entry.getMoney())
.reduce(BigDecimal.ZERO, BigDecimal::add);
}
@@ -92,7 +93,16 @@ public class FraudChecker {
return !entry.getDateTime().plusHours(TWENTY_FOUR_HOURS).isBefore(latestEntry.getDateTime());
}
private List<String> collectFraudulentCards() {
return fraudulentCards.keySet().stream().collect(Collectors.toList());
private boolean isTheCreditCardMarkedAsFraudulent(String hashedCreditCard) {
return fraudulentCards.containsKey(hashedCreditCard);
}
private void addTransactionEntryToMap(Map<String, List<TransactionEntry>> transactionsGroupByCard, TransactionEntry entry, List<TransactionEntry> entriesForCard) {
if (entriesForCard == null) {
entriesForCard = new ArrayList<>();
}
entriesForCard.add(entry);
transactionsGroupByCard.put(entry.getHashedCreditCard(), entriesForCard);
}
}