I want to call the constructor of the class that uses the method, for example:
if I have two classes B and C such that I have the same method foo
in them like so:
(And they both implement SomeInterface
)
interface SomeInterface {
public SomeInterface foo();
}
class B implements SomeInterface {
public B(int fst, int snd) {}
@Override
public SomeInterface foo() {
return new B(1, 1);
}
}
class C implements SomeInterface {
public C(int fst, int snd) {}
@Override
public SomeInterface foo() {
return new C(1, 1);
}
}
And let's say for the sake of this question that I have a lot more classes that implement SomeInterface
and they all do the same thing, that is return new <nameoftheclass>(1,1)
and all these classes extend a parent class A
. Is there a way for me to create only one method in A
such that if any of these classes use the foo
method that is found in A
it will call their constructor and just like that save me lines of code?
I hope I explained my question well, Any help will be greatly appreciated.
CodePudding user response:
You can do something like this with reflection, although it will be prone to failure.
public SomeInterface foo() {
Constructor<? extends SomeInterface> c = getClass().getConstructor(int.class, int.class);
return c.newInstance( 1, 1);
}
You'll have to manage some exceptions, but is this what you're after?
The question would then be, where can this be used? Interfaces don't have a common constructor.
public interface SomeInterface{
default SomeInterface another(){
Constructor<? extends SomeInterface> c = getClass().getConstructor(int.class, int.class);
return c.newInstance( 1, 1);
}
}
That would work provided whatever the implementations try to use it have that constructor. There is no guarantee that constructor exists though. Maybe you would want it on an abstract class?
CodePudding user response:
use the foo method that is found in A it will call their constructor and just like that save me lines of code?
You are getting it wrong. Class design decisions must be based on use cases and relationships of the classes in your domain. If your main criteria will be to spare some lines of code, you can end up with a coffee machine extending combine harvester because both of them have tree dimensions. Don't take a pill if you have no headache.
As an example of the "template" you've provided might be useful, will be a situation when classes with similar functionality need to grouped together.
The interface can serve as a single entry point for the user of the code. Every class will implement the behavior defined by the interface, and only through the interface it'll be possible to get an instance of the class with a particular flavor of functionality. The actual classes will be hidden from the user.
Similarly, abstract class NumberFormat
from the JDK provides a way to obtain different kinds of formatters, but actual implementations are hidden are not exposed (the approach shown below is far more simple than the actual way of how factory methods of the NumberFormat
are implemented).
Note, interface and its implementations must reside in the same package.
public interface BaseInterface {
public static BaseInterface getInstance(Classifier classifier) { // factory
return switch(classifier) {
case A -> new A();
case B -> new B();
};
}
void doSomeThingUseful(); // behaviour that every class should implement
}
enum Classifier { A, B }
class A implements BaseInterface {
A() {}
@Override
public void doSomeThingUseful() {
System.out.println("Class A");
}
}
class B implements BaseInterface {
B() {}
@Override
public void doSomeThingUseful() {
System.out.println("Class B");
}
}
main()
- demo
public static void main(String[] args) {
List<BaseInterface> items = List.of(BaseInterface.getInstance(Classifier.A),
BaseInterface.getInstance(Classifier.B));
for (BaseInterface item: items) {
item.doSomeThingUseful();
}
}
Output
Class A
Class B