Better way to call common method on randomly selected object in java - java

Nice day to everybody.
I have an abstract class with the method runRandomExercise(), and several classes that extends it to add different kind of exercise.
I now want to chose a random type exercise, so I need to randomly choose one of the classes, and call runRandomExercise() on that.
For now I am manually coding this, which is not the very best solution I think. However, I can’t store just the classes in the array since the class type is different, and if I use object[] I can’t call the runRandomExercise() method. Any smart way to handle this?
Here is my code till now. It works, but it’s gonna be a pain to add other classes...
/*Specific classes that extend abstract class TrainingClass with the runRandomExercise() method*/
private MatheMagic mMathMag;
private Mnemonics mMnemonics;
private String[] mTrainingClasses;
/*Initialize classes*/
mMathMag = new MatheMagic();
mMnemonics = new Mnemonics();
/*Manually store classe names*/
mTrainingClasses = new String[2];
mTrainingClasses[0] = "mMathMag";
mTrainingClasses[1] = "mMnemonics";
/*Return random exercise*/
public String[] RandomExercise() {
Random aGenerator = new Random();
/*Get random class name*/
int rnd = aGenerator.nextInt(mTrainingClasses.length);
String aChosen = mTrainingClasses[rnd];
String[] aRes = new String[2];
if (aChosen == "mMathMag") {
aRes = mMathMag.runRandomExercise();
} else if (aChosen == "mMnemonics") {
aRes = mMnemonics.runRandomExercise();
}
return aRes;
}
EDIT
Here is how TrainingClass is defined:
/** Common interface for all exercises */
public interface Exercise {
public String[] run();
}
/** Common interface for all training classes */
public abstract class TrainingClass {
private Random mRandGen = new Random();
public ArrayList<Exercise> mExerciseTypes = new ArrayList<Exercise>();
/** Run a random exercise */
public String[] runRandomExercise() {
int i = mRandGen.nextInt(mExerciseTypes.size());
return mExerciseTypes.get(i).run();
}
}
/*Specific training class*/
public class MatheMagic extends TrainingClass {
public MatheMagic() {
class SomeExercise implements Exercise {
public String[] run() {
String[] mRes = new String[2];
mRes[0] = "Question type 1";
mRes[1] = "Answer type 1";
return mRes;
}
}
class SomeOtherExercise implements Exercise {
public String[] run() {
String[] mRes = new String[2];
mRes[0] = "Question type 2";
mRes[1] = "Answer type 2";
return mRes;
}
}
SomeExercise mN = new SomeExercise();
SomeOtherExercise mS = new SomeOtherExercise();
mExerciseTypes.add(mN);
mExerciseTypes.add(mS);
}
}

Easy solution is to create an interface with the common method and have all your classes extend it.
Create a collection or array of that type instead of Object; you can simply iterate through or randomly select and call the method you want.
It feels like a Command pattern from GoF to me.
public interface Exercise {
void execute();
}
Now your classes do this:
public class MatheMagic implements Execise {
public void execute() {
// special logic here.
}
}
Then you can do this:
int numExercises = 1;
Exercise [] exercises = new Exercise[numExercises];
exercises[0] = new MatheMagic();
for (Exercise exercise : exercises) {
exercise.execute();
}

Yes, yes you can store all those Classes in an array and then call them at random. How? Create an interface and in all your classes derive from that interface. That way you can invoke based on interface, and not on implementation.

Related

Java: Making classes with arrays and using those arrays in another class

