How to allow a user to choose what class to initialise - java

I have an abstract class Foo, which contains a function a(Object o).
Depending on what implementation of Foo you use, a(Object o) is implemented slightly differently.
I want the user of the program to be able to determine what implementation of Foo is used (eg., aFoo,bFoo, cFoo, etc), but I want to cut down on my use of conditional logic so that I can add to my program more safely in the future.
I currently have an Enum eBar that holds the names of all the implementations of Foo, which the user can choose from, but I am unable to determine how to use that to initialise the class.

Store the instance of Foo to use, or add a method creating the Foo to use, in each enum instance:
public enum FooType {
A {
#Override
public Foo createFoo() {
return new AFoo();
}
},
B {
#Override
public Foo createFoo() {
return new BFoo();
}
}
public abstract Foo createFoo();
}
Then, once the user has chosen the type, all you need to do is
selectedFooType.createFoo().a(object);

[EDIT] You can do that using an Enum like below
public enum FooType {
FOO_A(aFoo::new),
FOO_B(bFoo::new),
FOO_C(cFoo::new);
//add as much as you want here
private final Supplier<Foo> fooSupp; //the aim of using a supplier is to create a new instance each time you call the create method as mentioned in the comment.
FooType(final Supplier<Foo> fooSupp) {
this.fooSupp = fooSupp;
}
public final Foo create(){
return this.fooSupp.get();
}
}
Then you can use it like this
final Foo myFoo = FooType.FOO_A.create();
myFoo.o(Object);

Related

Java method with unknown parameter type

