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

This task was hard #1282

Open
wants to merge 9 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 8 commits
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
3 changes: 3 additions & 0 deletions finalReport.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
fruit,quantity
apple,90
banana,152

Choose a reason for hiding this comment

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

move all files to the resources directory

Choose a reason for hiding this comment

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

fix comment

2 changes: 0 additions & 2 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,6 @@
</maven.checkstyle.plugin.configLocation>
</properties>

<dependencies>
</dependencies>
<build>
<plugins>
<plugin>
Expand Down
8 changes: 8 additions & 0 deletions reportToRead.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
b,banana,20

Choose a reason for hiding this comment

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

move ro resources folder

b,apple,100
s,banana,100
p,banana,13
r,apple,10
p,apple,20
p,banana,5
s,banana,50
48 changes: 46 additions & 2 deletions src/main/java/core/basesyntax/HelloWorld.java
Original file line number Diff line number Diff line change
@@ -1,9 +1,53 @@
package core.basesyntax;

import core.basesyntax.dataservice.DataConverter;
import core.basesyntax.dataservice.DataConverterImpl;
import core.basesyntax.dataservice.ShopService;
import core.basesyntax.dataservice.ShopServiceImpl;
import core.basesyntax.fileservice.FileReader;
import core.basesyntax.fileservice.FileReaderImpl;
import core.basesyntax.fileservice.FileWriter;
import core.basesyntax.fileservice.FileWriterImpl;
import core.basesyntax.reportservice.ReportGenerator;
import core.basesyntax.reportservice.ReportGeneratorImpl;
import core.basesyntax.transactions.BalanceOperation;
import core.basesyntax.transactions.FruitTransaction;
import core.basesyntax.transactions.OperationHandler;
import core.basesyntax.transactions.OperationStrategy;
import core.basesyntax.transactions.OperationStrategyImpl;
import core.basesyntax.transactions.PurchaseOperation;
import core.basesyntax.transactions.ReturnOperation;
import core.basesyntax.transactions.SupplyOperation;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
* Feel free to remove this class and create your own.
*/
public class HelloWorld {
// HINT: In the `public static void main(String[] args)` it is better to create instances of your classes,
// and call their methods, but do not write any business logic in the `main` method!
private static final String INPUT_FILE = "reportToRead.csv";
private static final String OUTPUT_FILE = "finalReport.csv";

public static void main(String[] args) {
FileReader fileReader = new FileReaderImpl();
List<String> inputReport = fileReader.readFile(INPUT_FILE);

Map<FruitTransaction.Operation, OperationHandler> operationHandlers = new HashMap<>();
operationHandlers.put(FruitTransaction.Operation.BALANCE, new BalanceOperation());
operationHandlers.put(FruitTransaction.Operation.PURCHASE, new PurchaseOperation());
operationHandlers.put(FruitTransaction.Operation.RETURN, new ReturnOperation());
operationHandlers.put(FruitTransaction.Operation.SUPPLY, new SupplyOperation());
OperationStrategy operationStrategy = new OperationStrategyImpl(operationHandlers);
DataConverter dataConverter = new DataConverterImpl();
List<FruitTransaction> transactions = dataConverter.convertToTransaction(inputReport);
ShopService shopService = new ShopServiceImpl(operationStrategy);
shopService.process(transactions);

ReportGenerator reportGenerator = new ReportGeneratorImpl();
String resultingReport = reportGenerator.getReport();

FileWriter fileWriter = new FileWriterImpl();
fileWriter.writeFile(resultingReport, OUTPUT_FILE);
}
}
8 changes: 8 additions & 0 deletions src/main/java/core/basesyntax/dataservice/DataConverter.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package core.basesyntax.dataservice;

import core.basesyntax.transactions.FruitTransaction;
import java.util.List;

public interface DataConverter {
List<FruitTransaction> convertToTransaction(List<String> data);
}
28 changes: 28 additions & 0 deletions src/main/java/core/basesyntax/dataservice/DataConverterImpl.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package core.basesyntax.dataservice;

import core.basesyntax.transactions.FruitTransaction;
import java.util.ArrayList;
import java.util.List;

public class DataConverterImpl implements DataConverter {
private static final int OPERATION = 0;
private static final int FRUIT_TYPE = 1;
private static final int NUMBER = 2;
private static final String SEPARATOR = ",";

@Override
public List<FruitTransaction> convertToTransaction(List<String> data) {
List<FruitTransaction> fruitTransactionList = new ArrayList<>();
data.stream()
.map(array -> array.split(SEPARATOR))
.forEach(strings -> {
FruitTransaction fruitTransaction = new FruitTransaction();
fruitTransaction.setFruit(strings[FRUIT_TYPE]);
fruitTransaction.setQuantity(Integer.parseInt(strings[NUMBER]));
Copy link

Choose a reason for hiding this comment

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

What happens if quantity in not a number? Also we want to check if it's not negative before processing any transaction. It's called fail fast principle. It's better to use for loop and wrap this line in try catch block to throw an IllegalArgumentException

fruitTransaction.setOperation(FruitTransaction.Operation
.coverToOperation(strings[OPERATION]));
fruitTransactionList.add(fruitTransaction);
});
return fruitTransactionList;
}
}
8 changes: 8 additions & 0 deletions src/main/java/core/basesyntax/dataservice/ShopService.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package core.basesyntax.dataservice;