I've looked around and haven't found an answer to exactly what I am asking so here it is:
I'm new to Java and I need to make a class that has 3 arrays which can be called from another class. I am lost because I don't know how to "properly" create the instance so that it can be called from the other class without inheritance.
public class Book {
int[] Book0 = new int[7];
int[] Book1 = new int[4];
int[] Book2 = new int[3];
public Book {
Book0 = new int[] {1,2,3,4,5,6,7};
Book1 = new int[] {};
Book2 = new int[] {};
}
}
public class Catalogue {
public Catalogue{
}
}
In class Catalogue I'm not sure how to call the instance in class Book. Do I need to change class Book and put "this"? If so, is it this() or this.____? Or do you do that in class Catalogue?
You want to encapsulate your fields with getters and setters and give your getters public access type so you can access your array outside of the object, and package.
public class Book {
int[] Book0;
int[] Book1;
int[] Book2;
public Book {
Book0 = {1,2,3,4,5,6,7};
Book1 = new int[4];
Book2 = new int[3];
}
public int[] getBook0(){
return Book0;
}
public int[] getBook1(){
return Book1;
}
public int[] getBook2(){
return Book2;
}
}
public class Catalogue {
public Catalogue{
Book book = new Book();
int[] tempArray = book.getBook0();
}
}
You need to create an object of the class and the you can use that object to call methods or a constructor.
Book book = new Book();
You would probably want to instantiate Book and use the instance.
In Catalogue class (or any other class that uses Book):
Book b = new Book();
b.Book0; // {1,2,3,4,5,6,7}
b.Book1; // {}
b.Book2; // {}
Also you should declare the arrays as explicitly public, to indicate everyone can see and modify them.
If this Book object will have further functionalities (methods it implements) you should probably not use it like this but declare the arrays as private, not allowing access to any other class, and using getters/setters instead (think if you really need direct access).
By the way, in your code you initialize the three arrays with empty arrays with sizes 3, 4, and 7. These initializations are overriden by the constructor (which resets the arrays).
I'm not sure, but if i understood you, you want do something like that:
public class Book {
// private fields : Remmember, in java + OOP class members should be private
private String[] page0;
private String[] page1;
private String[] page2;
public Book(int sizeOfPage0, int sizeOfPage1, int sizeOfPage2) {
page0 = new String[sizeOfPage0]; // Argument inside [] sets array size
page1 = new String[sizeOfPage1];
page2 = new String[sizeOfPage2];
}
// Getters
public String[] getPage0() {
return page0;
}
public String[] getPage1() {
return page0;
}
public String[] getPage2() {
return page2;
}
}
public class Catalogue {
private Book[] books;
public Catalogue(Book[] books) {
this.books = books;
}
public Book[] getBooks() {
return this.books;
}
}
public class MyApp {
// entrypoint of the application
public static void main(String[] args) {
Book book1 = new Book(2, 1, 1);
book.getPage0()[0] = "In some place of 'La mancha' which I do not want remember";
book.getPage0()[1] = "lives some 'hidalgo' ... etc";
book.getPage1()[0] = "Sancho Panza as squire of Don Quijote";
Book book2 = new Book(1, 3, 1);
// ... something similar...
Book[] books = {book1, book2};
Catalogue catalogue = new Catalogue(books);
System.out.println(catalogue.getBooks()[0].getPage0()[0]);
}
}
Remember to take each class into a separated file or get only one public class and the rest default per file

How to avoid a circular reference in Java

I'm trying to create two different classes that represent different options of exercises the user can choose to sort by. After one class is chosen, the other is no longer an option, because of this I create an ArrayList in both classes of classes which are not allowed to follow it.
The problem is that since they are not able to follow each other, when these classes are constructed it results in an infinite loop, is there any way I can avoid this?
PushPullLegs Class
public class PushPullLegs extends SortingGroup implements Serializable{
public PushPullLegs(){
this.setName("Push,Pull,Legs");
this.addCantFollow(new MuscleGroup());
SortingCategory push = new SortingCategory("Push","PPL","Push");
this.addOption(push);
SortingCategory pull = new SortingCategory("Pull","PPL","Pull");
this.addOption(pull);
SortingCategory legs = new SortingCategory("Legs","PPL","Legs");
this.addOption(legs);
}
}
MuscleGroup Class
public class MuscleGroup extends SortingGroup implements Serializable {
public MuscleGroup(){
this.addCantFollow(new PushPullLegs());
SortingCategory chest = new SortingCategory("Chest","Primary","Chest");
chest.addNewOptions(new ChestMovementPatterns());
this.addOption(chest);
SortingCategory triceps = new SortingCategory("Triceps","Primary","Triceps");
triceps.addNewOptions(new TricepMovementPatterns());
this.addOption(triceps);
SortingCategory lats = new SortingCategory("Lats","Primary","Lats");
this.addOption(lats);
SortingCategory quads = new SortingCategory("Quads","Primary","Quads");
this.addOption(quads);
SortingCategory hamstrings = new SortingCategory("Hamstrings","Primary","Hamstrings");
this.addOption(hamstrings);
}
}
You would use code like this:
private Set<Class<? extends SortingGroup>> cantFollowClass = new HashSet<>();
public void addCantFollow(Class<? extends SortingGroup> clazz) {
this.cantFollowClass = clazz;
}
public boolean canFollow(SortingGroup group) {
return ! this.cantFollowClass.contains(group.getClass());
}

