patternjavaMinor
Reflection and Project Euler
Viewed 0 times
andreflectionprojecteuler
Problem
I have made a Project Euler runner in order to facilitate the running of the various problems. I have never used reflection before, and I believe that I have found a good use for reflection within this project.
My question boils down to this:
```
package ProjectEulerRunner;
import static java.lang.System.*;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Scanner;
public class ProjectEulerRunner
{
private static final int NUM_OF_PROBLEMS = 20;
private static final Scanner scan = new Scanner(in);
public static void main(String[] args) throws InstantiationException, IllegalAccessException, NoSuchMethodException, SecurityException, IllegalArgumentException, InvocationTargetException, IOException
{
for(;;)
{
out.println("Welcome to the Project Euler problem solver!");
out.println("==========================================================");
out.println("Total Number of Problems: " + NUM_OF_PROBLEMS);
out.println("==========================================================");
out.println();
out.println("What would you like to do?");
out.println();
out.println("(1) Run all Project Euler problems.");
out.println("(2) Run a specific problem number. Between 1 and " + NUM_OF_PROBLEMS);
out.println("(3) Get all problem descriptions.");
out.println("(4) Get a specific problem description.");
out.println("(5) View all incomplete problems");
out.println("(6) Basic problem statistics. (Percentage Correct, etc.)");
out.println("(7) Advanced problem statistics. (Average Run Times, Collated Data, etc.");
out.println("(0) Exit");
out.printl
My question boils down to this:
- Is this an appropriate use of reflection? Or am I approaching this the wrong way?
- Is the static import of System wrong in this case?
```
package ProjectEulerRunner;
import static java.lang.System.*;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Scanner;
public class ProjectEulerRunner
{
private static final int NUM_OF_PROBLEMS = 20;
private static final Scanner scan = new Scanner(in);
public static void main(String[] args) throws InstantiationException, IllegalAccessException, NoSuchMethodException, SecurityException, IllegalArgumentException, InvocationTargetException, IOException
{
for(;;)
{
out.println("Welcome to the Project Euler problem solver!");
out.println("==========================================================");
out.println("Total Number of Problems: " + NUM_OF_PROBLEMS);
out.println("==========================================================");
out.println();
out.println("What would you like to do?");
out.println();
out.println("(1) Run all Project Euler problems.");
out.println("(2) Run a specific problem number. Between 1 and " + NUM_OF_PROBLEMS);
out.println("(3) Get all problem descriptions.");
out.println("(4) Get a specific problem description.");
out.println("(5) View all incomplete problems");
out.println("(6) Basic problem statistics. (Percentage Correct, etc.)");
out.println("(7) Advanced problem statistics. (Average Run Times, Collated Data, etc.");
out.println("(0) Exit");
out.printl
Solution
There are two concerns here of significance.
First up, I am not certain that reflection is the right tool for the job. You've done it in an effective (if messy) way, but a better approach would be to have each problem implement an interface, something like:
Now, you can use that to get the ID and solution, once you have the instance you need.
To get the instance, I would go the traditional route of adding instances to an array:
Then, if you want to, you can add them to a structure like a TreeMap, that will sort them for you. Something like:
Once they are in that Map, it would be easy to locate, and find things.
If you need to use reflection, I would still use a Map-like structure, but would only use it to locate the class definitions, and then still have the interface that each class uses. Only create instances that implement the interface. That way you can just use a system like (excluding exceptions)...:
Once you have the class instances in the map, you are singing ;-)
That's enough for the reflection, but what about the rest?
Your runAllProblems() does far too much. At a minimum I would expect a method that contains:
Then, I expect your code to be broken in to one part that builds up the available tests, and another part that loops through what's available, and runs it.
You can then, as you extend your code, use these smaller methods to solve the smaller activities.
First up, I am not certain that reflection is the right tool for the job. You've done it in an effective (if messy) way, but a better approach would be to have each problem implement an interface, something like:
public interface ProblemSolver {
public int getID();
public void solve();
}Now, you can use that to get the ID and solution, once you have the instance you need.
To get the instance, I would go the traditional route of adding instances to an array:
private static ProblemSolver[] SOLVERS = {
new Problem1Solver(),
new Problem2Solver(),
....
}Then, if you want to, you can add them to a structure like a TreeMap, that will sort them for you. Something like:
SortedMap mySolvers = new TreeMap<>();
for (ProblemSolver ps : SOLVERS) {
mySolvers.put(ps.getID(), ps);
}Once they are in that Map, it would be easy to locate, and find things.
If you need to use reflection, I would still use a Map-like structure, but would only use it to locate the class definitions, and then still have the interface that each class uses. Only create instances that implement the interface. That way you can just use a system like (excluding exceptions)...:
try {
Class eulerclass = Class.forName(prefix + number + suffix);
if (eulerclass.isInstance(ProblemSolver.class)) {
ProblemSolver instance = ProblemSolver.class.cast(eulerclass.newInstance());
mySolvers.put(instance.getId(), instance);
}
} .....Once you have the class instances in the map, you are singing ;-)
That's enough for the reflection, but what about the rest?
Your runAllProblems() does far too much. At a minimum I would expect a method that contains:
public void runEuler(ProblemSolver problem) {
System.out.println("Running problem " + problem.getID());
try {
problem.solve();
System.out.println("Problem " + problem.getID() + " PASSED!");
} catch (RuntimeException re) {
// expect no checked exceptions, runtimes only.
System.out.println("Problem " + problem.getID() + " FAILED!");
re.printStackTrace();
}
}Then, I expect your code to be broken in to one part that builds up the available tests, and another part that loops through what's available, and runs it.
You can then, as you extend your code, use these smaller methods to solve the smaller activities.
Code Snippets
public interface ProblemSolver {
public int getID();
public void solve();
}private static ProblemSolver[] SOLVERS = {
new Problem1Solver(),
new Problem2Solver(),
....
}SortedMap<Integer, ProblemSolver> mySolvers = new TreeMap<>();
for (ProblemSolver ps : SOLVERS) {
mySolvers.put(ps.getID(), ps);
}try {
Class eulerclass = Class.forName(prefix + number + suffix);
if (eulerclass.isInstance(ProblemSolver.class)) {
ProblemSolver instance = ProblemSolver.class.cast(eulerclass.newInstance());
mySolvers.put(instance.getId(), instance);
}
} .....public void runEuler(ProblemSolver problem) {
System.out.println("Running problem " + problem.getID());
try {
problem.solve();
System.out.println("Problem " + problem.getID() + " PASSED!");
} catch (RuntimeException re) {
// expect no checked exceptions, runtimes only.
System.out.println("Problem " + problem.getID() + " FAILED!");
re.printStackTrace();
}
}Context
StackExchange Code Review Q#68145, answer score: 5
Revisions (0)
No revisions yet.