Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Create new instance class reference

Tags:

java

java-8

I have an Enum like this:

public static enum TestEnum {
    // main
    ENUM_A  (1, "test1", TestADto.class),
    ENUM_B  (2, "test2", TestBDto.class),
    ENUM_C  (3, "test3", TestCDto.class),
    ...

    private Class<? extends Dto> dtoClass;

    public Class<? extends Dto getDtoClass() {
        return dtoClass;
    }

    ...
}

All of these dto classes extend the same abstract (dto) class:

public abstract class AbstractDto {

    private String foo;

    private int bar;

    ...

    AbstractDto(AbstractClassNeededForInitialization o) {
        this.foo = o.getFoo();
        this.bar = o.getBar();
    }

    ... some functions here ...
}

This would a example Dto implementation of TestADto:

@Getter
@Setter
public class TestADto extends AbstractDto {

    private String anotherFoo;

    private int anotherBar;

    ...

    public TestADto(AbstractClassNeededForInitialization o) {
        super(o);
    }

    ... some functions here ...
}

Is it possible (im using Java 8) create a concrete instance of these in the enum reference classes without the need of knowing which concrete istance it is?

Lets say im at a certain point in a function and im having the Enum_A. Now i want to create a dto instance (TestADto.class). What would be the best approach or pattern for this?

Imagine a enum with more than 100 entries and every entry has a different dto which extends the same abstract dto or implements a interface.

How can i create these concrete object without writing a huge if else or switch statement or handle it case by case.

I read something about reflection and proxies but not sure if this is the right way i am. Or is the current state im having already a kind of poor design? Everything i want to reach is to assign the dto name to an enum for creating it later at some certain points. But without creating a huge condition if possible...

@Edit

I forgot to mention that creating a instance of each dto needs to have object which is passed to the constructor. This object which is passed to the constructor also implements a interface.

like image 344
StephanM Avatar asked Aug 16 '17 13:08

StephanM


3 Answers

If you need to invoke an empty constructor for your DTO subclasses, you could provide a Supplier in the enum constructor that you store in a field :

...
ENUM_A  (1, "test1", TestADto::new),
ENUM_B  (2, "test2", TestBDto::new),
ENUM_C  (3, "test3", TestCDto::new);

private Supplier<Dto> supplierDto;

TestEnum(int i, String name, Supplier<Dto> supplierDTO){
    this.supplierDto = supplierDTO;
    ...
}
...

Then you can create the Dto instance by invoking supplierDto.get();


After your edit :

I forgot to mention that creating a instance of each dto needs to have object which is passed to the constructor.

A Supplier<Dto> doesn't suit any longer as it is not designed to be used with a constructor that presents one parameter.

By Supposing that your constructors are like that :

public class TestADto{
    ...
   private MyInterface myInterface;

   public TestADto (MyInterface myInterface){
       this.myInterface = myInterface;
   }
    ...    
}

You could so declare in the enum constructor a Function <MyInterface, Dto> parameter to match to this constructor.

...
ENUM_A  (1, "test1", TestADto::new),
ENUM_B  (2, "test2", TestBDto::new),
ENUM_C  (3, "test3", TestCDto::new);

private Function <MyInterface, Dto> dtoConstructor;

TestEnum(int i, String name, Function <MyInterface, Dto> dtoConstructor){
    this.dtoConstructor = dtoConstructor;
    ...
}

public Dto createInstance(MyInterface myInterface){
    return myInterfaceToDtoFunction.apply(myInterface);
}

...
like image 150
davidxxx Avatar answered Oct 20 '22 00:10

davidxxx


David was almost there, but you said the constructor requires a parameter, so I'd do this. For the purposes of this example, I've assumed your constructors take a String:

ENUM_A  (1, "test1", TestADto::new),
ENUM_B  (2, "test2", TestBDto::new),
ENUM_C  (3, "test3", TestCDto::new);

private final Function<String, Foo> constructor;

TestEnum(int i, String name, Function<String, Foo> constructor){
    this.constructor = constructor;
}

public Dto getInstance(final String argument)
{
    return constructor.apply(argument);
}
like image 7
Michael Avatar answered Oct 20 '22 01:10

Michael


The easiest way is to use reflection on the Class object returned by the getDtoClass() method of the TestEnum instance you got in hand. The method Class#newInstance() will create an instance of any class object you have.

This solution makes the assumption that there is a zero argument constructor visible in all the classes you'd reference in the enum - thanks to @Michael for pointing that out. If this is not the case, you can still use reflection but might want to check out the Constructor accessor class, which offers more powerful access to all the constructors in a class. This nice tutorial explains the advantages of Constructor in more detail.

Using reflection when needed also has the distinct advantage of being inherently lazy. The instance will only be created when needed, as opposed to instanciating all classes when initializing the enum class.

like image 1
hiergiltdiestfu Avatar answered Oct 20 '22 01:10

hiergiltdiestfu