Using a fluent builder pattern without inner static classes for workflow

This is a continuation from what I was working in Passing 1 to many parameters of same object type
I've gotten good feedback on that , I believe i have the improved the design . The whole code is at https://github.com/spakai/flow_input_builder
The requirement is simple : -
I need to build a set of input for different workflows using 1 or more outputs from previous workflows
I have a set of interfaces
public interface SwfInput {
}
public interface SwfOutput {
}
public interface Workflow<I extends SwfInput, O extends SwfOutput> {
public O execute(I input);
}
public interface Builder<I extends SwfInput> {
public I build();
}
Now , Say I have 3 flows which gets executed in sequence FlowA->FlowB->FlowC
FlowC needs mandatory output from FlowB but only optionally from FlowA
so I have a implementation for FlowCBuilder
public class FlowCInputBuilder implements Builder<FlowCInput> {
private final FlowBOutput mandatoryflowBOutput;
private FlowAOutput optionalflowAOutput;
public FlowAOutput getOptionalflowAOutput() {
return optionalflowAOutput;
}
public FlowCInputBuilder setOptionalflowAOutput(FlowAOutput optionalflowAOutput) {
this.optionalflowAOutput = optionalflowAOutput;
return this;
}
public FlowCInputBuilder(FlowBOutput mandatoryflowBOutput) {
this.mandatoryflowBOutput = mandatoryflowBOutput;
}
#Override
public FlowCInput build() {
FlowCInput input = new FlowCInput();
input.setMandatoryFromFlowB(mandatoryflowBOutput.getOutput1FromB());
if (optionalflowAOutput != null) {
input.setOptionalFromFlowA(optionalflowAOutput.getOutput2FromA());
}
return input;
}
}
one test i have written shows an example usage
FlowBOutput mandatoryflowBOutput = new FlowBOutput();
mandatoryflowBOutput.setOutput1FromB("iNeedThis");
FlowAOutput optionalflowAOutput = new FlowAOutput();
FlowCInput input = new FlowCInputBuilder(mandatoryflowBOutput)
.setOptionalflowAOutput(optionalflowAOutput)
.build();
I have not used static inner class for the Builder pattern.
Any suggestions are welcomed.
You should use static inner class. The key point of using this approach is that, the inner can directly access private properties of the object being constructed. This helps eliminating duplicated code since the builder does not need to maintain a long list of temporary state for the constructing. So, your code can be rewritten like this:
public class FlowCInput {
private int output1FromB; // suppose that it is int
private String output2FromA; // suppose that it is String
private FlowCInput() { }
//...
public static class FlowCInputBuilder implements Builder<FlowCInput> {
private final FlowCInput result;
public FlowCInputBuilder(FlowBOutput mandatoryflowBOutput) {
result = new FlowCInput();
// output1FromB is private but still accessed from here
result.output1FromB = mandatoryflowBOutput.getOutput1FromB();
}
public FlowCInputBuilder setOptionalflowAOutput(FlowAOutput optionalflowAOutput) {
// same for output2FromA
result.output2FromA = optionalflowAOutput.getOutput2FromA();
return this;
}
#Override
public FlowCInput build() {
return result;
}
}
}
As you see, the builder now holds only a FlowCInput object, it does not unnecessarily hold mandatoryflowBOutput and optionalflowAOutput as before.

initialise superclass array in subclass (java)

