I want to do a factory pattern in java with generics. My code is:
The interface:
public abstract class Factory<T> {
public abstract T create();
}
FactoryA class:
public class FactoryA extends Factory<FactoryA> {
public FactoryA() {
}
public FactoryA create() {
return new FactoryA();
}
}
FactoryB class:
public class FactoryB extends Factory<FactoryB> {
public FactoryB() {
}
public FactoryB create() {
return new FactoryB();
}
}
The main class:
public class FactoryCreator {
public static <T> T createFactory() {
Factory<T> t = ?; // is that right way?
return t.create();
}
public static void main(String[] args) {
FactoryA factoryA = FactoryCreator.createFactory();
FactoryB factoryB = FactoryCreator.createFactory();
}
}
The question, what Factory t = need to be equal, or is there any other way?
Not really sure what you're trying to achieve, but this might help;
public interface Factory<T>
{
public T create(String type);
public T create(String type, Object arg);
public T create(String type, Object[] args);
}
And then have a class implement that factory interface, like this;
public class TemplateFactory<T> implements Factory {
#Override
public T create(String type) throws IllegalArgumentException
{
return create(type, null);
}
#Override
public T create(String type, Object arg) throws IllegalArgumentException
{
// Convert to array of 1 element
Object[] arguments = new Object[1];
arguments[0] = arg;
return create(type, arguments);
}
#Override
public T create(String type, Object[] args) throws IllegalArgumentException
{
// Create array for all the parameters
Class<?> params[] = (args != null) ? new Class<?>[args.length] : new Class<?>[0];
if(args != null)
{
// Adding the types of the arguments
for(int i = 0; i < args.length; ++i)
params[i] = (args[i] != null) ? args[i].getClass() : null;
}
try
{
// Create a class variable
Class classLoader = Class.forName(type);
// Find the right constructor
Constructor co;
if(params.length > 0)
co = classLoader.getConstructor(params);
else
co = classLoader.getConstructor();
// Instantiate the class with the given arguments
T newObject = (T)co.newInstance(args);
return newObject;
}
catch(Exception e)
{
throw new IllegalArgumentException(e.toString());
}
}
}
And then use it like this (using some imaginary strategy-classes as an example):
TemplateFactory<StrategyInterface> factory;
factory = new TemplateFactory<>();
factory.create("packageName.StrategyA");
factory.create("packageName.StrategyB");
factory.create("packageName.StrategyC");
The strategy classes (A, B and C) would implement the StrategyInterface-class in this example.
Something like this might work:
public static <T extends Factory> T createFactory(Class<T> clazz) {
try {
t = clazz.newInstance();
return t.create();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
return null;
}
}
...
FactoryA factoryA = FactoryCreator.createFactory(FactoryA.class);
alternatively, without parameters. But then you need two methods.
public static FactoryA createFactoryA() {
return new FactoryA().create();
}
...
FactoryA factoryA = FactoryCreator.createFactoryA();
Since the Generic types are erased at runtime you have to supply the Class parameter so that the runtime knows what class you are talking about.
Related
I am writing a java (processing) library for unexperienced students, and am looking for the best architecture for implementing it.
Initialization of an object should be as close as possible to this:
myObject = new General("type1");
Such that myObject will become an instance of Type1 which extends General:
class General {
public General() {}
}
class Type1 extends General {
public Type1() {}
}
class Type2 extends General {
public Type1() {}
}
As far as I know, this isn't possible (choosing between extended classes during initialization), but I'm looking for the closest solution possible.
So far, my best solution is to make a static initializer inside General:
class General {
...
static General init (String type) {
General temp;
if (type.equals("type1") {
temp = new Type1();
}
...
return temp;
}
and the initialization is:
General myObject;
myObject = General.init("type1");
This is far from ideal...
thanks.
you can make a factory class that manages initialization.
instead of doing it inside the parent.
// Empty vocabulary of actual object
public interface IPerson
{
string GetName();
}
public class Villager : IPerson
{
public string GetName()
{
return "Village Person";
}
}
public class CityPerson : IPerson
{
public string GetName()
{
return "City Person";
}
}
public enum PersonType
{
Rural,
Urban
}
/// <summary>
/// Implementation of Factory - Used to create objects.
/// </summary>
public class Factory
{
public IPerson GetPerson(PersonType type)
{
switch (type)
{
case PersonType.Rural:
return new Villager();
case PersonType.Urban:
return new CityPerson();
default:
throw new NotSupportedException();
}
}
}
The State design pattern can be a solution here. Rather than the constructor argument changing the type of the object (which isn't possible) it can set a field of the object, to make it behave as if its type is different.
package stackoverflow.questions;
public class Main {
private interface MyInterface {
String foo();
int bar();
}
private static class Type1 implements MyInterface {
#Override public String foo() { return "lorem ipsum "; }
#Override public int bar() { return 6; }
}
private static class Type2 implements MyInterface {
#Override public String foo() { return "dolor sit amet"; }
#Override public int bar() { return 7; }
}
public static class General {
private final MyInterface type;
public General(String type) {
try {
this.type = (MyInterface) Class
.forName("stackoverflow.questions.Main$" + type)
.getDeclaredConstructor().newInstance();
} catch (Exception e) {
throw new IllegalArgumentException("Invalid type: " + type);
}
}
public String method1() { return type.foo(); }
public int method2() { return type.bar(); }
}
public static void main(String... args) {
General one = new General("Type1");
General two = new General("Type2");
System.out.println(one.method1() + two.method1());
System.out.println(one.method2() * two.method2());
}
}
I have some generated code (i.e. it cannot be changed) that looks something like this.
class Generated1 {
public String getA() {
return "1";
}
public void setB(String b) {
}
public void setC(String c) {
}
public void setD(String d) {
}
}
class Generated2 {
public String getA() {
return "2";
}
public void setB(String b) {
}
public void setC(String c) {
}
public void setD(String d) {
}
}
I am exploring these objects by reflection. None of them implement any common interface but there's many of them and I want to treat them as if they implement:
interface CommonInterface {
String getA();
void setB(String b);
void setC(String c);
void setD(String d);
}
It certainly should be possible. This is considered perfectly good code
class CommonInterface1 extends Generated1 implements CommonInterface {
// These are perfectly good classes.
}
class CommonInterface2 extends Generated2 implements CommonInterface {
// These are perfectly good classes.
}
I suppose what I'm looking for is something like:
private void doCommon(CommonInterface c) {
String a = c.getA();
c.setB(a);
c.setC(a);
c.setD(a);
}
private void test() {
// Simulate getting by reflection.
List<Object> objects = Arrays.asList(new Generated1(), new Generated2());
for (Object object : objects) {
// What is the simplest way to call `doCommon` with object here?
doCommon(object);
}
}
My question: How do I treat an object that doesn't implement an interface but actually has all the code to do so as if it does implement the interface.
I want to replace
private void doCommon(Generated1 c) {
String a = c.getA();
c.setB(a);
c.setC(a);
c.setD(a);
}
private void doCommon(Generated2 c) {
String a = c.getA();
c.setB(a);
c.setC(a);
c.setD(a);
}
...
with
private void doCommon(CommonInterface c) {
String a = c.getA();
c.setB(a);
c.setC(a);
c.setD(a);
}
I know I can use a Proxy like this but I'd really prefer to use something better.
private void test() {
// Simulate getting by reflection.
List<Object> objects = Arrays.asList(new Generated1(), new Generated2());
for (Object object : objects) {
// What is the simplest way to call `doCommon` with object here?
doCommon(adapt(object));
}
}
private CommonInterface adapt(Object o) {
return adapt(o, CommonInterface.class);
}
public static <T> T adapt(final Object adaptee,
final Class<T>... interfaceToImplement) {
return (T) Proxy.newProxyInstance(
adaptee.getClass().getClassLoader(),
interfaceToImplement,
// Call the equivalent method from the adaptee.
(proxy, method, args) -> adaptee.getClass()
.getMethod(method.getName(), method.getParameterTypes())
.invoke(adaptee, args));
}
If you're using reflection, you don't need the two CommonInterfaceX classes, you can use a proxy implementing CommonInterface:
public class Wrapper implements InvocationHandler {
private final Object delegate;
public static <T> T wrap(Object obj, Class<T> intf) {
ClassLoader cl = Thread.currentThread().getContextClassLoader();
Object proxy = Proxy.newProxyInstance(cl, new Class<?>[] {intf},
new Wrapper(obj));
return intf.cast(proxy);
}
private Wrapper(Object delegate) {
this.delegate = delegate;
}
#Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
Method dmethod = delegate.getClass().getMethod(
method.getName(), method.getParameterTypes());
return dmethod.invoke(delegate, args);
}
}
You can use this class as follows:
List<Object> objects = Arrays.asList(new Generated1(), new Generated2());
for (Object object : objects) {
CommonInterface proxy = Wrapper.wrap(object, CommonInterface.class);
doCommon(proxy);
}
UPDATE: note that the same Wrapper class works with any interface.
There's no way to achieve a static type relationship between Generated1 and Generated2.
Even if you created CommonInterface1 and CommonInterface2, you still wouldn't be able to statically use a Generated1 object as a CommonInterface1 because new Generated1() is not a CommonInterface1 (and will never become one)
By far the simplest solution is to change your code generation to add the CommonInterface to Generated1 and Generated2.
If that's absolutely impossible, the only other way to avoid this code duplication is to go for reflection.
You can do it manuallly by reflection.
public class Generated {
public String getA() {
return "A";
}
public String sayHello(String name) {
return "hello " + name;
}
}
public class Helper {
private static final String METHOD_NAME = "getA";
private static final String METHOD_WITH_PARAM_NAME = "sayHello";
public static void main(String[] args) throws Exception {
Generated generated = new Generated();
accessMethod(generated);
accessMethodWithParameter(generated);
}
private static void accessMethod(Generated g) throws Exception {
Method[] methods = g.getClass().getDeclaredMethods();
for(Method method : methods) {
if(isCommonMethod(method)) {
String result = (String) method.invoke(g);
System.out.println(METHOD_NAME + "() = " + result);
}
}
}
private static boolean isCommonMethod(Method m) {
return m.getName().equals(METHOD_NAME) && m.getReturnType().equals(String.class);
}
private static void accessMethodWithParameter(Generated g) throws Exception {
Method[] methods = g.getClass().getDeclaredMethods();
for(Method method : methods) {
if(isCommonMethodWithParameter(method)) {
String result = (String) method.invoke(g, "Max");
System.out.println(METHOD_WITH_PARAM_NAME + "(\"Max\") = " + result);
}
}
}
private static boolean isCommonMethodWithParameter(Method m) {
return m.getName().equals(METHOD_WITH_PARAM_NAME) &&
m.getReturnType().equals(String.class) &&
m.getParameterTypes().length == 1 &&
m.getParameterTypes()[0].equals(String.class);
}
}
Output is
getA() = A
sayHello("Max") = hello Max
If you want to replace as your comment. I think you can do it easily
First, you create interface CommonInterface
interface CommonInterface {
String getA();
void setB(String b);
void setC(String c);
void setD(String d);
}
After that, you create 2 class Generated1 and Generated2 inherited CommonInterface
class Generated1 implements CommonInterface {
#overide
public String getA() {
return "1";
}
#overide
public void setB(String b) {
}
#overide
public void setC(String c) {
}
#overide
public void setD(String d) {
}
}
class Generated2 implements CommonInterface {
#overide
public String getA() {
return "2";
}
#overide
public void setB(String b) {
}
#overide
public void setC(String c) {
}
#overide
public void setD(String d) {
}
}
I have a generic interface Handler
public interface Handler<T> {
void handle(T obj);
}
I can have n implementations of this interface. Let's say I have following 2 implementations for now. One which handles String objects and another handles Date
public class StringHandler implements Handler<String> {
#Override
public void handle(String str) {
System.out.println(str);
}
}
public class DateHandler implements Handler<Date> {
#Override
public void handle(Date date) {
System.out.println(date);
}
}
I want to write a factory which will return handler instances based on the class type. Something like this :
class HandlerFactory {
public <T> Handler<T> getHandler(Class<T> clazz) {
if (clazz == String.class) return new StringHandler();
if (clazz == Date.class) return new DateHandler();
}
}
I get following error in this factory :
Type mismatch: cannot convert from StringHandler to Handler<T>
How to fix this?
SIMPLE SOLUTION
You could save your mappings Class<T> -> Handler<T> in a Map. Something like:
Map<Class<T>, Handler<T>> registry = new HashMap<>();
public void registerHandler(Class<T> dataType, Class<? extends Handler> handlerType) {
registry.put(dataType, handlerType);
}
public <T> Handler<T> getHandler(Class<T> clazz) {
return registry.get(clazz).newInstance();
}
In some place, initialize handlers (could be in the factory itself):
factory.registerHandler(String.class, StringHandler.class);
factory.registerHandler(Date.class, DateHandler.class);
And in another place, you create and use them:
Handler<String> stringhandler = factory.getHandler(String.class);
Handler<Date> dateHandler = factory.getHandler(Date.class);
MORE COMPLEX SOLUTION
You can "scan" classes using reflection and, instead of register manually the mappings Class<T> -> Handler<T>, do it using reflection.
for (Class<? extends Handler> handlerType : getHandlerClasses()) {
Type[] implementedInterfaces = handlerType.getGenericInterfaces();
ParameterizedType eventHandlerInterface = (ParameterizedType) implementedInterfaces[0];
Type[] types = eventHandlerInterface.getActualTypeArguments();
Class dataType = (Class) types[0]; // <--String or Date, in your case
factory.registerHandler(dataType, handlerType);
}
Then, you create and use them like above:
Handler<String> stringhandler = factory.getHandler(String.class);
Handler<Date> dateHandler = factory.getHandler(Date.class);
To implement getHandlerClasses(), look at this to scan all classes in your jar. For each class, you have to check if it is a Handler:
if (Handler.class.isAssignableFrom(scanningClazz) //implements Handler
&& scanningClazz.getName() != Handler.class.getName()) //it is not Handler.class itself
{
//is a handler!
}
Hope it helps!
Your problem is that the compiler cannot make the leap to the fact thet the type of the result is correct.
To help the compiler you can make the factory delegate the construction. Although this looks strange and unwieldly it does manage to properly maintain type safety without sacrifices such as casting or using ? or raw types.
public interface Handler<T> {
void handle(T obj);
}
public static class StringHandler implements Handler<String> {
#Override
public void handle(String str) {
System.out.println(str);
}
}
public static class DateHandler implements Handler<Date> {
#Override
public void handle(Date date) {
System.out.println(date);
}
}
static class HandlerFactory {
enum ValidHandler {
String {
#Override
Handler<String> make() {
return new StringHandler();
}
},
Date {
#Override
Handler<Date> make() {
return new DateHandler();
}
};
abstract <T> Handler<T> make();
}
public <T> Handler<T> getHandler(Class<T> clazz) {
if (clazz == String.class) {
return ValidHandler.String.make();
}
if (clazz == Date.class) {
return ValidHandler.Date.make();
}
return null;
}
}
public void test() {
HandlerFactory factory = new HandlerFactory();
Handler<String> stringHandler = factory.getHandler(String.class);
Handler<Date> dateHandler = factory.getHandler(Date.class);
}
The whole point of using a generic type is to share the implementation. If the n implementation of your Handler interface are so different that they can't be shared, then I don't think there is any reason to use define that generic interface at the first place. You'd rather just have StringHandler and DateHandler as top level classes.
On the other hand, if the implementation can be shared, as is the case of your example, then the factory works naturally:
public class Main {
static public interface Handler<T> {
void handle(T obj);
}
static public class PrintHandler<T> implements Handler<T> {
#Override
public void handle(T obj) {
System.out.println(obj);
}
}
static class HandlerFactory {
public static <T> Handler<T> getHandler() {
return new PrintHandler<T>();
}
}
public static void main(String[] args) {
Handler<String> stringHandler = HandlerFactory.getHandler();
Handler<Date> dateHandler = HandlerFactory.getHandler();
stringHandler.handle("TEST");
dateHandler.handle(new Date());
}
}
You can use something like:
class HandlerFactory {
public <T> Handler<T> getHandler(Class<T> clazz) {
if (clazz.equals(String.class)) return (Handler<T>) new StringHandler();
if (clazz.equals(Date.class)) return (Handler<T>) new DateHandler();
return null;
}
}
T is generic and the compiler can't map that at compile time. Also it is safer to use .equals instead of ==.
Define an interface for creating an object, but let subclasses decide which class to instantiate.
Factory method lets a class defer instantiation to subclasses.
Define generic abstract class
public abstract class Factory<T> {
public abstract T instantiate(Supplier<? extends T> supplier);
}
And a generic supplier
public class SupplierFactory<T> extends Factory<T> {
#Override
public T instantiate(Supplier<? extends T> supplier) {
return supplier.get();
}
}
Then an implementation needs to have concrete classes to implement the base interface and a main class to show class defer instantiation . i.e
The base interface (desired interface of the requirement)
public interface BaseInterface {
void doAction();
}
The first concrete class
public class Alpha implements BaseInterface {
#Override
public void doAction() {
System.out.println("The Alpha executed");
}
}
And the second one
public class Beta implements BaseInterface {
#Override
public void doAction() {
System.out.println("The Beta executed");
}
}
The main
public class Main {
public static void main(String[] args) {
Factory<BaseInterface> secondFactory = new SupplierFactory<>();
secondFactory.instantiate(Beta::new).doAction();
secondFactory.instantiate(Alpha::new).doAction();
}
}
Basically you can do:
public Handler getHandler( Class clazz ){
if( clazz == String.class ) return new StringHandler();
if( clazz == Date.class ) return new DateHandler();
return null;
}
public static void main( String[] args ){
HandlerFactory handlerFactory = new HandlerFactory();
StringHandler handler = ( StringHandler )handlerFactory.getHandler( String.class );
handler.handle( "TEST" );
DateHandler handler2 = ( DateHandler )handlerFactory.getHandler( Date.class );
handler2.handle( new Date() );
}
Output:
TEST
Tue Dec 15 15:31:00 CET 2015
But instead writing two different methods to get handlers separately always is a better way.
I edited your code and allowed Eclipse to "fix" the errors and it came up with this.
public Handler<?> getHandler(Class<?> clazz) {
if (clazz == String.class)
return new StringHandler();
if (clazz == Date.class)
return new DateHandler();
return null;
}
Yout HandlerFactory don't know about T. Use your factory like below-
public class HandlerFactory {
public Handler<?> getHandler(Class<?> clazz) {
if (clazz == String.class) {
return new StringHandler();
}
if (clazz == Date.class) {
return new DateHandler();
}
return null;
}
}
I have this class:
public DrawItem {
protected String getSeperator() {
return "";
}
.......
// some other methods
}
I've another class which extends DrawItem.
public DrawNumber extends DrawItem {
#Override
protected String getSeperator() {
return "-";
}
}
Now, in a generic class CombinationGenerator<E>, I'm trying to instantiate objects of DrawItem/DrawNumber. As instantiating a generic type is not possible in java (like new E(...)), I've created a Factory interface according to this answer.
public interface DrawItemFactory<E> {
E create(...);
}
Then in the CombinationGenerator<E> class,
public class CombinationGenerator<E> {
DrawItemFactory<E> factory;
public CombinationGenerator<E>(DrawItemFactory<E> factory) {
this.factory = factory;
}
public List<E> generate() {
......
list.add(factory.create(...));
......
}
}
And now the DrawNumber class implements DrawItemFactory<DrawItem> interface.
public DrawItem implements DrawItemFactory<DrawItem> {
protected String getSeperator() {
return "";
}
#Override
public DrawItem create(...) {
return new DrawItem(...);
}
.......
// some other methods
}
And I can create CombinationGenerator<DrawItem> class.
DrawItem drawItem = new DrawItem(...);
CombinationGenerator<DrawItem> generator = new CombinationGenerator<DrawItem>(drawItem);
List<DrawItem> combinations = generator.generate();
So far, everything is fine. But when I try to create a DrawNumber class like this,
public DrawNumber implements DrawItemFactory<DrawNumber> {
....
}
It gives me the following error:
The interface DrawItemFactory cannot be implemented more than once with different arguments: DrawItemFactory<DrawItem> and DrawItemFactory<DrawNumber>
I've tried this solution but I got the same error. Is there any other way to do this?
Instead of using all those factories you could do something like this:
public class CombinationGenerator<E> {
E instance;
public CombinationGenerator(Class<E> clazz) {
Constructor<?> con = clazz.getConstructor();
this.instance = (E) con.newInstance();
}
}
...
CombinationGenerator<DrawNumber> cg = new CombinationGenerator<DrawNumber>(DrawNumber.class);
According to #JB Nizet's comment, I've solved the problem by creating two separate factory classes like this:
public interface ItemFactory<E> {
E create(int[] values);
public static class DrawItemFactory implements ItemFactory<DrawItem> {
#Override
public DrawItem create(int[] values) {
return new DrawItem(values);
}
}
public static class DrawNumberFactory implements ItemFactory<DrawNumber> {
#Override
public DrawNumber create(int[] values) {
return new DrawNumber(values);
}
}
}
In the CombinationGenerator,
public class CombinationGenerator<E> {
ItemFactory<E> factory;
public CombinationGenerator<E>(ItemFactory<E> factory) {
this.factory = factory;
}
public List<E> generate() {
......
list.add(factory.create(...));
......
}
}
And instantiated CombinationGenerator like this:
DrawNumber drawNumber = new DrawNumber();
CombinationGenerator<DrawNumber> generator = new CombinationGenerator<DrawNumber>(new ItemFactory.DrawNumberFactory());
List<DrawNumber> combinations = generator.generate();
I have to handle two classes with identical methods but they don't implement the same interface, nor do they extend the same superclass. I'm not able / not allowed to change this classes and I don't construct instances of this classes I only get objects of this.
What is the best way to avoid lots of code duplication?
One of the class:
package faa;
public class SomethingA {
private String valueOne = null;
private String valueTwo = null;
public String getValueOne() { return valueOne; }
public void setValueOne(String valueOne) { this.valueOne = valueOne; }
public String getValueTwo() { return valueTwo; }
public void setValueTwo(String valueTwo) { this.valueTwo = valueTwo; }
}
And the other...
package foo;
public class SomethingB {
private String valueOne;
private String valueTwo;
public String getValueOne() { return valueOne; }
public void setValueOne(String valueOne) { this.valueOne = valueOne; }
public String getValueTwo() { return valueTwo; }
public void setValueTwo(String valueTwo) { this.valueTwo = valueTwo; }
}
(In reality these classes are larger)
My only idea is now to create a wrapper class in this was:
public class SomethingWrapper {
private SomethingA someA;
private SomethingB someB;
public SomethingWrapper(SomethingA someA) {
//null check..
this.someA = someA;
}
public SomethingWrapper(SomethingB someB) {
//null check..
this.someB = someB;
}
public String getValueOne() {
if (this.someA != null) {
return this.someA.getValueOne();
} else {
return this.someB.getValueOne();
}
}
public void setValueOne(String valueOne) {
if (this.someA != null) {
this.someA.setValueOne(valueOne);
} else {
this.someB.setValueOne(valueOne);
}
}
public String getValueTwo() {
if (this.someA != null) {
return this.someA.getValueTwo();
} else {
return this.someB.getValueTwo();
}
}
public void setValueTwo(String valueTwo) {
if (this.someA != null) {
this.someA.setValueTwo(valueTwo);
} else {
this.someB.setValueTwo(valueTwo);
}
}
}
But I'm not realy satisfied with this solution. Is there any better / more elegant way to solve this problem?
A better solution would be to create an interface to represent the unified interface to both classes, then to write two classes implementing the interface, one that wraps an A, and another that wraps a B:
public interface SomethingWrapper {
public String getValueOne();
public void setValueOne(String valueOne);
public String getValueTwo();
public void setValueTwo(String valueTwo);
};
public class SomethingAWrapper implements SomethingWrapper {
private SomethingA someA;
public SomethingWrapper(SomethingA someA) {
this.someA = someA;
}
public String getValueOne() {
return this.someA.getValueOne();
}
public void setValueOne(String valueOne) {
this.someA.setValueOne(valueOne);
}
public String getValueTwo() {
return this.someA.getValueTwo();
}
public void setValueTwo(String valueTwo) {
this.someA.setValueTwo(valueTwo);
}
};
and then another class just like it for SomethingBWrapper.
There, a duck-typed solution. This will accept any object with valueOne, valueTwo properties and is trivially extensible to further props.
public class Wrapper
{
private final Object wrapped;
private final Map<String, Method> methods = new HashMap<String, Method>();
public Wrapper(Object w) {
wrapped = w;
try {
final Class<?> c = w.getClass();
for (String propName : new String[] { "ValueOne", "ValueTwo" }) {
final String getter = "get" + propName, setter = "set" + propName;
methods.put(getter, c.getMethod(getter));
methods.put(setter, c.getMethod(setter, String.class));
}
} catch (Exception e) { throw new RuntimeException(e); }
}
public String getValueOne() {
try { return (String)methods.get("getValueOne").invoke(wrapped); }
catch (Exception e) { throw new RuntimeException(e); }
}
public void setValueOne(String v) {
try { methods.get("setValueOne").invoke(wrapped, v); }
catch (Exception e) { throw new RuntimeException(e); }
}
public String getValueTwo() {
try { return (String)methods.get("getValueTwo").invoke(wrapped); }
catch (Exception e) { throw new RuntimeException(e); }
}
public void setValueTwo(String v) {
try { methods.get("setValueTwo").invoke(wrapped, v); }
catch (Exception e) { throw new RuntimeException(e); }
}
}
You can use a dynamic proxy to create a "bridge" between an interface you define and the classes that conform but do not implement your interface.
It all starts with an interface:
interface Something {
public String getValueOne();
public void setValueOne(String valueOne);
public String getValueTwo();
public void setValueTwo(String valueTwo);
}
Now you need an InvocationHandler, that will just forward calls to the method that matches the interface method called:
class ForwardInvocationHandler implements InvocationHandler {
private final Object wrapped;
public ForwardInvocationHandler(Object wrapped) {
this.wrapped = wrapped;
}
#Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
Method match = wrapped.getClass().getMethod(method.getName(), method.getParameterTypes());
return match.invoke(wrapped, args);
}
}
Then you can create your proxy (put it in a factory for easier usage):
SomethingA a = new SomethingA();
a.setValueOne("Um");
Something s = (Something)Proxy.newProxyInstance(
Something.class.getClassLoader(),
new Class[] { Something.class },
new ForwardInvocationHandler(a));
System.out.println(s.getValueOne()); // prints: Um
Another option is simpler but requires you to subclass each class and implement the created interface, simply like this:
class SomethingAImpl extends SomethingA implements Something {}
class SomethingBImpl extends SomethingB implements Something {}
(Note: you also need to create any non-default constructors)
Now use the subclasses instead of the superclasses, and refer to them through the interface:
Something o = new SomethingAImpl(); // o can also refer to a SomethingBImpl
o.setValueOne("Uno");
System.out.println(o.getValueOne()); // prints: Uno
i think your original wrapper class is the most viable option...however it can be done using reflection, your real problem is that the application is a mess...and reflection is might not be the method you are looking for
i've another proposal, which might be help: create a wrapper class which has specific functions for every type of classes...it mostly copypaste, but it forces you to use the typed thing as a parameter
class X{
public int asd() {return 0;}
}
class Y{
public int asd() {return 1;}
}
class H{
public int asd(X a){
return a.asd();
}
public int asd(Y a){
return a.asd();
}
}
usage:
System.out.println("asd"+h.asd(x));
System.out.println("asd"+h.asd(y));
i would like to note that an interface can be implemented by the ancestor too, if you are creating these classes - but just can't modify it's source, then you can still overload them from outside:
public interface II{
public int asd();
}
class XI extends X implements II{
}
class YI extends Y implements II{
}
usage:
II a=new XI();
System.out.println("asd"+a.asd());
You probably can exploit a facade along with the reflection - In my opinion it streamlines the way you access the legacy and is scalable too !
class facade{
public static getSomething(Object AorB){
Class c = AorB.getClass();
Method m = c.getMethod("getValueOne");
m.invoke(AorB);
}
...
}
I wrote a class to encapsulate the logging framework API's. Unfortunately, it's too long to put in this box.
The program is part of the project at http://www.github.com/bradleyross/tutorials with the documentation at http://bradleyross.github.io/tutorials. The code for the class bradleyross.library.helpers.ExceptionHelper in the module tutorials-common is at https://github.com/BradleyRoss/tutorials/blob/master/tutorials-common/src/main/java/bradleyross/library/helpers/ExceptionHelper.java.
The idea is that I can have the additional code that I want to make the exception statements more useful and I won't have to repeat them for each logging framework. The wrapper isn't where you eliminate code duplication. The elimination of code duplication is in not having to write multiple versions of the code that calls the wrapper and the underlying classes. See https://bradleyaross.wordpress.com/2016/05/05/java-logging-frameworks/
The class bradleyross.helpers.GenericPrinter is another wrapper that enables you to write code that works with both the PrintStream, PrintWriter, and StringWriter classes and interfaces.