FibonacciBase Abstract Class:
package com.nighthawk.spring_portfolio.mvc.fibonacci;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
import java.util.stream.Collectors;
import java.util.stream.Stream;
abstract class FibonacciBase {//abstract class providing common functionality for Fibonacci implementations
public List<Long> calculateFibonacci(int num) {//method to calculate Fibonacci numbers and measure time
long startTime = System.nanoTime();
List<Long> fibonacciNumbers = performFibonacciCalculation(num);
long endTime = System.nanoTime();
displayResults(getMethodName(), endTime - startTime, fibonacciNumbers);
return fibonacciNumbers;
}
protected abstract List<Long> performFibonacciCalculation(int num); //abstract method to be implemented by subclasses
protected abstract String getMethodName(); //abstract method to get the method name
private static void displayResults(String method, double timeTaken, List<Long> fibonacciNumbers) {//displaying results method
System.out.println("Method: " + method);
System.out.println("Time taken: " + timeTaken / 1e6 + " milliseconds"); //convert to milliseconds
System.out.println("Fibonacci numbers: " + fibonacciNumbers);
System.out.println();
}
}
- FibonacciBase is an abstract class providing common functionality for Fibonacci implementations
- calculateFibonacci method calculates Fibonacci numbers and measures the time taken
- performFibonacciCalculation is an abstract method to be implemented by subclasses
- getMethodName is an abstract method to get the method name
- displayResults is a private static method displaying the results, including method name, time taken, and Fibonacci numbers
FibonacciFor Class
class FibonacciFor extends FibonacciBase {//implementation of FibonacciBase using a for loop
@Override
protected List<Long> performFibonacciCalculation(int num) {
List<Long> result = new ArrayList<>();
long a = 0, b = 1;
for (int i = 0; i < num; i++) {
result.add(a);
long temp = a;
a = b;
b = temp + b;
}
return result;
}
@Override
protected String getMethodName() {
return "For Loop";
}
}
- FibonacciFor is a concrete class that extends FibonacciBase and implements the Fibonacci calculation using a for loop
- performFibonacciCalculation method calculates Fibonacci numbers using a for loop
- getMethodName method returns the method name, which is “For Loop”
FibonacciWhile Class
class FibonacciWhile extends FibonacciBase {//implementation of FibonacciBase class using a while loop
@Override
protected List<Long> performFibonacciCalculation(int num) {
List<Long> result = new ArrayList<>();
long a = 0, b = 1;
int count = 0;
while (count < num) {
result.add(a);
long temp = a;
a = b;
b = temp + b;
count++;
}
return result;
}
@Override
protected String getMethodName() {
return "While Loop";
}
}
- FibonacciWhile is a concrete class that extends FibonacciBase and implements the Fibonacci calculation using a while loop
- performFibonacciCalculation method calculates Fibonacci numbers using a while loop
- getMethodName method returns the method name, which is “While Loop”
FibonacciRecursion Class
class FibonacciRecursion extends FibonacciBase {//implementation of FibonacciBase using recursion
@Override
protected List<Long> performFibonacciCalculation(int num) {
List<Long> result = new ArrayList<>();
fibonacciRecursionStructure(num, 0, 1, result);
return result;
}
private static void fibonacciRecursionStructure(int num, long a, long b, List<Long> result) {//helper method for recursive calculation
if (num > 0) {
result.add(a);
fibonacciRecursionStructure(num - 1, b, a + b, result);
}
}
@Override
protected String getMethodName() {
return "Recursion Loop";
}
}
- FibonacciRecursion is a concrete class that extends FibonacciBase and implements the Fibonacci calculation using recursion
- performFibonacciCalculation method calculates Fibonacci numbers using recursion
- fibonacciRecursionStructure is a helper method for the recursive calculation
- getMethodName method returns the method name, which is “Recursion Loop”
FibonacciStream Class
class FibonacciStream extends FibonacciBase {//implementation of FibonacciBase using Java Streams
@Override
protected List<Long> performFibonacciCalculation(int num) {
return Stream.iterate(new long[]{0, 1}, f -> new long[]{f[1], f[0] + f[1]})
.limit(num)
.mapToLong(f -> f[0])
.boxed()
.collect(Collectors.toList());
}
@Override
protected String getMethodName() {
return "Stream Loop";
}
}
- FibonacciRecursion is a concrete class that extends FibonacciBase and implements the Fibonacci calculation using recursion
- performFibonacciCalculation method calculates Fibonacci numbers using recursion
- fibonacciRecursionStructure is a helper method for the recursive calculation
- getMethodName method returns the method name, which is “Recursion Loop”
Fibonacci Class
public class Fibonacci {//fibonacci class to demonstrate and compare different Fibonacci implementations
public static void main(String[] args) {
int num = getUserInput();
FibonacciBase fibonacciFor = new FibonacciFor();//instantiate and calculate Fibonacci using For Loop
fibonacciFor.calculateFibonacci(num);
FibonacciBase fibonacciWhile = new FibonacciWhile();//same for while loop
fibonacciWhile.calculateFibonacci(num);
FibonacciBase fibonacciRecursion = new FibonacciRecursion();//same for recursion loop
fibonacciRecursion.calculateFibonacci(num);
FibonacciBase fibonacciStream = new FibonacciStream();//same for stream loop
fibonacciStream.calculateFibonacci(num);
}
private static int getUserInput() {
Scanner scanner = new Scanner(System.in); //scanner for number fo Fibonacci numbers user wants to input
System.out.print("Enter the number of Fibonacci numbers to generate: ");
int num;
while (true) {
try {
num = scanner.nextInt();
if (num > 0) {
break;
} else {
System.out.print("Please enter a positive integer: "); //asking only for positive integer
}
} catch (Exception e) {
System.out.print("Invalid input. Please enter a positive integer: "); //will catch invalid input such as negative number or letter
scanner.next(); // consume invalid input
scanner.next(); //consume invalid input
}
}
scanner.close();
return num;
}
}
- Fibonacci is the main class that demonstrates and compares different Fibonacci implementations
- main method initializes instances of Fibonacci implementations and calculates Fibonacci numbers using user input
- getUserInput method retrieves the number of Fibonacci numbers the user wants to generate using a Scanner
Inheritance
Example: Utilization in the Fibonacci Class
FibonacciBase fibonacciFor = new FibonacciFor();
fibonacciFor.calculateFibonacci(num);
FibonacciBase fibonacciWhile = new FibonacciWhile();
fibonacciWhile.calculateFibonacci(num);
FibonacciBase fibonacciRecursion = new FibonacciRecursion();
fibonacciRecursion.calculateFibonacci(num);
FibonacciBase fibonacciStream = new FibonacciStream();
fibonacciStream.calculateFibonacci(num);
In the Fibonacci class, instances of the concrete subclasses (FibonacciFor, FibonacciWhile, FibonacciRecursion, FibonacciStream) are created and assigned to variables of type FibonacciBase. This is possible because of the inheritance relationship; a subclass instance can be treated as an instance of its superclass.
The calculateFibonacci method is then called on each instance, demonstrating polymorphism. The specific implementation of calculateFibonacci in each subclass is invoked based on the type of the object, allowing for flexibility and code reuse.