import core.basesyntax.transactions.FruitTransaction;
import java.util.List;

public interface ShopService {
void process(List<FruitTransaction> transactions);
}
26 changes: 26 additions & 0 deletions src/main/java/core/basesyntax/dataservice/ShopServiceImpl.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package core.basesyntax.dataservice;

import core.basesyntax.transactions.FruitTransaction;
import core.basesyntax.transactions.OperationHandler;
import core.basesyntax.transactions.OperationStrategy;
import java.util.List;

public class ShopServiceImpl implements ShopService {
private OperationStrategy operationStrategy;

public ShopServiceImpl(OperationStrategy operationStrategy) {
this.operationStrategy = operationStrategy;
}

@Override
public void process(List<FruitTransaction> transactions) {
transactions.stream()
.forEach(transaction -> {
OperationHandler operationHandler = operationStrategy
.getOperation(transaction.getOperation());
operationHandler.resultOfOperation(transaction.getFruit(),
transaction.getQuantity());

});
}
}
7 changes: 7 additions & 0 deletions src/main/java/core/basesyntax/fileservice/FileReader.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package core.basesyntax.fileservice;

import java.util.List;

public interface FileReader {
List<String> readFile(String nameOfFile);
}
26 changes: 26 additions & 0 deletions src/main/java/core/basesyntax/fileservice/FileReaderImpl.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package core.basesyntax.fileservice;

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

public class FileReaderImpl implements FileReader {
@Override
public List<String> readFile(String nameOfFile) {
File file = new File(nameOfFile);
List<String> dataOfFile = new ArrayList<>();
try (BufferedReader bufferedReader = new BufferedReader(new java.io.FileReader(file))) {
String value = bufferedReader.readLine();
while (value != null) {
dataOfFile.add(value);
value = bufferedReader.readLine();
}
bufferedReader.read();
} catch (IOException e) {
throw new RuntimeException("File is not found");
}
return dataOfFile;
}
}
5 changes: 5 additions & 0 deletions src/main/java/core/basesyntax/fileservice/FileWriter.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package core.basesyntax.fileservice;

public interface FileWriter {
void writeFile(String report, String nameOfNewFile);
}
16 changes: 16 additions & 0 deletions src/main/java/core/basesyntax/fileservice/FileWriterImpl.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package core.basesyntax.fileservice;

import java.io.BufferedWriter;
import java.io.IOException;

