-
Notifications
You must be signed in to change notification settings - Fork 1.1k
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
add solution #1242
base: master
Are you sure you want to change the base?
add solution #1242
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,9 +1,61 @@ | ||
package core.basesyntax; | ||
|
||
import core.basesyntax.dao.FruitRepository; | ||
import core.basesyntax.dao.impl.FruitRepositoryImpl; | ||
import core.basesyntax.model.FruitTransaction; | ||
import core.basesyntax.model.enums.Operation; | ||
import core.basesyntax.service.DataConverter; | ||
import core.basesyntax.service.FileService; | ||
import core.basesyntax.service.ReportGenerator; | ||
import core.basesyntax.service.ShopService; | ||
import core.basesyntax.service.handler.OperationHandler; | ||
import core.basesyntax.service.handler.OperationStrategy; | ||
import core.basesyntax.service.handler.impl.BalanceOperationHandler; | ||
import core.basesyntax.service.handler.impl.OperationStrategyImpl; | ||
import core.basesyntax.service.handler.impl.PurchaseOperationHandler; | ||
import core.basesyntax.service.handler.impl.ReturnOperationHandler; | ||
import core.basesyntax.service.handler.impl.SupplyOperationHandler; | ||
import core.basesyntax.service.impl.DataConverterImpl; | ||
import core.basesyntax.service.impl.FileServiceImpl; | ||
import core.basesyntax.service.impl.ReportGeneratorImpl; | ||
import core.basesyntax.service.impl.ShopServiceImpl; | ||
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! | ||
public static void main(String[] arg) { | ||
// 1. Read the data from the input CSV file | ||
FileService fileService = new FileServiceImpl(); | ||
List<String> inputReport = fileService.read("transactions.csv"); | ||
|
||
// 2. Convert the incoming data into FruitTransactions list | ||
DataConverter dataConverter = new DataConverterImpl(); | ||
|
||
// 3. Create and feel the map with all OperationHandler implementations | ||
FruitRepository repository = new FruitRepositoryImpl(); | ||
Map<Operation, OperationHandler> operationHandlers = new HashMap<>(); | ||
operationHandlers.put(Operation.BALANCE, new BalanceOperationHandler(repository)); | ||
operationHandlers.put(Operation.PURCHASE, new PurchaseOperationHandler(repository)); | ||
operationHandlers.put(Operation.RETURN, new ReturnOperationHandler(repository)); | ||
operationHandlers.put(Operation.SUPPLY, new SupplyOperationHandler(repository)); | ||
OperationStrategy operationStrategy = new OperationStrategyImpl(operationHandlers); | ||
|
||
// 4. Process the incoming transactions with applicable OperationHandler implementations | ||
|
||
List<FruitTransaction> transactions = dataConverter | ||
.convertStringsDataToFruitTransactions(inputReport); | ||
ShopService shopService = new ShopServiceImpl(operationStrategy); | ||
shopService.process(transactions); | ||
|
||
// 5.Generate report based on the current Storage state | ||
ReportGenerator reportGenerator = new ReportGeneratorImpl(repository); | ||
String resultingReport = reportGenerator.generateReport(); | ||
|
||
// 6. Write the received report into the destination file | ||
fileService.write("report.csv", resultingReport); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
package core.basesyntax.dao; | ||
|
||
import java.util.Map; | ||
|
||
public interface FruitRepository { | ||
void add(String fruit, int quantity); | ||
|
||
void remove(String fruit, int quantity); | ||
|
||
boolean hasFruit(String fruit); | ||
|
||
Map<String, Integer> getAll(); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
package core.basesyntax.dao.impl; | ||
|
||
import core.basesyntax.dao.FruitRepository; | ||
import core.basesyntax.db.Database; | ||
import java.util.Map; | ||
|
||
public class FruitRepositoryImpl implements FruitRepository { | ||
private final Map<String, Integer> db = Database.getStorage(); | ||
|
||
@Override | ||
public void add(String fruit, int quantity) { | ||
Integer newQuantity = db.containsKey(fruit) | ||
? db.get(fruit) + quantity | ||
: quantity; | ||
db.put(fruit, newQuantity); | ||
} | ||
|
||
@Override | ||
public void remove(String fruit, int quantity) { | ||
if (db.get(fruit) - quantity < 0) { | ||
throw new RuntimeException("Not enough " + fruit + " in storage to remove"); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. let's create a custom exception for such cases |
||
} | ||
db.put(fruit, db.get(fruit) - quantity); | ||
} | ||
|
||
@Override | ||
public boolean hasFruit(String fruit) { | ||
return db.containsKey(fruit); | ||
} | ||
|
||
@Override | ||
public Map<String, Integer> getAll() { | ||
return Map.copyOf(db); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,16 @@ | ||||||||||||||||||||||
package core.basesyntax.db; | ||||||||||||||||||||||
|
||||||||||||||||||||||
import java.util.HashMap; | ||||||||||||||||||||||
import java.util.Map; | ||||||||||||||||||||||
|
||||||||||||||||||||||
public class Database { | ||||||||||||||||||||||
private static final Map<String, Integer> storage; | ||||||||||||||||||||||
|
||||||||||||||||||||||
static { | ||||||||||||||||||||||
storage = new HashMap<>(); | ||||||||||||||||||||||
} | ||||||||||||||||||||||
|
||||||||||||||||||||||
public static Map<String, Integer> getStorage() { | ||||||||||||||||||||||
return storage; | ||||||||||||||||||||||
} | ||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||||||||||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
package core.basesyntax.model; | ||
|
||
import core.basesyntax.model.enums.Operation; | ||
|
||
public class FruitTransaction { | ||
private Operation operation; | ||
private String fruit; | ||
private int quantity; | ||
|
||
public FruitTransaction(Operation operation, String fruit, int quantity) { | ||
this.operation = operation; | ||
this.fruit = fruit; | ||
this.quantity = quantity; | ||
} | ||
|
||
public Operation getOperation() { | ||
return operation; | ||
} | ||
|
||
public String getFruit() { | ||
return fruit; | ||
} | ||
|
||
public int getQuantity() { | ||
return quantity; | ||
} | ||
|
||
public void setOperation(Operation operation) { | ||
this.operation = operation; | ||
} | ||
|
||
public void setFruit(String fruit) { | ||
this.fruit = fruit; | ||
} | ||
|
||
public void setQuantity(int quantity) { | ||
this.quantity = quantity; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
package core.basesyntax.model.enums; | ||
|
||
public enum Operation { | ||
BALANCE("b"), | ||
SUPPLY("s"), | ||
PURCHASE("p"), | ||
RETURN("r"); | ||
|
||
private final String code; | ||
|
||
Operation(String code) { | ||
this.code = code; | ||
} | ||
|
||
public String getCode() { | ||
return code; | ||
} | ||
|
||
public static Operation getByCode(String code) { | ||
for (Operation operation : values()) { | ||
if (operation.code.equals(code)) { | ||
return operation; | ||
} | ||
} | ||
return null; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. let's throw an exception instead |
||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
package core.basesyntax.service; | ||
|
||
import core.basesyntax.model.FruitTransaction; | ||
import java.util.List; | ||
|
||
public interface DataConverter { | ||
List<FruitTransaction> convertStringsDataToFruitTransactions(List<String> stringsData); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. let's make the method name concise and clear enough |
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
package core.basesyntax.service; | ||
|
||
import java.util.List; | ||
|
||
public interface FileService { | ||
List<String> read(String filePath); | ||
|
||
void write(String filePath, String data); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
package core.basesyntax.service; | ||
|
||
public interface ReportGenerator { | ||
String generateReport(); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
package core.basesyntax.service; | ||
|
||
import core.basesyntax.model.FruitTransaction; | ||
import java.util.List; | ||
|
||
public interface ShopService { | ||
void process(List<FruitTransaction> transactions); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
package core.basesyntax.service.handler; | ||
|
||
import core.basesyntax.model.FruitTransaction; | ||
|
||
public interface OperationHandler { | ||
void handle(FruitTransaction transaction); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
package core.basesyntax.service.handler; | ||
|
||
import core.basesyntax.model.enums.Operation; | ||
|
||
public interface OperationStrategy { | ||
OperationHandler getOperationHandler(Operation operation); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
package core.basesyntax.service.handler.impl; | ||
|
||
import core.basesyntax.dao.FruitRepository; | ||
import core.basesyntax.model.FruitTransaction; | ||
import core.basesyntax.service.handler.OperationHandler; | ||
|
||
public class BalanceOperationHandler extends BaseOperationHandler implements OperationHandler { | ||
private final FruitRepository fruitRepository; | ||
|
||
public BalanceOperationHandler(FruitRepository fruitRepository) { | ||
this.fruitRepository = fruitRepository; | ||
} | ||
|
||
@Override | ||
public void handle(FruitTransaction transaction) { | ||
checkTransaction(transaction); | ||
fruitRepository.add(transaction.getFruit(), transaction.getQuantity()); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
package core.basesyntax.service.handler.impl; | ||
|
||
import core.basesyntax.model.FruitTransaction; | ||
|
||
public class BaseOperationHandler { | ||
public void checkTransaction(FruitTransaction transaction) { | ||
if (transaction.getQuantity() < 0) { | ||
throw new RuntimeException("Quantity can't be less than 0"); | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this isn't a good place for transaction validations. It's better to validate quantity before or during parsing phase |
||
} | ||
} |
Original file line number | Diff line number | Diff line change | ||
---|---|---|---|---|
@@ -0,0 +1,20 @@ | ||||
package core.basesyntax.service.handler.impl; | ||||
|
||||
import core.basesyntax.model.enums.Operation; | ||||
import core.basesyntax.service.handler.OperationHandler; | ||||
import core.basesyntax.service.handler.OperationStrategy; | ||||
import java.util.Map; | ||||
|
||||
public class OperationStrategyImpl implements OperationStrategy { | ||||
|
||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. remove empty line
Suggested change
|
||||
private final Map<Operation, OperationHandler> handlersMap; | ||||
|
||||
public OperationStrategyImpl(Map<Operation, OperationHandler> handlersMap) { | ||||
this.handlersMap = handlersMap; | ||||
} | ||||
|
||||
@Override | ||||
public OperationHandler getOperationHandler(Operation operation) { | ||||
return handlersMap.get(operation); | ||||
} | ||||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
package core.basesyntax.service.handler.impl; | ||
|
||
import core.basesyntax.dao.FruitRepository; | ||
import core.basesyntax.model.FruitTransaction; | ||
import core.basesyntax.service.handler.OperationHandler; | ||
|
||
public class PurchaseOperationHandler extends BaseOperationHandler implements OperationHandler { | ||
private final FruitRepository repository; | ||
|
||
public PurchaseOperationHandler(FruitRepository repository) { | ||
this.repository = repository; | ||
} | ||
|
||
@Override | ||
public void handle(FruitTransaction transaction) { | ||
checkTransaction(transaction); | ||
if (repository.hasFruit(transaction.getFruit())) { | ||
repository.remove(transaction.getFruit(), transaction.getQuantity()); | ||
} else { | ||
throw new RuntimeException("Can't return fruits that are/were not in storage"); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. do not use the most general RuntimeException. Create your own one for such a case. Fix the same issue in all places |
||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
package core.basesyntax.service.handler.impl; | ||
|
||
import core.basesyntax.dao.FruitRepository; | ||
import core.basesyntax.model.FruitTransaction; | ||
import core.basesyntax.service.handler.OperationHandler; | ||
|
||
public class ReturnOperationHandler extends BaseOperationHandler implements OperationHandler { | ||
private final FruitRepository fruitRepository; | ||
|
||
public ReturnOperationHandler(FruitRepository fruitRepository) { | ||
this.fruitRepository = fruitRepository; | ||
} | ||
|
||
@Override | ||
public void handle(FruitTransaction transaction) { | ||
checkTransaction(transaction); | ||
if (fruitRepository.hasFruit(transaction.getFruit())) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. the same |
||
fruitRepository.add(transaction.getFruit(), transaction.getQuantity()); | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
package core.basesyntax.service.handler.impl; | ||
|
||
import core.basesyntax.dao.FruitRepository; | ||
import core.basesyntax.model.FruitTransaction; | ||
import core.basesyntax.service.handler.OperationHandler; | ||
|
||
public class SupplyOperationHandler extends BaseOperationHandler implements OperationHandler { | ||
private final FruitRepository repository; | ||
|
||
public SupplyOperationHandler(FruitRepository repository) { | ||
this.repository = repository; | ||
} | ||
|
||
@Override | ||
public void handle(FruitTransaction transaction) { | ||
checkTransaction(transaction); | ||
repository.add(transaction.getFruit(), transaction.getQuantity()); | ||
} | ||
} |
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.
map has native merge method to handle cases when key exists and doesn't exist