I am new to JAVA / Android programming and have a small problem.
I created in a Superclass a Array and wanted to initialize it in multiple subclasses. But when I try to initialize it, it says it's not possible.
My code:
public abstract class Fragen {
String[] Deutsch;
String[] Slowakisch;
static int Anzahl;
Random random;
int randNumber;
byte Fächer;
public String displayQuestion()
{
//TODO Fach abfragen
randNumber = random.nextInt(Anzahl);
return Slowakisch[randNumber];
}
public boolean correctAnswer(String answer)
{
//TODO Fächer +/-
if(answer.equals(Deutsch[randNumber]))
return true;
else
return false;
}
}
(Superclass)
public class Lektion1 extends Fragen
{
private Lektion1()
{
super();
Anzahl = 60;
//Deutsch = new String[];
Deutsch = {"",""};
Slowakisch = {"",""};
}
}
(Subclass)
Kind regards
Thomas
Try this:
public class Lektion1 extends Fragen
{
private Lektion1()
{
super();
Anzahl = 60;
//Deutsch = new String[];
Deutsch = new String[]{"", ""};
Slowakisch = new String[]{"", ""};
}
}
Just create a constructor in your super class and initialize that array there:
public abstract class Fragen {
...
public Fragen() {
Deutsch = new String[];
}
...
}
alternative
or if your fields have appropriate access modifiers, then you can also access them using super keyword
public abstract class Fragen {
public String[] Deutsch;
...
...
}
and in base class:
public class Lektion1 extends Fragen {
private Lektion1()
{
super();
Anzahl = 60;
super.Deutsch = new String[];
Deutsch = {"",""};
Slowakisch = {"",""};
}
}
Edit: For a conrete answer to your concrete question, #MrQuattro’s answer is of course correct and fulfilling.
That said, if you want to learn more of object-oriented design, I still myself like the ideas from my original answer. You can of course throw away or use as you see fit: I propose that it will be more convenient to keep the German and the Slovakian word together, so I’d make a class Frage to hold one word (or phrase or expression) in both languages.
Next I’d want to make a constructor in Fragen that accepts all the Frage objects, for instance as varargs (you should learn about those). This will allow the Lektion1 constructor to contain just
super(new Frage("", ""), new Frage("", ""), new Frage("", ""));
Fragen can count, so you don’t need to: the superclass constructor will set anzahl (please use lowercase a for a variable) to the number of questions received.
If you want to take it a step further, the Frage class could also be given the responsibility of checking whether an answer is correct.
Link: Anti-pattern: parallel collections

How to model cycles between immutable class instances?

