Create an instance of a class based on another class

In Java, I have a class X and an interface Y , and then a set of classes A1 .. And we extend X and implement Y Then I create a wrapper / adapter for each of the A1..An classes (i.e. A1'..An' ).

Now, in the client class C , I get a list of instances of the Y interface ( ArrayList < Y > ).

At this point, for each instance in the list, I want to create a new instance of the class Ax' (from A1'..An' ) based on which instance of Y is in the list. For A1 do A1' , etc.

My doubt is how I can achieve this without if .. else if ... and (instance) build. Can I use inheritance here somehow?

I tested some design patterns, but I could not find a solution on how to create classes based on which instance these other classes are.

Any help and recommendations would be appreciated. Thank you

+4
source share
6 answers
 for(Y y : ArrayList < Y >) { y.getClass().newInstance(); } 

if I understand your question correctly ...

EDIT

 abstract class X implements Y { Y getInstance(); } class A1 extends X { void someMethod() { getInstance(); // return instance of A1_ } } class A1_ extends A1 { Y getInstance() { return new A1_(); } } 

EDIT2

If you want to get the parent instance in the child, you can do

 this.getClass().getSuperclass().newInstance(); 
+2
source

You can use the Class.forName() method to create a wrapper. The mapping between the A1..AN class and the shell class name can be stored either hardcoded, either in the properties or in an XML file, or if you want to use the annotation placed in the A1 ... AN classes.

+1
source
 for(Y y : ArrayList < Y >) { Class<?> clazz = Class.forName(y.getClass().getName()+"Adapter"); YAdapter ya = (YAdapter)clazz.newInstance(); } 

Mixing both answers.

+1
source

Create a HashMap<Class<Y>, Class<?>> . For each An and A'n, create a relationship: map.put(An.class, A'n.class) .

Then, for each obj in the ArrayList, get A 'class: Class aa=map.get(obj.getClass()) . Then create an instance of the aa class either using aa.newInstance() (and then pass obj via setter) or using the constructor using reflection (and pass obj as a parameter).

+1
source

First, you need a way to associate adapters (A ' 1 .. A' n ) with specific instances (A 1 .. A n ). This is best done using Map<Class<?>, Constructor<?>> . A good way would be to create a registry around it:

 public class AdapterRegistry { private static final Map<Class<?>, Constructor<?>> adapterMap = new HashMap<Class<?>, Constructor<?>>(); public static void register(Class<?> interfaceClass, Class<?> concreteClass, Class<?> adapterClass) throws NoSuchMethodException { // Check for the constructor Constructor<?> constructor = adapterClass.getConstructor(interfaceClass); adapterMap.put(concreteClass, constructor); } public static <T, V extends T> T wrap(V v) { Class<?> concreteClass = v.getClass(); try { Constructor<?> constructor = adapterMap.get(concreteClass); if (constructor != null) { return (T) constructor.newInstance(v); } } catch (Exception ex) { // TODO Log me } return null; } } 

Then it's just a matter of creating adapters:

 public class Adapter implements Y { private Y innerY; public Adapter(Y innerY) { this.innerY = innerY; } // Implement Y } 

And register your adapter (s):

 AdapterRegistry.register(Y.class, A1.class, Adapter1.class); AdapterRegistry.register(Y.class, A2.class, Adapter1.class); AdapterRegistry.register(Y.class, A3.class, Adapter2.class); // ... AdapterRegistry.register(An.class, AdapterM.class); 

Notice how you can register multiple adapters for the same class if you want. That way, if a subset of specific classes will be handled the same way, you just need to register the same adapter for all of them.

Next, get a shell:

 for (Y y : yList) { Y adapter = AdapterRegistry.wrap(y); // Do something with the adapter } 

This has certain limitations:

  • You must have a constructor in each adapter that accepts a specific object on its interface.
  • There should be methods in the interface that you want to change (if you use Y as the type for innerY , you can change this so that you have access to non-interface methods, but then you need to do the casting).

Then you can also use your AdapterRegistry in other parts of your program due to the use of generics.

Let me know if there is a problem with the code and you cannot figure it out.

+1
source

One standard solution that should be avoided if / else-chains in such situations is to force classes to implement some interface that contains a method that makes objects know what to do themselves - for example, use inheritance, as you suggest.

Concrete classes know their specific types, how to copy themselves, etc., but you don’t know what is in the loop - so it makes sense to shift the responsibility for creating new concrete classes directly to specific classes.

What I would do is add a new method to the Y interface, which creates a new instance. For example, if you just want to take a copy of the instances in the list, you can add β€œcopy” factory -method to Y :

 public interface Y { ... public Y copy(); ... } 

Each implementation of Y must implement a copy method. He knows how to copy himself. Example:

 public class MyClass implements Y { ... public MyClass copy() { return new MyClass(...); } ... } 

Thus, creating new instances when repeated in the list then simply becomes something like this:

 List<Y> ys = ...get list from somewhere...; for (Y y : ys) { Y copy = y.copy(); ... } 

Please note that there is no reflection or other hacks needed for this approach.

Also note that the loop should not know anything about specific classes - it should only know the Y interface. All code specific to specific classes is stored inside the classes themselves. This simplifies code usage (avoids instanceof + if / else chains).

Instead of the copy method, you could of course also create more complex methods, perhaps by taking some parameters. This can be useful if the objects do not just need to copy themselves, but must themselves create a new instance in some special way based on some input.

(Note: This copy method may remind you of a β€œclone,” but since Java cloning is severely broken, this is usually the best approach).

Note. I assumed that both wrappers Ai' and Ai extend Y

Note. If you cannot make changes to Y , but you can change adapter classes, you can create a new interface Y' that extends Y and which adapter classes implement it, and use List<Y'> instead of List<Y> , which you iterate over channels.

+1
source

Source: https://habr.com/ru/post/1435328/


All Articles