I'm a beginner: I have learned concepts and features which I think I need in my project, but this is my first serious program and it is my internship project. I'm totally confused and need help to tell me is my way of thinking about OOP, this project and etc correct or not?
As you know already from the title, this project is about the calculation of very big numbers. My employer didn't tell me how many digits, but I'm going to do this for up to 1M digits.
I'm using a linked-list to store numbers. I have 2 classes and one interface till now: class Numbers
which stores numbers, interface Arthimetic_Operations
and a class (which I haven't named yet) to do operations on Number
instances using Arthimetic_Operations
interface (actually this 2nd class is an idea for now).
Numbers can be complex or non-complex. They real part and imaginary part can have fractional parts.
Now let's look at Number.java, which I will explain further below.
public class Number {
private class Store {
private Node[] currentNode;
private String number;
private Utility util = new Utility();
public Store() {
}
void setFields(String number, Node... parts) {
int n = parts.length;
this.currentNode = new Node[n];
System.arraycopy(parts, 0, currentNode, 0, n);
this.number = number;
}
void start() {
Number.SetFields set = new Number.SetFields();
String boundries[] = subStringBoundries().split("_");
int i = 0;
int down, up;
StringBuilder subString;
set.setMarks(number);
while (i < currentNode.length) {
down = Integer.parseInt(boundries[i].split("-")[0]);
up = Integer.parseInt(boundries[i].split("-")[1]);
subString = new StringBuilder((number.substring(down, up)));
set.setLengthAndDecimalPointIndex(subString.toString(), i);
if (subString.indexOf(".") != -1) {
subString.delete(subString.indexOf("."), subString.indexOf(".") + 1);
}
store(currentNode[i], subString.toString());
i++;
}
}
void store(Node currentNode, String number) {
int nodes = number.length() / Node.NODE_LENGTH;
if (number.length() > nodes * Node.NODE_LENGTH) {
nodes++;
}
int subStringLength = 0;
String subString;
while (nodes > 0) {
try {
subString = number.substring(subStringLength, subStringLength + Node.NODE_LENGTH);
currentNode.setNumber(subString);
if (nodes > 1) {
currentNode.setNextNode(new Node());
currentNode.getNextNode().setPreviousNode(currentNode);
currentNode = currentNode.getNextNode();
}
nodes--;
subStringLength += Node.NODE_LENGTH;
} catch (IndexOutOfBoundsException e) {
e.getMessage();
subString = number.substring(subStringLength, number.length());
currentNode.setNumber(subString);
nodes--;
}
}
}
private String subStringBoundries() {
StringBuilder boundries = new StringBuilder();
if (util.hasTwoPart(number)) {
int complexMarkIndex = number.indexOf('i');
int operationIndexl;
if (number.indexOf('-', 1) != -1) {
operationIndexl = number.indexOf('-', 1);
} else {
operationIndexl = number.indexOf('+', 1);
}
if (util.isInNormalForm(number)) {
if (util.firstCharIsInteger(number)) {
boundries.append("0-").append(operationIndexl);
} else {
boundries.append("1-").append(operationIndexl);
}
if (operationIndexl + 1 == complexMarkIndex) {
boundries.append("_").append(complexMarkIndex + 1).append("-").append(number.length());
} else {
boundries.append("_").append(operationIndexl + 1).append("-").append(number.length() - 1);
}
} else {
boundries.append(operationIndexl + 1).append("-").append(number.length());
if (complexMarkIndex != operationIndexl - 1) {
boundries.append("_").append(complexMarkIndex + 1).append("-").append(operationIndexl);
} else if (util.firstCharIsInteger(number)) {
boundries.append("_0-").append(complexMarkIndex);
} else {
boundries.append("_1-").append(complexMarkIndex);
}
}
} else if (util.isComplex(number)) {
int complexMarkIndex = number.indexOf('i');
if (complexMarkIndex == 0) {
boundries.append("1-").append(number.length());
} else if (complexMarkIndex == 1) {
boundries.append("2-").append(number.length());
} else if (util.firstCharIsInteger(number)) {
boundries.append("0-").append(number.length() - 1);
} else {
boundries.append("1-").append(number.length() - 1);
}
} else if (util.firstCharIsInteger(number)) {
boundries.append("0-").append(number.length());
} else {
boundries.append("1-").append(number.length());
}
return boundries.toString();
}
private class Utility {
private boolean isComplex(String number) {
return (number.indexOf('i') != -1);
}
private boolean hasTwoPart(String number) {
return (number.indexOf('-', 1) != -1 || number.indexOf('+', 1) != -1);
}
boolean firstCharIsInteger(String number) {
return (number.charAt(0) != '-' && number.charAt(0) != '+');
}
boolean isInNormalForm(String number) {
int markIndex = number.indexOf('i');
int opeIndex;
if (number.indexOf('-', 1) != -1) {
opeIndex = number.indexOf('-', 1);
} else {
opeIndex = number.indexOf('+', 1);
}
return (markIndex > opeIndex);
}
}
}
private class SetFields {
Number.Store x = new Number.Store();
Store.Utility util = x.new Utility();
private void setMarks(String number) {
int temp;
if (util.hasTwoPart(number)) {
temp = number.indexOf('-', 1);
if (temp == -1) {
temp = number.indexOf('+', 1);
}
if (util.isInNormalForm(number)) {
if (number.charAt(0) == '-') {
real.mark = mark.NEGATIVE;
}
if (number.charAt(temp) == '-') {
imaginary.mark = mark.NEGATIVE;
}
} else {
if (number.charAt(0) == '-') {
imaginary.mark = mark.NEGATIVE;
}
if (number.charAt(temp) == '-') {
real.mark = mark.NEGATIVE;
}
}
} else if (util.isComplex(number)) {
if (number.charAt(0) == '-') {
imaginary.mark = mark.NEGATIVE;
}
} else if (number.charAt(0) == '-') {
real.mark = mark.NEGATIVE;
}
}
private void setLengthAndDecimalPointIndex(String number, int key) {
int index;
switch (key) {
case 0:
index = number.indexOf('.');
if (index != -1) {
real.integerPartLength = number.substring(0, index).length();
real.fractionalPartLength = number.substring(index + 1, number.length()).length();
if (real.integerPartLength == 1) {
if (number.charAt(0) == '0') {
real.integerPartLength = 0;
}
}
} else {
real.fractionalPartLength = 0;
real.integerPartLength = number.length();
}
break;
case 1:
index = number.indexOf('.');
if (index != -1) {
imaginary.integerPartLength = number.substring(0, index).length();
imaginary.fractionalPartLength = number.substring(index + 1, number.length()).length();
} else {
imaginary.fractionalPartLength = 0;
imaginary.integerPartLength = number.length();
}
if (imaginary.integerPartLength == 1) {
if (imaginary.getFirstNode().getNumber().charAt(0) == '0') {
imaginary.integerPartLength = 0;
}
}
break;
}
}
}
public static class Node {
public static final int NODE_LENGTH = 3;
private String number;
private Node nextNode;
private Node previousNode;
Node() {
this.number = "";
}
Node(String number) {
Node temp = this;
int nodes = number.length() / Node.NODE_LENGTH;
if (number.length() > nodes * Node.NODE_LENGTH) {
nodes++;
}
int subStringLength = 0;
String subString;
while (nodes > 0) {
try {
subString = number.substring(subStringLength, subStringLength + Node.NODE_LENGTH);
temp.setNumber(subString);
if (nodes > 1) {
temp.setNextNode(new Node());
temp.getNextNode().setPreviousNode(temp);
temp = temp.getNextNode();
}
nodes--;
subStringLength += Node.NODE_LENGTH;
} catch (IndexOutOfBoundsException e) {
e.getMessage();
subString = number.substring(subStringLength, number.length());
temp.setNumber(subString);
nodes--;
}
}
}
Node(StringBuilder number) {
Node temp = this;
int nodes = number.length() / Node.NODE_LENGTH;
if (number.length() > nodes * Node.NODE_LENGTH) {
nodes++;
}
int subStringLength = 0;
String subString;
while (nodes > 0) {
try {
subString = number.substring(subStringLength, subStringLength + Node.NODE_LENGTH);
temp.setNumber(subString);
if (nodes > 1) {
temp.setNextNode(new Node());
temp.getNextNode().setPreviousNode(temp);
temp = temp.getNextNode();
}
nodes--;
subStringLength += Node.NODE_LENGTH;
} catch (IndexOutOfBoundsException e) {
e.getMessage();
subString = number.substring(subStringLength, number.length());
temp.setNumber(subString);
nodes--;
}
}
}
public String getNumber() {
return number;
}
public Node getNextNode() {
return nextNode;
}
public Node getPreviousNode() {
return previousNode;
}
public void setNumber(String number) {
this.number = number;
}
public void setNextNode(Node nextNode) {
this.nextNode = nextNode;
}
public void setPreviousNode(Node previousNode) {
this.previousNode = previousNode;
}
public boolean hasNext() {
return (this.getNextNode() != null);
}
public boolean hasPrevious() {
return (this.getPreviousNode() != null);
}
public Node lastNode() {
Node temp = this;
try {
while (temp.hasNext()) {
temp = temp.getNextNode();
}
return temp;
} catch (NullPointerException e) {
System.out.println("Error Occured: " + e.getMessage());
}
return null;
}
}
public enum mark {
POSITIVE, NEGATIVE;
}
public class RealPart {
private Node firstNode;
private int fractionalPartLength;
private int integerPartLength;
private mark mark = Number.mark.POSITIVE;
public void setFirstNode(Node firstNode) {
this.firstNode = firstNode;
}
public void setFractionalPartLength(int fractionalPartLength) {
this.fractionalPartLength = fractionalPartLength;
}
public void setIntegerPartLength(int integerPartLength) {
this.integerPartLength = integerPartLength;
}
public Node getFirstNode() {
return firstNode;
}
public int getFractionalPartLength() {
return fractionalPartLength;
}
public int getIntegerPartLength() {
return integerPartLength;
}
public mark getMark() {
return mark;
}
}
public class ImaginaryPart {
private Node firstNode;
private int fractionalPartLength;
private int integerPartLength;
private mark mark = Number.mark.POSITIVE;
public void setFirstNode(Node firstNode) {
this.firstNode = firstNode;
}
public Node getFirstNode() {
return firstNode;
}
public int getFractionalPartLength() {
return fractionalPartLength;
}
public int getIntegerPartLength() {
return integerPartLength;
}
public mark getMark() {
return mark;
}
}
private RealPart real;
private ImaginaryPart imaginary;
public Number(String number) {
Number.Store store = new Number.Store();
if (store.util.hasTwoPart(number)) {
real = new RealPart();
real.setFirstNode(new Node());
imaginary = new ImaginaryPart();
imaginary.setFirstNode(new Node());
store.setFields(number, real.getFirstNode(), imaginary.getFirstNode());
} else if (store.util.isComplex(number)) {
imaginary = new ImaginaryPart();
imaginary.setFirstNode(new Node());
store.setFields(number, imaginary.getFirstNode());
} else {
real = new RealPart();
real.setFirstNode(new Node());
store.setFields(number, real.getFirstNode());
}
store.start();
}
public Number(BufferedReader number) throws IOException {
this(number.readLine());
}
public Number() {
}
public ImaginaryPart getImaginary() {
return imaginary;
}
public RealPart getReal() {
return real;
}
public void setImaginary(ImaginaryPart imaginary) {
this.imaginary = imaginary;
}
public void setReal(RealPart real) {
this.real = real;
}
public void print() throws IOException {
BufferedWriter write = new BufferedWriter(new OutputStreamWriter(System.out));
class Print {
private Number.Node currentNode;
private int nodes = -1;
private int integerPartLength;
Print(Number.Node x) {
this.currentNode = x;
}
Print(Number.Node x, int nodes, int integerPartLength) {
currentNode = x;
this.nodes = nodes;
this.integerPartLength = integerPartLength;
}
void printNodesValues() throws IOException {
while (currentNode != null) {
write.write(currentNode.getNumber());
currentNode = currentNode.getNextNode();
}
write.flush();
}
void printNodesValues(int nodes) throws IOException {
int n = nodes;
while (n > 0) {
write.write(currentNode.getNumber());
currentNode = currentNode.getNextNode();
n--;
}
write.flush();
}
void start() throws IOException {
if (nodes == -1) {
printNodesValues();
} else {
int n = 0;
if (nodes * Number.Node.NODE_LENGTH < integerPartLength) {
n = integerPartLength - (nodes * Number.Node.NODE_LENGTH);
}
printNodesValues(nodes);
if (n != 0) {
StringBuilder temp = new StringBuilder(currentNode.getNumber());
temp.insert(n, '.');
write.write(temp.toString());
currentNode = currentNode.getNextNode();
} else {
write.write('.');
}
printNodesValues();
}
}
}
Print print;
if (this.real != null) {
if (real.getMark() == mark.NEGATIVE) {
write.write("-");
}
if (this.real.fractionalPartLength != 0) {
int nodes = this.real.integerPartLength / Number.Node.NODE_LENGTH;
print = new Print(real.getFirstNode(), nodes, real.getIntegerPartLength());
print.start();
} else {
print = new Print(this.real.getFirstNode());
print.start();
}
}
if (this.imaginary != null) {
if (imaginary.getMark() == mark.NEGATIVE) {
write.write("-");
} else {
write.write("+");
}
if (this.imaginary.fractionalPartLength != 0) {
int nodes = this.imaginary.integerPartLength / Number.Node.NODE_LENGTH;
print = new Print(imaginary.getFirstNode(), nodes, imaginary.getIntegerPartLength());
print.start();
} else {
print = new Print(this.imaginary.getFirstNode());
print.start();
}
write.write("i");
}
write.write("\n");
write.flush();
}
}
To store numbers I have created an inner class called Store
. In Store
, I specify input number's type, up and down indexes of integer and fractional part and set other fields like number's mark and etc. Is it a good design or is it good to use an inner class to store numbers?, Do I have to remove the class and let the methods be in Number
?.
The other inner class, is class Node
which is for linked-list's cells. I declared it static and I decided to let it be an inner class because I think I'm using this class and Number
class in one place and it's better to be this way! but I am using Node
class's instances in Arithmetic_Operations
interface for calculations, so I'm not sure it is a good idea not not! so Should I separate Node
class?.
I have 3 more inner classes. Two of them are RealPart
and ImaginaryPart
classes which I'm somehow sure that they are good as an inner class. The other is SetFields
for setting number's mark and different part's length.
Also I have a local class called Print
in print()
method which has required methods to print a number, And an inner class in Store
class, Utility
, which has some required methods to store numbers, as well as Print
class.
In summary,
- What are my class
Number
issues? - How to design it better?
- Is it ok to have several methods in a class with long bodies or using inner classes is good enough?
- Am i doing OOP programming in the correct way or not?
I guess it's more than long till now, so if necessary, I'll send another post for Arthimetic_Operations
.