public class FileWriterImpl implements FileWriter {
@Override
public void writeFile(String report, String nameOfNewFile) {
try (BufferedWriter bufferedWriter
= new BufferedWriter(new java.io.FileWriter(nameOfNewFile))) {
bufferedWriter.write(report);
} catch (IOException e) {
throw new RuntimeException(e);

Choose a reason for hiding this comment

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

provide exception message

Choose a reason for hiding this comment

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

fix comment

}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package core.basesyntax.reportservice;

public interface ReportGenerator {
String getReport();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package core.basesyntax.reportservice;

import core.basesyntax.storage.DateFruits;

Choose a reason for hiding this comment

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

Direct access to DateFruits may violate the Dependency Inversion Principle. Consider using an abstraction or interface to access the storage, which would improve adherence to SOLID principles.

import java.util.stream.Collectors;

public class ReportGeneratorImpl implements ReportGenerator {
private static final String FRUIT = "fruit";
private static final String QUANTITY = "quantity";

@Override
public String getReport() {
return FRUIT + "," + QUANTITY + System.lineSeparator()

Choose a reason for hiding this comment

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

it's better to use StringBuilder

+ DateFruits.getAll().entrySet().stream()
.map(element -> element.getKey() + "," + element.getValue())
.collect(Collectors.joining(System.lineSeparator()));
}
}
20 changes: 20 additions & 0 deletions src/main/java/core/basesyntax/storage/DateFruits.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package core.basesyntax.storage;

import java.util.HashMap;
import java.util.Map;

public class DateFruits {
Copy link

Choose a reason for hiding this comment

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

Suggested change
public class DateFruits {
public class Storage {

private static final Map<String, Integer> fruitsStorage = new HashMap<>();

public static void save(String name, Integer amount) {
fruitsStorage.put(name, amount);
}

public static Integer get(String name) {
return fruitsStorage.get(name) == null ? 0 : fruitsStorage.get(name);
}

public static Map<String, Integer> getAll() {

Choose a reason for hiding this comment

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

The method getAll() returns a copy of the storage map, which is good for encapsulation. However, consider using an interface or abstraction for accessing the storage to adhere to the Dependency Inversion Principle.

return Map.copyOf(fruitsStorage);
}
}
15 changes: 15 additions & 0 deletions src/main/java/core/basesyntax/transactions/BalanceOperation.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package core.basesyntax.transactions;

import core.basesyntax.storage.DateFruits;

Choose a reason for hiding this comment

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

Direct access to DateFruits may violate the Dependency Inversion Principle. Consider using an abstraction or interface to access the storage, which would improve adherence to SOLID principles.


public class BalanceOperation implements OperationHandler {
@Override
public void resultOfOperation(String fruitName, int amount) {
if (amount <= 0) {
throw new RuntimeException(" The balance can`t be less or equals zero");
Copy link

Choose a reason for hiding this comment

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

Suggested change
throw new RuntimeException(" The balance can`t be less or equals zero");
throw new IllegalArgumentException(" The balance can`t be less or equals zero");

}
Comment on lines +8 to +10
Copy link

Choose a reason for hiding this comment

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

Let's move it to separate static or default method in OperationHandler and reuse where we need

int currentAmount = DateFruits.get(fruitName);
int newAmount = currentAmount + amount;
DateFruits.save(fruitName, newAmount);
}
}
67 changes: 67 additions & 0 deletions src/main/java/core/basesyntax/transactions/FruitTransaction.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package core.basesyntax.transactions;

import java.util.Arrays;

public class FruitTransaction {
private Operation operation;
private String fruit;
private int quantity;

@Override
public String toString() {
return "FruitTransaction{"
+ "operation=" + operation
+ ", fruit='" + fruit + '\''
+ ", quantity=" + quantity
+ '}';
}

public Operation getOperation() {
return operation;
}

public void setOperation(Operation operation) {
this.operation = operation;
}

public String getFruit() {
return fruit;
}

public void setFruit(String fruit) {
this.fruit = fruit;
}

public int getQuantity() {
return quantity;
}

public void setQuantity(int quantity) {
this.quantity = quantity;
}

public enum Operation {
BALANCE("b"),
SUPPLY("s"),
PURCHASE("p"),
RETURN("r");

private String code;

Operation(String code) {
this.code = code;
}

public String getCode() {
return code;
}

public static Operation coverToOperation(String code) {
return Arrays.stream(Operation.values())
.filter(e -> e.getCode().equals(code))
.findFirst()
.orElseThrow(() -> new RuntimeException(("Operation with code [%s] "
Copy link

Choose a reason for hiding this comment

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

Suggested change
.orElseThrow(() -> new RuntimeException(("Operation with code [%s] "
.orElseThrow(() -> new IllegalArgumentException(("Operation with code [%s] "

+ "does not exist!").formatted(code)));
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package core.basesyntax.transactions;

public interface OperationHandler {
void resultOfOperation(String fruitName, int amount);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package core.basesyntax.transactions;

public interface OperationStrategy {
OperationHandler getOperation(FruitTransaction.Operation operation);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package core.basesyntax.transactions;

import java.util.Map;

public class OperationStrategyImpl implements OperationStrategy {
private Map<FruitTransaction.Operation, OperationHandler> operationHandlerMap;

public OperationStrategyImpl(Map<FruitTransaction.Operation,
OperationHandler> operationHandlerMap) {
this.operationHandlerMap = operationHandlerMap;
}

@Override
public OperationHandler getOperation(FruitTransaction.Operation operation) {
if (operationHandlerMap.get(operation) == null) {
throw new RuntimeException("Operation can`t be null");
Copy link

Choose a reason for hiding this comment

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

Suggested change
throw new RuntimeException("Operation can`t be null");
throw new IllegalArgumentException("Operation can`t be null");

}
return operationHandlerMap.get(operation);

Choose a reason for hiding this comment

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

Consider adding a check to handle cases where the operation is not found in the operationHandlerMap. This could prevent potential NullPointerExceptions and improve robustness.

}
}
16 changes: 16 additions & 0 deletions src/main/java/core/basesyntax/transactions/PurchaseOperation.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package core.basesyntax.transactions;

import core.basesyntax.storage.DateFruits;

public class PurchaseOperation implements OperationHandler {
@Override
public void resultOfOperation(String fruitName, int amount) {
int currentAmount = DateFruits.get(fruitName);
int newAmount = currentAmount - amount;

Choose a reason for hiding this comment

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

Before saving the new amount, ensure that newAmount is not negative. If it is, throw a RuntimeException to prevent the storage from having a negative balance, as per the task requirements.

if (newAmount >= 0) {
DateFruits.save(fruitName, newAmount);
} else {
throw new RuntimeException("New amount can`t be negative");
}
}
}
Loading
Loading