Fibonacci Extends and Data Modeling
The Fibonacci sequence, as Mr. Mort notes, can be written in code in many different ways. In this notebook, I'll be using the OOP principles of inheritance and polymorphism to write my code and keep the alteration of code minimal.
- Fibonacci Sequence
- Object Oriented Programming (Inheritance and Polymorphism)
- Class Running Fibonacci in Multiple Ways
- Abstract Class
Fibonacci Sequence
Object Oriented Programming (Inheritance and Polymorphism)
Two of the most important pillars of OOP are Inheritance and Polymorphism.
Inheritance allows for the passing of constructors and data variables from one class to another creating a hierarchical structure. This is especially useful for code to be reused for certain classes like methods while also allowing for the sub classes to implement their own methods either overwriting them or creating entirely new ones. This can be implemented through extends key word which indicates inheritance and can either be done through an abstract class (a class with abstract methods that have undefined logic that must be defined in child classes) or normal classes.
Polymorphism allows for a single action to be performed in multiple ways meaning that the name space for functions is easier to manage as functions that do a single action will do the same thing as another function but can be implemented in a different way. Typically this comes in the form of overwriting a super class's methods with a class with the same signature but a different implementation, or establishing the logic of an abstract method from an abstract class.
Class Running Fibonacci in Multiple Ways
Here, we'll explore the different ways of implementing the Fibonacci sequence while using inheritance and polymorphism to our advantage to avoid clutter and create cleaner more effective code. Here, I'll start with Mr. Mort's code before working my way down and creating an abstract class and its respective sub classes.
Abstract Class
Abstract key word when creating class. Cannot make an instance of this class and can only extend using a subclass
/*
* Creator: Nighthawk Coding Society
* Mini Lab Name: Fibonacci sequence, featuring a Stream Algorithm
*
*/
import java.util.ArrayList;
import java.util.HashMap;
import java.util.stream.Stream;
/* Objective will require changing to abstract class with one or more abstract methods below */
public abstract class Fibo {
String name; // name or title of method
int size; // nth sequence
int hashID; // counter for hashIDs in hash map
ArrayList<Long> list; // captures current Fibonacci sequence
HashMap<Integer, Object> hash; // captures each sequence leading to final result
/*
* Zero parameter constructor uses Telescoping technique to allow setting of the
* required value nth
*
* @param: none
*/
public Fibo() {
this(20); // telescope to avoid code duplication, using default as 20
}
/*
* Construct the nth fibonacci number
*
* @param: nth number, the value is constrained to 92 because of overflow in a
* long
*/
public Fibo(int nth) {
this.size = nth;
this.list = new ArrayList<>();
this.hashID = 0;
this.hash = new HashMap<>();
// initialize fibonacci and time mvc
this.init();
}
/*
* This Method should be "abstract"
* Leave method as protected, as it is only authorized to extender of the class
* Make new class that extends and defines init()
* Inside references within this class would change from this to super
* Repeat process using for, while, recursion
*/
protected abstract void init();
/*
* Number is added to fibonacci sequence, current state of "list" is added to
* hash for hashID "num"
*/
public void setData(long num) {
list.add(num);
hash.put(this.hashID++, list.clone());
}
/*
* Custom Getter to return last element in fibonacci sequence
*/
public long getNth() {
return list.get(this.size - 1);
}
/*
* Custom Getter to return last fibonacci sequence in HashMap
*/
public Object getNthSeq(int i) {
return hash.get(i);
}
/*
* Console/Terminal supported print method
*/
public void print() {
System.out.println("Init method = " + this.name);
System.out.println("fibonacci Number " + this.size + " = " + this.getNth());
System.out.println("fibonacci List = " + this.list);
System.out.println("fibonacci Hashmap = " + this.hash);
for (int i = 0; i < this.size; i++) {
System.out.println("fibonacci Sequence " + (i + 1) + " = " + this.getNthSeq(i));
}
}
}
//Original Code Fibo (Stream)
import java.util.ArrayList;
import java.util.HashMap;
import java.util.stream.Stream;
public class FiboStream extends Fibo {
public FiboStream() {
this(20); // telescope to avoid code duplication, using default as 20
}
public FiboStream(int nth) {
super(nth);
}
@Override
protected void init() {
this.name = "Stream";
Stream.iterate(new long[] { 0, 1 }, f -> new long[] { f[1], f[0] + f[1] })
.limit(this.size)
.forEach(f -> this.setData(f[0]));
}
/*
* Tester class method. If this becomes abstract you will not be able to test it
* directly ...
* Change this method to call "main" class of each of the extended classes
*/
static public void main(String[] args) {
FiboStream fib = new FiboStream();
fib.print();
}
}
FiboStream.main(null);
public class FiboFor extends Fibo {
public FiboFor() {
this(20); // telescope to avoid code duplication, using default as 20
}
public FiboFor(int nth) {
super(nth);
}
@Override
protected void init() {
this.name = "For";
long f[] = new long[] { 0, 1 };
for (int i = 0; i < size; i++) {
long n = f[0];
this.setData(f[0]);
f[0] = f[1];
f[1] = n + f[1];
}
}
static public void main(String[] args) {
FiboFor fib = new FiboFor();
fib.print();
}
}
FiboFor.main(null);
import java.util.ArrayList;
import java.util.HashMap;
public class FiboWhile extends Fibo {
public FiboWhile() {
this(20); // telescope to avoid code duplication, using default as 20
}
public FiboWhile(int nth) {
super(nth);
}
@Override
protected void init() {
this.name = "While";
long f[] = new long[] { 0, 1 };
int i = 0;
while (i < size) {
long n = f[0];
this.setData(f[0]);
f[0] = f[1];
f[1] = n + f[1];
i++;
}
}
/*
* Tester class method. If this becomes abstract you will not be able to test it
* directly ...
* Change this method to call "main" class of each of the extended classes
*/
static public void main(String[] args) {
FiboWhile fib = new FiboWhile();
fib.print();
}
}
FiboWhile.main(null);
import java.util.ArrayList;
import java.util.HashMap;
public class FiboRecursion extends Fibo {
public FiboRecursion() {
this(20); // telescope to avoid code duplication, using default as 20
}
public FiboRecursion(int nth) {
super(nth);
}
@Override
protected void init() {
this.name = "Recursion";
for (int i = 0; i < size; i++) {
setData(fiboRecursion(i));
}
}
private long fiboRecursion(long n) {
if (n <= 1) {
return n;
}
return (fiboRecursion(n - 1) + fiboRecursion(n - 2));
}
/*
* Tester class method. If this becomes abstract you will not be able to test it
* directly ...
* Change this method to call "main" class of each of the extended classes
*/
static public void main(String[] args) {
FiboRecursion fib = new FiboRecursion();
fib.print();
}
}
FiboRecursion.main(null);