I have three classes.
public class PutController{
public PutController[] putControllerArray = new PutController[2];
public void controlar(int players) {
if(numeroJugadores==0){
putControllerArray[0] = new PutAutoController(tablero, tableroView, turno, turnoView);
putControllerArray[1] = new PutAutoController(tablero, tableroView, turno, turnoView);
}
if(numeroJugadores==1){
putControllerArray[0] = new PutManualController(tablero, tableroView, turno, turnoView);
putControllerArray[1] = new PutAutoController(tablero, tableroView, turno, turnoView);
}
}
}
public class PutManualController extends PutController {
public void methodToCall(){
.....
}
}
public class PutAutoController extends PutController {
public void methodToCall(){
.....
}
}
class Principal{
private PutController putController = new PutController(tablero, tableroView, turno, turnoView);
}
and in my Principal class i want to call a method of an element in the array of put class, like this.
putController.putControllerArray[0].methodToCall();
Hope you can help me. Thanks!
As long as PutController contains the method methodToCall() (either as an abstract method implemented by the sub classes, or with a concrete implementation in the base class), you can call it on any element of your array.
public class PutController
{
...
public void methodToCall ()
{
....
}
...
}
The sub-classes can override methodToCall() if they require different implementations.
This would make the code putControllerArray[0].methodToCall() valid. Of course, if you need to access that array from outside your class, you need to create an instance of your class, since it's not a static member. It would be better, though, to make the array private and access it via a method that returns the i'th element of the array.
public class PutController
{
...
public PutController getElement (int i)
{
if (i < 0 || i >= putControllerArray.length) {
// TODO throw some exception
}
return putControllerArray[i];
}
...
}
Then you can execute methodToCall() via putController.getElement(0).methodToCall();
Related
Yes, I read many examples in web, but I didn't find a way how to call a method based on string value. May be I am not searching in right way... I wrote all code, but don't know how to call the method.
fyi: I don't want to use if else or switch case
Here is what I want:
I get the card reader type as String from database. I have to call the corresponding class' method.
My code:
LoginPanel.java
public class LoginPanel {
public static void main(String args[]) {
String readerType = "Omnikey5427-CK"; // I get this ("Omnikey5427-CK" or "Omnikey5427-G2") from a database as String
// I WANT TO CALL getCardNumber() method of respective class
}
}
ISmartCardReader.java
public interface ISmartCardReader {
public Integer getCardNumber();
}
Omnikey5427G2.java
public class Omnikey5427G2 implements ISmartCardReader {
public Omnikey5427G2() {
System.out.println("G222222222222222...");
}
public Integer getCardNumber() {
return 222;
}
}
Omnikey5427CK.java
public class Omnikey5427CK implements ISmartCardReader {
public Omnikey5427CK() {
System.out.println("CKKKKKKKKKKKKKKK...");
}
public Integer getCardNumber() {
return 111;
}
}
SmacrtCardEnumFactory.java
public enum SmacrtCardEnumFactory {
OMNIKEY5427CK("Omnikey5427-CK") {
public ISmartCardReader geInstance() {
return new Omnikey5427CK();
}
},
OMNIKEY5427G2("Omnikey5427-G2") {
public ISmartCardReader geInstance() {
return new Omnikey5427G2();
}
};
private String cardReaderName;
private SmacrtCardEnumFactory(String cardReaderName) {
this.cardReaderName = cardReaderName;
}
public String cardReaderName() {
return cardReaderName;
}
}
You can use valueOf() function of enum provided your enum sonstant names match strings used to lookup (you may use cardName.toUpper()). You may also create objects for all the card types and store them in a hash map and then lookup them. You can also write some fatory method, but this will be if-then-else or switch inside
You could iterate over the factory's values() and get the one that matches the string:
public enum SmacrtCardEnumFactory {
// current code omitted for brevity
public static getSmartCardReader(String name) {
return Arrays.stream(values())
.filter(r -> r.cardReaderName().equals(name))
.map(SmacrtCardEnumFactory::getInstance();
.orElse(null);
}
}
I have created an array which I wanted to control from main. My code runs, but I don't know how to add integers to the array from the main class. Also as each ConcreteSubject has its own storage array, how would i change this to store them all in the same array?
public class ConcreteSubject extends AbstractSpy
{
private AbstractSpy[] spies = new AbstractSpy[10];
private int i = 0;
public void addSpy(AbstractSpy s) {
if (i < spies.length) {
spies[i] = s;
System.out.println("spy added at index " + i);
i++;
}
}
}
public class TestClass
{
public static void main(String[] args) {
ConcreteSubject cs = new ConcreteSubject();
AbstractSpy spies = new AbstractSpy() {
#Override
public void addSpy(AbstractSpy spies) {
}
};
cs.addSpy(cs);
spies.addSpy(spies);
}
}
It seems like your program logic is a little borked. This bit in particular doesn't make much sense:
***AbstractSpy spies = new AbstractSpy() {
#Override
public void addSpy(AbstractSpy spies) {
}
};
cs.addSpy(cs);
***spies.addSpy(spies);
What you're doing is creating TWO AbstractSpy instances, one named cs and one named spies. On that last line you're adding spies to itself! That doesn't help you at all.
Note that AbstractSpy is the most granular unit in your setup - it shouldn't have an addSpy() method and its own internal array, it should be the thing that's added to something else's array!
Here's the same code, but cleaned up a bit:
public abstract class AbstractSpy { }
public class ConcreteSpy extends AbstractSpy { }
public class ConcreteSubject {
private AbstractSpy[] spies = new AbstractSpy[10];
private int i = 0;
public void addSpy(AbstractSpy spy) {
if (i < spies.length)
{
spies[i] = spy;
System.out.println("spy added at index " + i);
i++;
}
}
}
public class TestClass {
public static void main(String[] args) {
ConcreteSubject cs = new ConcreteSubject();
AbstractSpy spy = new ConcreteSpy();
cs.addSpy(spy);
}
}
The big difference here is that ConcreteSpy is an implementation of AbstractSpy that you can add to your ConcreteSubject's array of spies. I think you might have been confused by Java's insistence that you can't create an instance of an abstract class on its own unless you supply an anonymous class that inherits from the abstract class.
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.
I don't understand how to use lambdas to pass a method as a parameter.
Considering the following (not compiling) code, how can I complete it to get it work ?
public class DumbTest {
public class Stuff {
public String getA() {
return "a";
}
public String getB() {
return "b";
}
}
public String methodToPassA(Stuff stuff) {
return stuff.getA();
}
public String methodToPassB(Stuff stuff) {
return stuff.getB();
}
//MethodParameter is purely used to be comprehensive, nothing else...
public void operateListWith(List<Stuff> listStuff, MethodParameter method) {
for (Stuff stuff : listStuff) {
System.out.println(method(stuff));
}
}
public DumbTest() {
List<Stuff> listStuff = new ArrayList<>();
listStuff.add(new Stuff());
listStuff.add(new Stuff());
operateListWith(listStuff, methodToPassA);
operateListWith(listStuff, methodToPassB);
}
public static void main(String[] args) {
DumbTest l = new DumbTest();
}
}
Declare your method to accept a parameter of an existing functional interface type which matches your method signature:
public void operateListWith(List<Stuff> listStuff, Function<Stuff, String> method) {
for (Stuff stuff : listStuff) {
System.out.println(method.apply(stuff));
}
}
and call it as such:
operateListWith(listStuff, this::methodToPassA);
As a further insight, you don't need the indirection of methodToPassA:
operateListWith(listStuff, Stuff::getA);
Your MethodParameter should be some interface you define with a single method. This is referred to as a functional interface. You can then pass your methods in. A quick demonstration:
public interface Test{
void methodToPass(string stuff);
}
[...]
public class DumbTest{
//MethodParameter is purely used to be comprehensive, nothing else...
public void operateListWith(List<Stuff> listStuff, Test method) {
for (Stuff stuff : listStuff) {
System.out.println(method(stuff));
}
}
public DumbTest() {
List<Stuff> listStuff = new ArrayList<>();
//fill list
operateListWith(listStuff, methodToPassA);
operateListWith(listStuff, methodToPassB);
}
}
The definition of MethodParameter is missing from your source code. To be used with lambda expressions, it must be a functional interface, for example:
#FunctionalInterface
interface MethodParameter {
String apply(Stuff input);
}
(The #FunctionalInterface annotation is optional.)
To use the method, you have call the method from the interface:
System.out.println(method.apply(stuff));
And thirdly, a method reference always needs a context. In your case you have to do:
operateListWith(listStuff, this::methodToPassA);
operateListWith(listStuff, this::methodToPassB);
You need to use method references.
You don't need to create a method like operateListWith, that's sort of the whole idea. Instead, you can operate on each value using forEach by doing something like this:
listStuff.stream.forEach(object::methodToPassA);
For example:
public class StreamExample {
public static void main(String[] args) {
List<String> list = Arrays.asList("Hello", "What's Up?", "GoodBye");
list.stream().forEach(System.out::println);
}
}
Output:
Hello
What's Up?
GoodBye
In your case, you can get the value inside Stuff using .map, and then operate on it using forEach, like this:
public class DumbTest {
public class Stuff {
public String getA() {
return "a";
}
public String getB() {
return "b";
}
}
public String methodToPassA(Stuff stuff) {
return stuff.getA();
}
public String methodToPassB(Stuff stuff) {
return stuff.getA();
}
public DumbTest() {
List<Stuff> listStuff = Arrays.asList(new Stuff(), new Stuff());
listStuff.stream()
.map(this::methodToPassA)
.forEach(System.out::println);
}
public static void main(String[] args) {
DumbTest l = new DumbTest();
}
}
I'm trying to design an undo/redo mechanism to my Chess game.. I decided to use stack data structure which is going to build on an ArrayList.. I also want that my UndoStack and RedoStack classes should be singleton.. However i'm getting
method does not override or implement a method from a supertype
pop() in UndoStack cannot implement pop() in IStackable
return type Move is not compatible with cgas5.Move
where Move is a type-variable:
Move extends Object declared in class UndoStack
error..
Here is my IStackable interface:
package cgas5;
public interface IStackable {
abstract public Move pop();
abstract public void push(Move m);
}
and my UndoStack class
package cgas5;
import java.util.ArrayList;
public class UndoStack<Move> extends ArrayList<Move> implements IStackable {
UndoStack undoStack;
private UndoStack() {
undoStack = new UndoStack();
}
public UndoStack getUndoStack() {
if (undoStack == null) {
undoStack = new UndoStack();
}
return undoStack;
}
#Override
public Move pop() {
Move m = get(size() - 1);
remove(size() - 1);
return m;
}
#Override
public void push(Move m) {
add(m);
}
}
and if it's necessary my Move class:
package cgas5;
public class Move {
private Piece pieceToMove;
private Square currentSquare;
private Square targetSquare;
private Piece capturedPiece;
private Piece promotedPiece;
public Move(){
}
public Move(Piece pieceToMove, Square currentSquare, Square targetSquare){
this.pieceToMove = pieceToMove;
this.currentSquare = currentSquare;
this.targetSquare = targetSquare;
}
public Piece getPieceToMove() {
return pieceToMove;
}
public void setPieceToMove(Piece pieceToMove) {
this.pieceToMove = pieceToMove;
}
public Square getCurrentSquare() {
return currentSquare;
}
public void setCurrentSquare(Square currentSquare) {
this.currentSquare = currentSquare;
}
public Square getTargetSquare() {
return targetSquare;
}
public void setTargetSquare(Square targetSquare) {
this.targetSquare = targetSquare;
}
public Piece getCapturedPiece() {
return capturedPiece;
}
public void setCapturedPiece(Piece capturedPiece) {
this.capturedPiece = capturedPiece;
}
public Piece getPromotedPiece() {
return promotedPiece;
}
public void setPromotedPiece(Piece promotedPiece) {
this.promotedPiece = promotedPiece;
}
}
Thanks in advance..
This is the problem:
public class UndoStack<Move> extends ArrayList<Move>
That's using Move as a generic type parameter, whereas really you don't want a generic type at all - you just want to use Move as the type argument for ArrayList<E>. You want:
public class UndoStack extends ArrayList<Move>
That should fix the problem - although personally I'd strongly recommend using composition instead of inheritance here. (In other words, make your UndoStack type contain an ArrayList<Move> - or something similar - rather than subclassing it.)
Additionally, this is never going to work:
UndoStack undoStack;
private UndoStack() {
undoStack = new UndoStack();
}
That means that to create an UndoStack, you need to create another UndoStack... how do you expect that to happen? You'll currently get a stack overflow exception... why do you need the variable at all?