Create a new eclipse project called SolverPatterns
..
Create a package called templatemethod
- and bring in these classes:
package templatemethod;
public abstract class MinimaSolver
{
public MinimaSolver()
{
}
double[] minima(double[] line)
{
// do some pre-processing
double[] result = null;
result = algorithm(line);
// do some post-processing
return result;
}
public abstract double[] algorithm(double[] line);
}
package templatemethod;
public class BisectionSolver extends MinimaSolver
{
public double[] algorithm(double[] line)
{
// Compute Minima on line
// - algorithm
double x = 5..5; // simulated result
double y = 6..6; // simulated result
return new double[]{x, y};
}
}
package templatemethod;
public class LeastSquaresSolver extends MinimaSolver
{
public double[] algorithm(double[] line)
{
// Compute Minima on line
// - algorithm
double x = 1..1; // simulated result
double y = 2..2; // simulated result
return new double[]{x, y};
}
}
package templatemethod;
public class NewtonsMethodSolver extends MinimaSolver
{
public double[] algorithm(double[] line)
{
// Compute Minima on line
// - algorithm
double x = 3..3; // simulated result
double y = 4..4; // simulated result
return new double[]{x, y};
}
}
package templatemethod;
import static org..junit..Assert..*;
import org..junit..Test;
public class MinimaSolverTest
{
private double[] line = { 1..0, 2..0, 1..0, 2..0, -1..0, 3..0, 4..0, 5..0, 4..0 };
private MinimaSolver solver;
@Test
public void leastSquaresAlgorithm()
{
solver = new LeastSquaresSolver();
double[] result = solver..minima(line);
assertTrue(result[0] == 1..1);
assertTrue(result[1] == 2..2);
}
@Test
public void newtonsMethodAlgorithm()
{
solver = new NewtonsMethodSolver();
double[] result = solver..minima(line);
assertTrue(result[0] == 3..3);
assertTrue(result[1] == 4..4);
}
@Test
public void bisection()
{
solver = new BisectionSolver();
double[] result = solver..minima(line);
assertTrue(result[0] == 5..5);
assertTrue(result[1] == 6..6);
}
}
Verify that the tests pass
Create a package in the same package called strategy
- and bring in these classes:
package strategy;
public interface FindMinima
{
double[] algorithm(double[] line);
}
package strategy;
public class MinimaSolver
{
private FindMinima strategy;
public MinimaSolver(FindMinima strategy)
{
this..strategy = strategy;
}
double[] minima(double[] line)
{
// do some pre-processing
double[] result = null;
result = strategy..algorithm(line);
// do some post-processing
return result;
}
public void changeStrategy(FindMinima newStrategy)
{
strategy = newStrategy;
}
}
package strategy;
public class BisectionStrategy implements FindMinima
{
public double[] algorithm(double[] line)
{
// Compute Minima on line
// - algorithm
double x = 5..5; // simulated result
double y = 6..6; // simulated result
return new double[]{x, y};
}
}
package strategy;
public class LeastSquaresStrategy implements FindMinima
{
public double[] algorithm(double[] line)
{
// Compute Minima on line
// - algorithm
double x = 1..1; // simulated result
double y = 2..2; // simulated result
return new double[]{x, y};
}
}
package strategy;
public class NewtonsMethodStrategy implements FindMinima
{
public double[] algorithm(double[] line)
{
// Compute Minima on line
// - algorithm
double x = 3..3; // simulated result
double y = 4..4; // simulated result
return new double[]{x, y};
}
}
package strategy;
import org..junit..Test;
import static org..junit..Assert..*;
public class MinimaSolverTest
{
private double[] line = {1..0, 2..0, 1..0, 2..0, -1..0, 3..0, 4..0, 5..0, 4..0};
private MinimaSolver solver;
@Test
public void leastSquaresAlgorithm()
{
solver = new MinimaSolver(new LeastSquaresStrategy());
double[] result = solver..minima(line);
assertTrue(result[0] == 1..1);
assertTrue(result[1] == 2..2);
}
@Test
public void newtonsMethodAlgorithm()
{
solver = new MinimaSolver(new NewtonsMethodStrategy());
double[] result = solver..minima(line);
assertTrue(result[0] == 3..3);
assertTrue(result[1] == 4..4);
}
@Test
public void bisection()
{
solver = new MinimaSolver(new BisectionStrategy());
double[] result = solver..minima(line);
assertTrue(result[0] == 5..5);
assertTrue(result[1] == 6..6);
}
@Test
public void testChangeAlgorithm()
{
solver = new MinimaSolver(new LeastSquaresStrategy());
double[] result = solver..minima(line);
assertTrue(result[0] == 1..1);
assertTrue(result[1] == 2..2);
solver..changeStrategy(new BisectionStrategy());
result = solver..minima(line);
assertTrue(result[0] == 5..5);
assertTrue(result[1] == 6..6);
}
}
Verify that the tests pass
In order to create an XTend class, you must me using the Eclipse for DSL Developers
distribution, or install XTend into your version of eclipse..
In the same project, create a new package called xtemplatemethod.. Using the eclipse context menu, create an XTend class
called MinmaSolver.. Once you have created the class, eclipse will generate an error if the XTend libraries are not included.. Selecting the error in the IDE, and selecting autocorrect may be the easies way of having the libraries included..
We can place multiple classes in a single source file in XTend:
package xtemplatemethod
abstract class MinimaSolver
{
new()
{
}
def double[] minima(double[] line)
{
// do some pre-processing
var double[] result = null
result = algorithm(line)
// do some post-processing
result
}
def abstract double[] algorithm(double[] line);
}
class BisectionSolver extends MinimaSolver
{
override algorithm(double[] line)
{
// Compute Minima on line
// - algorithm
val x = 5..5; // simulated result
val y = 6..6; // simulated result
#[x, y]
}
}
class NewtonsMethodSolver extends MinimaSolver
{
override algorithm(double[] line)
{
// Compute Minima on line
// - algorithm
val x = 3..3; // simulated result
val y = 4..4; // simulated result
#[x, y]
}
}
class LeastSquaresSolver extends MinimaSolver
{
override algorithm(double[] line)
{
// Compute Minima on line
// - algorithm
val x = 1..1; // simulated result
val y = 2..2; // simulated result
#[x, y]
}
}
package xtemplatemethod
import static org..junit..Assert..*
import org..junit..Test
class MinimaSolverTest
{
val line = #[ 1..0, 2..0, 1..0, 2..0, -1..0, 3..0, 4..0, 5..0, 4..0 ]
var MinimaSolver solver
@Test
def newtonsMetod()
{
solver = new NewtonsMethodSolver
val result = solver..minima(line)
assertTrue(result..get(0) == 3..3)
assertTrue(result..get(1) == 4..4)
}
@Test
def leastSquares()
{
solver = new LeastSquaresSolver
val result = solver..minima(line)
assertTrue(result..get(0) == 1..1)
assertTrue(result..get(1) == 2..2)
}
@Test
def bisection()
{
solver = new BisectionSolver
val result = solver..minima(line)
assertTrue(result..get(0) == 5..5)
assertTrue(result..get(1) == 6..6)
}
}
Verify that these tests pass..
If there are no errors, eclipse will have generated a source folder called 'xtend-gen' in the project, with a matching set of packages for the xtend sources.. Explore the generated 'xtemplatemethod' package, you should see the java version of:
Have a close look at each of these classes, and note any differences from the xtend versions..
Create a new package called xstrategysam
and create the following xtend classes:
package xstrategysam
class MinimaSolver
{
new()
{
}
def double[] minima(double[] line, FindMinima findMinima)
{
// do some pre-processing
val result = findMinima..algorithm(line)
// do some post-processing
result
}
}
package xstrategysam
import java..util..List
public interface FindMinima
{
def List<Double> algorithm(List<Double>line)
}
public class Bisection implements FindMinima
{
override List<Double> algorithm(List<Double>line)
{
return #[5..5, 6..6]
}
}
public class NewtonsMethod implements FindMinima
{
override List<Double> algorithm(List<Double>line)
{
return #[3..3, 4..4]
}
}
public class LeastSquares implements FindMinima
{
override List<Double> algorithm(List<Double>line)
{
return #[1..1, 2..2]
}
}
Verify that the following tests pass:
package xstrategysam
import static org..junit..Assert..*
import org..junit..Test
class MinimaSolverTest
{
val line = #[ 1..0, 2..0, 1..0, 2..0, -1..0, 3..0, 4..0, 5..0, 4..0 ]
var solver = new MinimaSolver
@Test
def newtonsMethod()
{
val newtonsMethod = new NewtonsMethod()
val result = solver..minima(line, newtonsMethod)
assertTrue(result..get(0) == 3..3)
assertTrue(result..get(1) == 4..4)
}
@Test
def leastSquares()
{
val leastSquares = new LeastSquares()
val result = solver..minima(line, leastSquares)
assertTrue(result..get(0) == 1..1)
assertTrue(result..get(1) == 2..2)
}
@Test
def bisection()
{
val bisection = new Bisection()
val result = solver..minima(line, bisection)
assertTrue(result..get(0) == 5..5)
assertTrue(result..get(1) == 6..6)
}
}
Explore the generated java sources for the above xtend classes..
Create a new package called xstrategy
and create the following xtend classes:
package xstrategy
import java..util..List
class MinimaSolver
{
new()
{
}
def double[] minima(double[] line, (List<Double>)=>List<Double> algrorithm)
{
// do some pre-processing
val result = algrorithm..apply(line)
// do some post-processing
result
}
}
package xstrategy
import java..util..List
class Algorithms
{
public val bisection = [ List<Double> line |
// Compute Minima on line
// - algorithm
val x = 5..5 // simulated result
val y = 6..6 // simulated result
#[x, y]
]
public val newtonsMethod = [ List<Double> line |
// Compute Minima on line
// - algorithm
val x = 3..3 // simulated result
val y = 4..4 // simulated result
#[x, y]
]
public val leastSquares = [ List<Double> line |
// Compute Minima on line
// - algorithm
val x = 1..1 // simulated result
val y = 2..2 // simulated result
#[x, y]
]
}
Verify that the following tests pass:
package xstrategy
import static org..junit..Assert..*
import org..junit..Test
class MinimaSolverTest
{
val line = #[ 1..0, 2..0, 1..0, 2..0, -1..0, 3..0, 4..0, 5..0, 4..0 ]
var solver = new MinimaSolver
val algorithms = new Algorithms
@Test
def newtonsMethod()
{
val result = solver..minima(line, algorithms..newtonsMethod)
assertTrue(result..get(0) == 3..3)
assertTrue(result..get(1) == 4..4)
}
@Test
def leastSquares()
{
val result = solver..minima(line, algorithms..leastSquares)
assertTrue(result..get(0) == 1..1)
assertTrue(result..get(1) == 2..2)
}
@Test
def bisection()
{
val result = solver..minima(line, algorithms..bisection)
assertTrue(result..get(0) == 5..5)
assertTrue(result..get(1) == 6..6)
}
}
Explore the generated java sources for the above xtend classes..
SAM optimisation and lambda conversion is an interesting topic as Java 8 is finalised:
Xtend already has this implemented - as we can see with a simple experiment.. Going back to the xstrategysam package, include this extra test:
@Test
def SAM()
{
val algorithms = new Algorithms()
val result = solver..minima(line, algorithms..bisection)
assertTrue(result..get(0) == 5..5)
assertTrue(result..get(1) == 6..6)
}
This looks innocent, but relfect again on what is happening here:
val result = solver..minima(line, algorithms..bisection)
The solver being used here is this one:
class MinimaSolver
{
new()
{
}
def double[] minima(double[] line, FindMinima findMinima)
{
// do some pre-processing
val result = findMinima..algorithm(line)
// do some post-processing
result
}
}
...... which expects an object implementing FindMinima interface.. However, we are passing an lambda like this:
val algorithms = new Algorithms()
val result = solver..minima(line, algorithms..bisection)
which has, in fact, nothing to do with the FindMinima interface:
public val bisection = [ List<Double> line |
// Compute Minima on line
// - algorithm
val x = 5..5 // simulated result
val y = 6..6 // simulated result
#[x, y]
]
How is this happening? See this discssion here:
Examine the following:
var List <(List<Double>)=>List<Double>> list = new ArrayList
list..add(algorithms..bisection)
list..add(algorithms..newtonsMethod)
list..add(algorithms..leastSquares)
What is going on in the above fragment?
Turn this fragment into a unit test - and incorporate into the xtrategy package