Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
60 changes: 60 additions & 0 deletions case-studies/01-srp-keyword-processor/java/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
# Java Implementation: SRP Keyword Processor

## Prerequisites

- Java Development Kit (JDK) 21 or higher
- Command-line access (Terminal, PowerShell, etc.)

## Project Structure

- `bad/KeywordOrchestrator.java`: Example that violates the Single Responsibility Principle (SRP)
- `good/KeywordOrchestrator.java` and related classes: Example that follows SRP using separate service classes

## How to Compile and Run
If you're using VSCode and have the Java extension, just open good/KeywordOrchestrator.java or bad version and click 'run' that appears above the main method. Other IDEs will have different processes. If you want to use the command line, do the following:

### 1. Compile the Code to a Build Directory

Navigate to the `java` directory:

```bash
cd case-studies/01-srp-keyword-processor/java
```

Create a build directory (if it doesn't exist):

```bash
mkdir build
```

Compile all Java files to the build directory:

```bash
javac -d build bad/*.java good/*.java
```

### 2. Run the "Bad" Version

This version violates SRP by combining all logic in one class.

```bash
java -cp build bad.KeywordOrchestrator
```

### 3. Run the "Good" Version

This version follows SRP by delegating responsibilities to separate classes.

```bash
java -cp build good.KeywordOrchestrator
```

## Notes

- Ensure you are using JDK 21 or higher for compatibility.
- No external libraries are required; only standard Java is used.
- Output will be printed to the console, demonstrating the difference in design approaches.

---

For more information on the Single Responsibility Principle and SOLID, see the project documentation or comments in the source files.
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package bad;

import java.util.List;
import java.util.Objects;

/**
* This class is an example of violation of the Single-Responsibility principle
* of the SOLID principles suite
*
* @author Arthur Tristram, Software Engineer (Java)
* @since 2025-12-18
*/
public class KeywordOrchestrator {

private static final String FILE_PATH = "keywords.csv";

/**
* @param filePath path of the file to be read
* @return void
* @implNote performs all actions in a single method (Violates SR)
*/
public void processKeywords(String filePath) {
System.out.printf("Opening file at %s...%n", filePath);
// 1. Reading File Logic (Mixed responsibility)

List<String> rawData = List.of("buy shoes", "", "best running shoes", "shoes");

for (String row : rawData) {
// 2. Validation Logic (Mixed responsibility)
if (Objects.isNull(row) || row.isBlank()) {
continue;
}

// 3. API Logic (Mixed responsibility)
System.out.printf("Checking API for: %s%n", row);
double volume = Math.floor(Math.random() * 1000); // Fake API call

// 4. Database Logic (Mixed responsibility)
System.out.printf("INSERT INTO keyword_stats (term, volume) VALUES('%s', %.0f)%n", row, volume);
}
}
// Usage
/**
* @param args any command line parameters that may be passed
* @return void
* @implNote calls the monolithic processKeywords() function
*/
public static void main(String[] args) {
KeywordOrchestrator keywordOrchestrator = new KeywordOrchestrator();
keywordOrchestrator.processKeywords(FILE_PATH);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package good;
import java.util.List;

import good.services.CsvFileParser;
import good.services.KeywordValidator;
import good.services.SearchVolumeService;
import good.services.StatsRepository;

/**
* @author Arthur Tristram, Software Engineer (Java)
* @since 2025-12-18
* @implNote This class calls Single Responsibility services as advised by SOLID
* principles(mimics microservices)
*/
public class KeywordOrchestrator {
private CsvFileParser parser;
private KeywordValidator validator;
private SearchVolumeService api;
private StatsRepository repo;

private static final String FILE_PATH = "data.csv";

public KeywordOrchestrator(CsvFileParser parser, KeywordValidator validator, SearchVolumeService api,
StatsRepository repo) {
this.parser = parser;
this.validator = validator;
this.api = api;
this.repo = repo;
}

/**
* @param filePath
* @implNote The run service that calls various microservices to execute business logic
*/
public void run(String filePath) {
List<String> keywords = parser.read(filePath);

for (String keyword : keywords) {
if (!validator.isValid(keyword))
continue;

double volume = api.getVolume(keyword);
repo.save(new KeywordStats(keyword, volume));
}
}

/**
* @param args any arguments passed into the command line
* @implNote Instantiates the class with the various services and calls the run() service
*/
public static void main(String[] args) {
KeywordOrchestrator keywordOrchestrator = new KeywordOrchestrator(new CsvFileParser(), new KeywordValidator(),
new SearchVolumeService(), new StatsRepository());

keywordOrchestrator.run(FILE_PATH);
}
}
33 changes: 33 additions & 0 deletions case-studies/01-srp-keyword-processor/java/good/KeywordStats.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package good;
/**
* @author Arthur Tristram, Software Engineer(Java)
* @since 2025-12-18
* @implNote Model class for database objects
*/
public class KeywordStats {
private String term;
private double volume;

public KeywordStats(String term, double volume) {
this.term = term;
this.volume = volume;
}

// Getters & Setters for encapsulation
public String getTerm() {
return term;
}

public void setTerm(String term) {
this.term = term;
}

public double getVolume() {
return volume;
}

public void setVolume(double volume) {
this.volume = volume;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package good.services;
import java.util.List;

/**
* @author Arthur Tristram, Software Engineer(Java)
* @since 2025-12-18
* @implNote This class handles the responsibility of reading the file
*/
public class CsvFileParser {
/**
* @param fileName name of the file to be parsed
* @return a list containing file records
*/
public List<String> read(String fileName) {
System.out.printf("Reading file: %s%n", fileName);
return List.of("buy shoes", "", "best running shoes", "shoes");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package good.services;
/**
* @author Arthur Tristram, Software Engineer(Java)
* @since 2025-12-18
* @implNote This class handles the responsibility of validating the file
*/
public class KeywordValidator {
/**
* @param term the string to be validated
* @return boolean true if valid, false if invalid
*/
public boolean isValid(String term) {
return !term.isEmpty();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package good.services;
/**
* @author Arthur Tristram, Software Engineer(Java)
* @since 2025-12-18
* @implNote This class handles the responsibility of reading the file
*/
public class SearchVolumeService {
/**
* @param term the record to be processed
* @return volume generated by a random API call
*/
public double getVolume(String term) {
System.out.printf("[API] Fetching volume for: %s%n", term);
return Math.floor(Math.random() * 1000);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package good.services;

import good.KeywordStats;

/**
* @author Arthur Tristram, Software Engineer(Java)
* @since 2025-12-18
* @implNote This class handles the responsibility of saving object to repository
*/
public class StatsRepository {
/**
* @param stats the database object to be saved
* @return void
*/
public void save(KeywordStats stats) {
System.out.printf("[DB] Saving: %s -> %.0f\n", stats.getTerm(), stats.getVolume());
}
}
60 changes: 60 additions & 0 deletions case-studies/02-ocp-payroll-system/java/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
# Java Implementation

## Prerequisites

- Java Development Kit (JDK) 21 or higher
- Command-line access (Terminal, PowerShell, etc.)

## Project Structure

- `src/bad/SalaryCalculator.java`: Example that violates the Open-Closed Principle (OCP)
- `src/good/SalaryCalculator.java` and related classes: Example that follows OCP using inheritance and polymorphism

## How to Compile and Run
If you're using VSCode and have the Java extension, just open the good or bad SalaryCalculator.java and click 'run' above the main method. Other IDEs will have different processes. If you want to use the command line, do the following:

### 1. Compile the Code

Navigate to the `java` directory:

```bash
cd case-studies/02-ocp-payroll-system/java
```

Create a build directory (if it doesn't exist):

```bash
mkdir build
```

Compile all Java files to the build directory:

```bash
javac -d build src/bad/SalaryCalculator.java src/good/SalaryCalculator.java
```

### 2. Run the "Bad" Version

This version violates OCP by using conditional logic for all employee types.

```bash
java -cp build bad.SalaryCalculator
```

### 3. Run the "Good" Version

This version follows OCP by using inheritance and polymorphism.

```bash
java -cp build good.SalaryCalculator
```

## Notes

- Ensure you are using JDK 21 or higher for compatibility.
- No external libraries are required; only standard Java is used.
- Output will be printed to the console, demonstrating the difference in design approaches.

---

For more information on the Open-Closed Principle and SOLID, see the project documentation or comments in the source files.
Loading