I had an interview with a global company yesterday. They had given me a programming assignment. I shared my screen and I must have finished the task in 1.5 hours.
Task was programming Reverse Polish Notation calculator in Java. I had developed as I shared my code below. I was rejected by not being stick to KISS and DRY principles. How should I improve my code according to these principles?
Calculator.java
package com.luxoft;
import java.util.Stack;
import com.luxoft.model.Element;
import com.luxoft.model.Number;
public class Calculator {
private Stack<Element> operationStack = new Stack<>();
public Integer add(String elements) {
return null;
}
public Integer calculate( String elements ) throws Exception {
operationStack.clear();
String[] elementArray = elements.split(" ");
for( int i=0; i<elementArray.length; i++ ) {
String element = elementArray[i];
Element operationElement = ElementExtractor.extract(element);
operationElement.process(operationStack);
}
System.out.println( "operationStack.size():"+operationStack.size() );
if( operationStack.size() != 1 ) {
throw new Exception("not calculated");
}
return ((Number)operationStack.pop()).getValue();
}
}
ElementExtractor.java
package com.luxoft;
import java.util.HashMap;
import java.util.Map;
import com.luxoft.model.DivideOperator;
import com.luxoft.model.Element;
import com.luxoft.model.MinusOperator;
import com.luxoft.model.MultiplyOperator;
import com.luxoft.model.Number;
import com.luxoft.model.PlusOperator;
public class ElementExtractor {
private static Map<String,Element> map = new HashMap<String,Element>();
static {
map.put("+", new PlusOperator());
map.put("-", new MinusOperator());
map.put("*", new MultiplyOperator());
map.put("/", new DivideOperator());
}
public static Element extract(String element) {
try {
Integer i = Integer.parseInt(element);
return new Number(i);
}catch (NumberFormatException e) {
return map.get(element);
}
}
}
Other Classes
package com.luxoft.model;
import java.util.Stack;
public abstract class Element {
public abstract Stack<Element> process( Stack<Element> stack );
}
public class Number extends Element{
private Integer value;
public Number(Integer value) {
this.value = value;
}
public Stack<Element> process( Stack<Element> stack ){
stack.push( this );
return stack;
}
public Integer getValue() {
return value;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((value == null) ? 0 : value.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Number other = (Number) obj;
if (value == null) {
if (other.value != null)
return false;
} else if (!value.equals(other.value))
return false;
return true;
}
}
public class PlusOperator extends Element{
public PlusOperator() {
}
@Override
public Stack<Element> process(Stack<Element> stack) {
Number secondElement = (Number)stack.pop();
Number firstElement = (Number)stack.pop();
stack.push(new Number( firstElement.getValue() + secondElement.getValue() ) );
return stack;
}
}
public class MinusOperator extends Element{
public MinusOperator() {
}
@Override
public Stack<Element> process(Stack<Element> stack) {
Number secondElement = (Number)stack.pop();
Number firstElement = (Number)stack.pop();
stack.push(new Number( firstElement.getValue() - secondElement.getValue() ) );
return stack;
}
}
public class MultiplyOperator extends Element{
public MultiplyOperator() {
}
@Override
public Stack<Element> process(Stack<Element> stack) {
Number secondElement = (Number)stack.pop();
Number firstElement = (Number)stack.pop();
stack.push(new Number( firstElement.getValue() * secondElement.getValue() ) );
return stack;
}
}
public class DivideOperator extends Element{
public DivideOperator() {
}
@Override
public Stack<Element> process(Stack<Element> stack) {
Number secondElement = (Number)stack.pop();
Number firstElement = (Number)stack.pop();
stack.push(new Number( firstElement.getValue() / secondElement.getValue() ) );
return stack;
}
}
And Unit Tests
package com.luxoft;
import static org.junit.Assert.assertEquals;
import org.junit.Test;
public class CalculatorTest {
@Test
public void shouldCalculateCorrectWhenAdded() throws Exception {
Calculator calculator = new Calculator();
assertEquals(calculator.calculate("8 7 +"), Integer.valueOf(15) );
}
@Test
public void shouldCalculateCorrectWhenAddedMultipleValues() throws Exception {
Calculator calculator = new Calculator();
assertEquals(calculator.calculate("99 11 + 8 7 + +"), Integer.valueOf(125) );
}
@Test
public void shouldCalculateCorrectWhenMultiplied() throws Exception{
Calculator calculator = new Calculator();
assertEquals(calculator.calculate("4 7 *"), Integer.valueOf(28));
}
@Test
public void shouldCalculateCorrectWhenMultipliedMultipleValues() throws Exception{
Calculator calculator = new Calculator();
assertEquals(calculator.calculate("4 7 * 5 2 * *"), Integer.valueOf(280));
}
@Test
public void shouldCalculateCorrectWhenSubtracted() throws Exception {
Calculator calculator = new Calculator();
assertEquals( calculator.calculate("8 3 -") , Integer.valueOf(5));
}
@Test
public void shouldCalculateCorrectWhenSubtractedMultipleValues() throws Exception {
Calculator calculator = new Calculator();
assertEquals( calculator.calculate("33 3 - 10 6 - -") , Integer.valueOf(26));
}
@Test
public void shouldCalculateCorrectWhenDivided() throws Exception {
Calculator calculator = new Calculator();
assertEquals( calculator.calculate( "36 9 / " ) , Integer.valueOf(4));
}
@Test
public void shouldCalculateCorrectWhenDividedMultipleValues() throws Exception {
Calculator calculator = new Calculator();
assertEquals( calculator.calculate( "90 3 / 30 5 / /" ) , Integer.valueOf(5));
}
@Test
public void shouldCalculateCorrectWhenAnyOperation() throws Exception{
Calculator calculator = new Calculator();
assertEquals( calculator.calculate( "15 7 1 1 + - / 3 * 2 1 1 + + -" ) , Integer.valueOf(5));
}
@Test
public void shouldCalculateCorrectWhenAnyExample() throws Exception{
Calculator calculator = new Calculator();
assertEquals( calculator.calculate( "2" ) , Integer.valueOf(2));
assertEquals( calculator.calculate( "3 4 +" ) , Integer.valueOf(7));
assertEquals( calculator.calculate( "12 4 / 1 -" ) , Integer.valueOf(2));
assertEquals( calculator.calculate( "12 4 1 - /" ) , Integer.valueOf(4));
assertEquals( calculator.calculate( "15 7 1 1 + - / 3 * 2 1 1 + + -" ) , Integer.valueOf(5));
}
}