Immutable classes are great but there is one big problem i cant think of a sensible way to solve - cycles.
class Friend {
Set<Friend> friends();
}
How does one model Me having You as a friend who in turn has me as a Friend back ?
IMMUTABILITY
This class from the outside world should definitely be immutable. The value held internally should be constant for the purposes of equality checks.
[[[ Edit: Added code to demonstrate fully immutable concept ]]]
That's why builders are so nice for immutables - they allow mutability during construction to get everything set before you "freeze" it. In this case, I guess you need a Friend builder that supports creating cycles.
final FriendBuilder john = new FriendBuilder().setName("john");
final FriendBuilder mary = new FriendBuilder().setName("mary");
final FriendBuilder susan = new FriendBuilder().setName("susan");
john
.likes(mary)
.likes(susan);
mary
.likes(susan)
.likes(john);
susan
.likes(john);
// okay lets build the immutable Friends
Map<Friend> friends = FriendsBuilder.createCircleOfFriends(john, mary, susan);
Friend immutableJohn = friends.get("john");
Edit: Added immutable example below to demonstrate approach:
There was some discussion in the comments about whether an immutable version was possible.
Fields are final and immutable. A modifiable set is used in the constructor, but it only the unmodifiable reference is kept after construction.
I have another version that uses Guava ImmutableSet for a truly immutable set rather than JDK's unmodifiable wrapper. It works the same, but uses Guava's nice set builder.
Code:
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.IdentityHashMap;
import java.util.Map;
import java.util.Set;
/**
* Note: potentially cycle graph - be careful of deep equals/hashCode/toString/etc.
* Immutable
*/
public class Friend {
public static class Builder {
private final String name;
private final Set<Builder> friends =
new HashSet<Builder>();
Builder(final String name) {
this.name = name;
}
public String getName() {
return name;
}
public Set<Builder> getFriends() {
return friends;
}
void likes(final Builder... newFriends) {
for (final Builder newFriend : newFriends)
friends.add(newFriend);
}
public Map<String, Friend> createCircleOfFriends() {
final IdentityHashMap<Builder, Friend> existing =
new IdentityHashMap<Builder, Friend>();
// Creating one friend creates the graph
new Friend(this, existing);
// after the call existingNodes contains all the nodes in the graph
// Create map of the all nodes
final Map<String, Friend> map =
new HashMap<String, Friend>(existing.size(), 1f);
for (final Friend current : existing.values()) {
map.put(current.getName(), current);
}
return map;
}
}
final String name;
final Set<Friend> friends;
private Friend(
final Builder builder,
final Map<Builder, Friend> existingNodes) {
this.name = builder.getName();
existingNodes.put(builder, this);
final IdentityHashMap<Friend, Friend> friends =
new IdentityHashMap<Friend, Friend>();
for (final Builder current : builder.getFriends()) {
Friend immutableCurrent = existingNodes.get(current);
if (immutableCurrent == null) {
immutableCurrent =
new Friend(current, existingNodes);
}
friends.put(immutableCurrent, immutableCurrent);
}
this.friends = Collections.unmodifiableSet(friends.keySet());
}
public String getName() {
return name;
}
public Set<Friend> getFriends() {
return friends;
}
/** Create string - prints links, but does not traverse them */
#Override
public String toString() {
final StringBuffer sb = new StringBuffer();
sb.append("Friend ").append(System.identityHashCode(this)).append(" {\n");
sb.append(" name = ").append(getName()).append("\n");
sb.append(" links = {").append("\n");
for (final Friend friend : getFriends()) {
sb
.append(" ")
.append(friend.getName())
.append(" (")
.append(System.identityHashCode(friend))
.append(")\n");
}
sb.append(" }\n");
sb.append("}");
return sb.toString();
}
public static void main(final String[] args) {
final Friend.Builder john = new Friend.Builder("john");
final Friend.Builder mary = new Friend.Builder("mary");
final Friend.Builder susan = new Friend.Builder("susan");
john
.likes(mary, susan);
mary
.likes(susan, john);
susan
.likes(john);
// okay lets build the immutable Friends
final Map<String, Friend> friends = john.createCircleOfFriends();
for(final Friend friend : friends.values()) {
System.out.println(friend);
}
final Friend immutableJohn = friends.get("john");
}
}
Output:
Node 11423854 {
value = john
links = {
susan (19537476)
mary (2704014)
}
}
Node 2704014 {
value = mary
links = {
susan (19537476)
john (11423854)
}
}
Node 19537476 {
value = susan
links = {
john (11423854)
}
}
The correct way to model a cycle is with a Graph. And a single source code line comment can be enough to enforce inmutability: "can't touch this".
What kind of inmutable enforcement are you looking for? Do you want a a velociraptor to appear whenever you modify the inmutable Set? The difference between mutable and inmutable is just a convention. However, the bits on the RAM can be easily modified and with the Reflection API you can break any encapsulation and data hiding conventions.
Ignoring the velociraptor for a moment, Java does not support an inmutable type. As a workaround, you need to model a datatype that behaves like one.
And for the inmutable property to make sense you need to make Friend an interface, having one implementing class: InmutableFriend, and the construction of the object should fully happen inside the constructor.
Then, since the graph contains cycles, before creating the final inmutable instances you need to store the graph nodes in some mutable temporary structure. You also need to return an unmodifiableSet on the InmutableFriend.friends() method.
Finally, to clone the graph you need to implement a Deep-copy algorithm like Breadth-first search on the Mutable graph. One question though is what happens when the graph is not fully connected.
interface Friend {
public Set<Friend> friends();
}
class MutableFriend {
private Set<MutableFriend> relations = new HashSet<MutableFriend>();
void connect(MutableFriend otherFiend) {
if (!relations.contains(otherFriend)) {
relations.add(otherFiend);
otherFriend.connect(this);
}
}
Friend freeze() {
Map<MutableFriend, InmutableFriend> table = ...;
/*
* FIXME: Implement a Breadth-first search to clone the graph,
* using this node as the starting point.
*
* TODO: If the graph is not connected this won't work.
*
*/
}
}
class InmutableFriend() implements Friend {
private Set<Friend> connections;
public Set<Friend> friends() {
return connections;
}
public InmutableFriend(Set<Friend> connections) {
// Can't touch this.
this.connections = Collections.unmodifiableSet(connections);
}
}
Immutability doesn't need to be compiler-enforced to be valid architecturaly. You can have a legitimate immutable object that takes post-construction initialization parameters. For instance...
private Object something;
public void init( final Object something )
{
if( this.something != null )
{
throw new IllegalStateException();
}
this.something = something
}
The member field "something" isn't final, but it cannot be set more than once either.
A more complex variant based on discussion in comments...
private boolean initialized;
private Object a;
private Object b;
public void init( final Object a, final Object b )
{
if( this.initialized )
{
throw new IllegalStateException();
}
this.initialized = true;
this.a = a;
this.b = b;
}
public Object getA()
{
assertInitialized();
return this.a;
}
public Object getB()
{
assertInitialized();
return this.b;
}
private void assertInitialized()
{
if( this.initialized )
{
throw new IllegalStateException( "not initialized" );
}
}

Categories