I'm new to Java.
There is repeating code in multiple files in a project I'm working on.
Object types can be Thing1, Thing2, Thing3 etc.
So the code looks like:
if (Thing1.getStuff() instanceof String) {
myObj.setString("Hello");
} else {
myObj.setString("World");
}
I want to extend myObj with a class and method to handle this, as such:
public class myObj extends DoStuff {...}
--
class DoStuff {
public String doThis(*WHAT_TYPE_TO_USE* input) {
var String = input.myMethod(); // I need to call method.
return "String after some logic";
}
}
Which should allow me to run:
myObj.doThis("Something");
However, I can't specify input to be a specific type in the method as it could be Thing1, Thing2 etc. Also, Thing1 and Thing2 can't be dynamically imported, can they? How can I run myMethod (which exists in Thing1 and Thing2)?
Any advice is appreciated.
You need your Thing classes to implement a common interface such as
public interface Thing {
public String myMethod();
}
public class Thing1 implements Thing {
...
}
If they don't have a common supertype, then the two myMethod methods are unrelated. The fact that they have the same name is irrelevant to Java; they're distinct methods defined in distinct classes. You can access them with reflection shenanigans, but then you're giving up a lot of type safety (at that point, you would just take an Object and trust the user to provide a value of the correct type; it's ugly and messy and I don't recommend it).
If the classes in question are third-party classes (i.e. that you don't control) and don't implement a common interface, then you need the adapter pattern. Basically, you define a new class that does implement the interface and wraps an instance of the original.
public class Thing1Adapter implements Thing {
private Thing1 impl;
public Thing1Adapter(Thing1 impl) {
this.impl = impl;
}
#Override
public String myMethod() {
return this.impl.myMethod();
}
}
...
DoThis(new Thing1Adapter(myThing1));

How would one pass an interface as a generic type and use it as an annotation?

Let's say I've got an annotation interface of foo
#interface foo {
String bar();
}
I want to be able to pass foo to a generic T in a class, let's call it someClass
class someClass<T> {
T ourAnnotation = getClass().getAnnotation(T); // this won't work
}
The reason I'd pass this is that later on, when creating a base class, we can pass this generic
#foo(bar = ...)
public class MyClass extends someClass<foo> {
public MyClass() {
ourAnnotation.bar // ... do stuff
}
}
How would I be able to pass this?
Edit: I've figured out a solution
Within someClass, I've made the following modifications:
class someClass<T> {
final T info;
public someClass(Class<T> tClass) {
info = getClass().getAnnotation(tClass);
}
}
Then, by passing foo (make sure it's retention policy is set to runtime), you can easily grab the values from MyClass.
Within someClass, I've made the following modifications:
class someClass<T> {
final T info;
public someClass(Class<T> tClass) {
info = getClass().getAnnotation(tClass);
}
}
Then, by passing foo (make sure it's retention policy is set to runtime), you can easily grab the values from MyClass.
This allows gson to find the values

Can individual values of an enum implement an interface

An enum can implement an interface. Is it possible for some of the values to implement an interface? The use case that I am thinking of is a tagging interface, so something like the following:
interface Foo {}
interface Bar {}
enum Widgets {
FOO implements Foo,
BAR_1 implements Bar,
BAR_2 implements Bar
}
That does not compile under Java 1.8. I know that internally, there are separate classes created for FOO and BAR_1, so it seems this is possible, but I can easily see the standard not supporting it.
Something similar that should work is
interface Widgets;
enum Foo implements Widgets { FOO };
enum Bar implements Widgets { BAR_1, BAR_2 };
This has the drawback that I cannot just do Widgets.values() and get all of the Widgets.
The Java Language Specification states
The optional class body of an enum constant implicitly defines an
anonymous class declaration (§15.9.5) that extends the immediately
enclosing enum type. The class body is governed by the usual rules of
anonymous classes; in particular it cannot contain any constructors.
Instance methods declared in these class bodies may be invoked outside
the enclosing enum type only if they override accessible methods in
the enclosing enum type (§8.4.8).
An anonymous class can only extend (or implement) the type specified in the new instance creation expression, your enum type in this case. As such, you can't have it additionally implement an interface.
The following
enum Foo {
CONSTANT
}
gets compiled to something similar to
class Foo extends Enum<Foo> {
private Foo() {/* calling Enum superconstructor */}
public static final Foo CONSTANT = new Foo();
}
If you wanted the constant to have a body (to override or declare some methods)
enum Foo {
CONSTANT {
public String toString() {
return name().toUpperCase();
}
}
}
becomes something like
class Foo extends Enum<Foo> {
private Foo() {/* calling Enum superconstructor */}
public static final Foo CONSTANT = new Foo() { // no way to express an additional interface
public String toString() {
return name().toUpperCase();
}
};
}
The enum values are not classes but instances, so they cannot implement an interface.
However, if what you want is just a way to "tag" your values, you can use a field:
enum Widgets {
FOO(true, false),
BAR_1(false, true),
BAR_2(false, true),
BOTH(true, true);
private final boolean isFoo;
private final boolean isBar;
Widgets(boolean isFoo, boolean isBar) {
this.isFoo = isFoo;
this.isBar = isBar;
}
public boolean foo() {
return isFoo;
}
public boolean bar() {
return isBar;
}
}
In that example, you will be able to enumerate your values with Widgets.values() and to know if each value is tagged "foo", "bar" or both.
An other method to "tag" you values can be:
enum Tag {
FOO,
BAR;
}
enum Widgets {
FOO(Tag.FOO),
BAR_1(Tag.BAR),
BAR_2(Tag.BAR),
BOTH(Tag.FOO, Tag.BAR);
private Tag[] tags;
Widgets(Tag... tags) {
this.tags = tags;
}
public Tag[] getTags() {
return tags;
}
}

Static Factories Methods

One advantage of static factories method states that:
Unlike constructors they can return an object of any subtype of their return type which gives you great flexibility in choosing the class of returned object.
What does this mean exactly?
Can someone explain this with code?
public class Foo {
public Foo() {
// If this is called by someone saying "new Foo()", I must be a Foo.
}
}
public class Bar extends Foo {
public Bar() {
// If this is called by someone saying "new Bar()", I must be a Bar.
}
}
public class FooFactory {
public static Foo buildAFoo() {
// This method can return either a Foo, a Bar,
// or anything else that extends Foo.
}
}
Let me break your question in two parts
(1) Unlike constructors they can return an object of any subtype of their return type (2) which gives you great flexibility in choosing the class of returned object.Let say You have two classes Extended from Player which are PlayerWithBall and PlayerWithoutBall
public class Player{
public Player(boolean withOrWithout){
//...
}
}
//...
// What exactly does this mean?
Player player = new Player(true);
// You should look the documentation to be sure.
// Even if you remember that the boolean has something to do with a Ball
// you might not remember whether it specified withBall or withoutBall.
to
public class PlayerFactory{
public static Player createWithBall(){
//...
}
public static Player createWithoutBall(){
//...
}
}
// ...
//Now its on your desire , what you want :)
Foo foo = Foo.createWithBall(); //or createWithoutBall();
Here you get the both answers Flexability and unlike constructor behaviour
Now You can see through these factory methods its upto you that WHICH TYPE OF PLAYER YOU NEED

How to use AOP to intercept a method call in super on an argument?

I'm extending a class and overriding a method. All I want to do is to call super, but with a modified argument that gets intercepted upon one of its methods is called. An example makes it more clear:
// Foo is an interface and also this method is part of an interface
#Override
public void foo(Foo foo) {
// I want to intercept the call to foo.bar() in super
super.foo(foo);
}
I'd rather use a tool that doesn't require a compiler of its own. What would be the optimal one?
Given that Foo is an interface, you might consider using a dynamic proxy that would:
Wrap the original foo
Intercept all message and forward them to the original foo
There is a complete example in the above link. Here is just the idea:
public class DebugProxy implements java.lang.reflect.InvocationHandler {
private Object obj;
private DebugProxy(Object obj) {
this.obj = obj;
}
public Object invoke(Object proxy, Method m, Object[] args) throws Throwable
{
System.out.println("before method " + m.getName());
return m.invoke(obj, args);
}
}
Foo original = ... ;
Foo wrapper = (Foo) java.lang.reflect.Proxy.newProxyInstance(
original.getClass().getClassLoader(),
original.getClass().getInterfaces(),
new DebugProxy(original));
wrapper.bar(...);
Note that if Foo was not an interface, you could still subclass Foo and override all methods manually so as to forward them.
class SubFoo extends Foo
{
Foo target;
SubFoo( Foo target ) { this.target = target };
public void method1() { target.method1(); }
...
}
It's pseudo-code, and I haven't tested it. In both cases, the wrapper allows you to intercept a call in super.
Of course, the wrapper has not the same class as the original Foo, so if super uses
reflection
instanceof
or access instance variables directly (not going through getter/setter)
, then it might be problematic.
Hope that I understood your problem right and that it helps.

Categories

Resources