Home > Software design >  Call the constructor of the class that uses the method
Call the constructor of the class that uses the method

Time:04-15

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
  • Related