Choosing between extended classes inside constructor - java

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());
}
}

Related

Factory of generic type interfaces

I am looking for some help in designing the factory of concrete implementations of a generic interface. Java version 7, can not use 8+
Given such interface and abstract class:
public interface ValidationStrategy<T> {
String getNativeQuery();
ValidationStrategy<T> withValue(T value);
}
public abstract class AbstractValidationStrategy<T> implements ValidationStrategy<T> {
protected T value;
public void setValue(T value) {
this.value = value;
}
}
I want to have multiple implementations of such interface like:
public class DocumentValidationStrategy extends AbstractValidationStrategy<String> {
#Override
public String getNativeQuery() {
// here goes customer native query
return null;
}
#Override
public ValidationStrategy<String> withValue(String value) {
setValue(value);
return this;
}
}
The ValidationStrategy would be decided upon predefined enum (interface, has to be cross-platform unified) by the, ideally, a factory. The problems are generics and I can not really go around them with nor I haven't crossed any question that would address my problem
public class ValidationStrategyFactory {
private static final Map<CustomerValueValidationEnum, Class<? extends ValidationStrategy<?>>> validationStrategiesMap = new HashMap<>();
{
validationStrategiesMap.put(CustomerValueValidationEnum.VALIDATE_DOCUMENT, DocumentValidationStrategy.class);
}
private static Class<? extends ValidationStrategy<?>> getInstance(CustomerValueValidationEnum validationEnum) {
return validationStrategiesMap.get(validationEnum);
}
public static ValidationStrategy<?> createInstance(CustomerValueValidationEnum validationEnum)
throws IllegalAccessException, InstantiationException {
return getInstance(validationEnum).newInstance();
}
}
This obviously leads to problems where I can not create the proper implemntation of the ValidationStrategy interface due to my bad usage of java generics where I try to:
public boolean isValueUnique(CustomerValueValidationEnum type, Object value) {
try {
ValidationStrategyFactory.createInstance(type).withValue(value);
} catch (IllegalAccessException | InstantiationException e) {
throw new UnsupportedOperationException();
}
return false;
}
which obviously does not work as I can not feed value the way I want (value can be everything, a String, Integer or a List). I know that I am trying to combine factory and strategy patterns and I tried my best to combine both of them, I guess it is a bad pattern but now I do not really know how else can I create easily extensible validation mechanism that would only require me to create a single class.
EDIT: as requested, simple enum class that is shared between multiple services and it should not contain any business logic.
public enum CustomerValueValidationEnum {
VALIDATE_DOCUMENT("validateDocumentNumber")
;
private final String name;
private CustomerValueValidationEnum(String name) {
this.name = name;
}
#ValueMapKey
public String getName() {
return this.name;
}
}
It is impossible to type dynamically any generic type as it's checked during compilation. I suggest you to make your factory switch on your enum (using/or not a Map).
Implementation without Map :
enum CustomerValueValidationEnum { // Not provided by OP
VALIDATE_DOCUMENT,
VALIDATE_NUMBER
}
interface ValidationStrategy<T> {
String getNativeQuery();
ValidationStrategy<T> withValue(T value);
}
abstract class AbstractValidationStrategy<T> implements ValidationStrategy<T> {
protected T value;
public void setValue(T value) {
this.value = value;
}
#Override
public String getNativeQuery() {
return null;
}
#Override
public ValidationStrategy<T> withValue(T value) {
setValue(value);
return this;
}
}
class DocumentValidationStrategy<T> extends AbstractValidationStrategy<T> {
#Override
public String getNativeQuery() {
return "Customer Query";
}
}
class ValidationStrategyFactory {
// Generic types are checked during compilation time, can't type it dynamically
public static ValidationStrategy<?> createInstance(CustomerValueValidationEnum validationEnum) {
ValidationStrategy valStrat = null;
switch(validationEnum) {
case VALIDATE_DOCUMENT:
valStrat = new DocumentValidationStrategy<String>();
case VALIDATE_NUMBER:
valStrat = new DocumentValidationStrategy<Integer>();
}
return valStrat;
}
}
Implementation with Map :
import java.util.HashMap;
import java.util.Map;
enum CustomerValueValidationEnum { // Not provided by OP
VALIDATE_DOCUMENT(String.class),
VALIDATE_NUMBER(Integer.class);
private Class validationType;
CustomerValueValidationEnum(Class cls) {
validationType = cls;
}
public Class getValidationType() {
return validationType;
}
}
interface ValidationStrategy<T> {
String getNativeQuery();
ValidationStrategy<T> withValue(T value);
}
abstract class AbstractValidationStrategy<T> implements ValidationStrategy<T> {
protected T value;
public void setValue(T value) {
this.value = value;
}
#Override
public String getNativeQuery() {
return null;
}
#Override
public ValidationStrategy<T> withValue(T value) {
setValue(value);
return this;
}
}
class DocumentValidationStrategy<T> extends AbstractValidationStrategy<T> {
#Override
public String getNativeQuery() {
return "Customer Query";
}
}
class ValidationStrategyFactory {
private static final Map<Class, ValidationStrategy> validationStrategiesMap = new HashMap<>();
{
validationStrategiesMap.put(String.class, new DocumentValidationStrategy<String>());
validationStrategiesMap.put(Integer.class, new DocumentValidationStrategy<Integer>());
}
private static ValidationStrategy<?> getInstance(CustomerValueValidationEnum validationEnum) {
return validationStrategiesMap.get(validationEnum.getValidationType());
}
}
You can't use generic type through enum (without implementing an interface) : Post
You can't type dynamically any generic type : Post
One workaround is using a way to get each generic type strategy with a separate method getting from a separate map.
The lower number of various strategy generic types, the more appropriate this way is.
public class StrategyFactory {
static final Map<CustomerValueValidationEnum, ValidationStrategy<String>> validationStringStrategiesMap = new HashMap<>() {{
validationStringStrategiesMap.put(CustomerValueValidationEnum.VALIDATE_DOCUMENT_STRING, new DocumentStringValidationStrategy());
}};
static final Map<CustomerValueValidationEnum, ValidationStrategy<Integer>> validationIntegerStrategiesMap = new HashMap<>() {{
validationIntegerStrategiesMap.put(CustomerValueValidationEnum.VALIDATE_DOCUMENT_INTEGER, new DocumentIntegerValidationStrategy());
}};
public static ValidationStrategy<String> stringStrategy(CustomerValueValidationEnum e) {
return validationStringStrategiesMap.get(e);
}
public static ValidationStrategy<Integer> integerStrategy(CustomerValueValidationEnum e) {
return validationIntegerStrategiesMap.get(e);
}
}
public class DocumentStringValidationStrategy extends AbstractValidationStrategy<String> { ... }
public class DocumentIntegerValidationStrategy extends AbstractValidationStrategy<Integer> { ... }
Advantages:
The generic type will be always inferred: StrategyFactory.integerStrategy(null).withValue(1); which means the user-call is very comfortable.
Scales with a low number of generic types: 2 generic type of strategies -> 2 maps -> 2 methods.
Disadvantage:
The user must know if the String-type or Integer-type is to be requested.
Doesn't scale with a high number of generic types: if each strategy has a custom type, then this solution will not help you at all.
Characteristics:
Not null-safe, the map can return null (I'd use null-object pattern for safe behavior). This would be issue even in any of your solutions

What is the idiomatic way to write common code for a group of classes with identical methods, but not implementing the same interface?

I'm using an external library that provides tightly related classes (generated from some template), but unfortunately without a shared interface, e.g.
public class A {
public UUID id();
public Long version();
public String foo();
public String bar();
}
public class B {
public UUID id();
public Long version();
public String foo();
public String bar();
}
public class C {
public UUID id();
public Long version();
public String foo();
public String bar();
}
// ... and more: D, E, F, etc.
Given I have no influence over the external library, what's the idiomatic way to write logic common to a group of classes that share the same method signatures (at least, for the methods being used by the common logic)?
Currently I do one of three things, on a case-by-case basis:
I write helper methods that take the primitive results from each object, e.g.
private static void myHelper(UUID id, Long version, String foo, String bar) {
...
}
This way I can "unpack" an object regardless of its type:
myHelper(whatever.id(), whatever.version(), whatever.foo(), whatever.bar());
But that can get very wordy, especially when I need to work with many members.
In the scenario where I'm only working with getters (i.e. only need to access current values of the objects), I've found a way to use mapping libraries like Dozer or ModelMapper to map A or B or C to my own common class, e.g.
public class CommonABC {
UUID id;
Long version;
String foo;
String bar;
}
By playing with configuration, you can get these libraries to map all members, whether method or field, public or private, to your class, e.g.
modelMapper.getConfiguration()
.setFieldMatchingEnabled(true)
.setFieldAccessLevel(Configuration.AccessLevel.PRIVATE);
But this was kind of a "broadsword" approach, a hack that IMO isn't clearly justified merely to factor out duplicate code.
Finally, in certain other scenarios it was most succinct to simply do
private static void myHelper(Object extLibEntity) {
if (extLibEntity instanceof A) {
...
} else if (extLibEntity instanceof B) {
...
} else if (extLibEntity instanceof C) {
...
} else {
throw new RuntimeException(...);
}
}
It's obvious why this is bad.
In enterprise situations where you have to live with a library that is this way, what would you do?
I'm leaning toward writing a very explicit, if verbose, mapper (not using a generic mapper library) that translates these entities from the start. But, I wonder if there's a better way. (Like, is there a way to "cast" an object as implementing a new interface, in runtime?)
An option that is (under the hood) likely similar to the second approach, but comparatively lean and flexible, is to use Dynamic Proxy Classes. With only a few lines of code, you can let any object "appear" to implement a certain interface, as long as it has the required methods. The following is an MCVE that shows the basic approach:
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.UUID;
public class DelegatingProxyExample {
public static void main(String[] args) {
A a = new A();
B b = new B();
C c = new C();
CommonInterface commonA = wrap(a);
CommonInterface commonB = wrap(b);
CommonInterface commonC = wrap(c);
use(commonA);
use(commonB);
use(commonC);
}
private static void use(CommonInterface commonInterface) {
System.out.println(commonInterface.id());
System.out.println(commonInterface.version());
System.out.println(commonInterface.foo());
System.out.println(commonInterface.bar());
}
private static CommonInterface wrap(Object object) {
CommonInterface commonInterface = (CommonInterface) Proxy.newProxyInstance(
CommonInterface.class.getClassLoader(),
new Class[] { CommonInterface.class }, new Delegator(object));
return commonInterface;
}
}
// Partially based on the example from
// https://docs.oracle.com/javase/8/docs/technotes/guides/reflection/proxy.html
class Delegator implements InvocationHandler {
private static Method hashCodeMethod;
private static Method equalsMethod;
private static Method toStringMethod;
static {
try {
hashCodeMethod = Object.class.getMethod("hashCode", (Class<?>[]) null);
equalsMethod = Object.class.getMethod("equals", new Class[] { Object.class });
toStringMethod = Object.class.getMethod("toString", (Class<?>[]) null);
} catch (NoSuchMethodException e) {
throw new NoSuchMethodError(e.getMessage());
}
}
private Object delegate;
public Delegator(Object delegate) {
this.delegate = delegate;
}
public Object invoke(Object proxy, Method m, Object[] args) throws Throwable {
Class<?> declaringClass = m.getDeclaringClass();
if (declaringClass == Object.class) {
if (m.equals(hashCodeMethod)) {
return proxyHashCode(proxy);
} else if (m.equals(equalsMethod)) {
return proxyEquals(proxy, args[0]);
} else if (m.equals(toStringMethod)) {
return proxyToString(proxy);
} else {
throw new InternalError("unexpected Object method dispatched: " + m);
}
} else {
// TODO Here, the magic happens. Add some sensible error checks here!
Method delegateMethod = delegate.getClass().getDeclaredMethod(
m.getName(), m.getParameterTypes());
return delegateMethod.invoke(delegate, args);
}
}
protected Integer proxyHashCode(Object proxy) {
return new Integer(System.identityHashCode(proxy));
}
protected Boolean proxyEquals(Object proxy, Object other) {
return (proxy == other ? Boolean.TRUE : Boolean.FALSE);
}
protected String proxyToString(Object proxy) {
return proxy.getClass().getName() + '#' + Integer.toHexString(proxy.hashCode());
}
}
interface CommonInterface {
UUID id();
Long version();
String foo();
String bar();
}
class A {
public UUID id() {
return UUID.randomUUID();
}
public Long version() {
return 1L;
}
public String foo() {
return "fooA";
}
public String bar() {
return "barA";
}
}
class B {
public UUID id() {
return UUID.randomUUID();
}
public Long version() {
return 2L;
}
public String foo() {
return "fooB";
}
public String bar() {
return "barB";
}
}
class C {
public UUID id() {
return UUID.randomUUID();
}
public Long version() {
return 3L;
}
public String foo() {
return "fooC";
}
public String bar() {
return "barC";
}
}
Of course, this uses reflection internally, and should only be used when you know what you're doing. Particularly, you should add some sensible error checking, at the place that is marked with TODO: There, the method of the interface is looked up in the given delegate object.
The only technique not tried:
package aplus;
public interface Common {
...
}
public class A extends original.A implements Common {
}
public class B extends original.B implements Common {
}

Method not available in Generic Return Object

I am trying to access the method GetDatbaseName(), from the returned object obj, but it is returning error that the method is not available.
However, when I Typecast the obj, it is working.
String name = ((Oracle)obj).GetDatabaseName();
How to handle this generic? Like I can't typecast for each return type like Oracle and MongoDB. Also any better implementation for this?
// one class needs to have a main() method
public class HelloWorld
{
// arguments are passed using the text field below this editor
public static void main(String[] args)
{
Data dt = new Data("Oracle");
Object obj = dt.GetObject();
String name = obj.GetDatabaseName();
System.out.println(name);
}
}
public class Data
{
public String _type;
public Data(String type)
{
_type = type;
}
public Object GetObject()
{
Object obj = null;
switch(_type)
{
case("Oracle"):
obj = new Oracle("Test");
break;
case("MongoDB"):
obj = new MongoDB("TestCollection");
break;
}
return obj;
}
}
public class Oracle
{
public String _databaseName;
public Oracle(String databaseName)
{
_databaseName = databaseName;
}
public String GetDatabaseName() { return _databaseName; }
}
public class MongoDB
{
public String _collectionName;
public MongoDB(String collectionName)
{
_collectionName = collectionName;
}
public String GetCollectionName() { return _collectionName; }
}
There are two ways to solve this, the first is using a generic class, while the second is using interface, the second approach is better if you know that the classes will have the same methods, while the generic approach is if the classes have different methods
Generic approach
public class DBtest{
public static void main(String[] args){
DataBase<Oracle> database = new DataBase<>(Oracle.class);
Oracle oracle = database.getDataBase();
System.out.println(oracle.getDatabaseName());
}
}
class DataBase<T>{
private T database;
public DataBase(Class<T> classOfT){
try {
database = classOfT.newInstance();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
public T getDataBase(){
return database;
}
}
class Oracle{
private String _databaseName;
public Oracle(){
_databaseName = "test";
}
public String getDatabaseName() { return _databaseName; }
}
As you can see, it is not possible to define the name of the database, this would be possible of you write <T extends Name> which is an interface which has getName() and setName() method
Interface approach
public class DBtest{
// arguments are passed using the text field below this editor
public static void main(String[] args){
DataBase database = new DataBase(new Oracle("test"));
DatabaseName databaseName = database.getDataBase();
System.out.println(databaseName.getName());
}
}
interface DatabaseName {
String getName();
}
class DataBase{
private DatabaseName databaseName;
public DataBase(DatabaseName databaseName){
this.databaseName = databaseName;
}
public DatabaseName getDataBase(){
return databaseName;
}
}
class Oracle implements DatabaseName {
private String _databaseName;
public Oracle(String name){
_databaseName = name;
}
public String getName() {
return _databaseName;
}
}
class MongoDB implements DatabaseName {
private String _databaseName;
public MongoDB(String name){
_databaseName = name;
}
public String getName() {
return _databaseName;
}
}
Obviously DatabaseName is a bad name for an interface, but it is the only method which is the same for both classes, so it makes sense to call it that. The great thing about interfaces is that you don't have to give a shit about what class is used as long as you know the method names.
You problem is on the following lines:
Object obj = dt.GetObject();
String name = obj.GetDatabaseName();
As far as those lines are concerned, obj is of type Object, which does not have the invoked method; thus, the issue. This is due to Java being strongly typed.
To go around that, you need a type that has this method, or use reflection. To use a type that has this method, they need to inherit it from a common parent of implement it from a common interface. You can also wrap you objects or a bunch of other alternatives.
In your case, it seems that a common interface is the easiest way to go. In this case, each class should implement this interface and instead of using Object your reference would be of the type of that interface.
public Object GetObject()
Would become
public MyInterface GetObject()
and
public class Oracle
would be
public class Oracle implements MyInterface
Where MyInterface would declare the method
public interface MyInterface {
String GetDatabaseName();
}
Being mindful of Java conventions, methods should start with lowercase
public interface MyInterface {
String getDatabaseName();
}
In the case where you cannot change the code in order to implements those methods, you can use "instanceof" to test against the class type.
name = (obj instanceof Oracle)?((Oracle)obj).GetDatabaseName():((MongoDB )obj).getCollectionName();
You must have to create an Interface and then with getDatabaseName() method. Then your objects Oracle and MongoDB must implement that interface.
What you are trying to do is something similar to AbstractFactory Pattern. You should google it.
public interface MyDbInterface {
String getDatabaseName();
}
public class HelloWorld {
// arguments are passed using the text field below this editor
public static void main(String[] ){
MyDbInterface dt = DataFactory.create("Oracle");
String name = dt.getDatabaseName();
System.out.println(name);
}
}
public final class DataFactory{
private DataFactory(){
super();
}
public static MyDbInterface create(String type){
MyDbInterface obj = null;
switch(type) {
case("Oracle"):
obj = new Oracle("Test");
break;
case("MongoDB"):
obj = new MongoDB("TestCollection");
break;
}
return obj;
}
}
public class Oracle implement MyDbInterface{
public String databaseName;
public Oracle(String databaseName){
databaseName = databaseName;
}
#Override
public String getDatabaseName() {
return databaseName;
}
}
public class MongoDB implement MyDbInterface{
public String collectionName;
public MongoDB(String collectionName){
collectionName = collectionName;
}
public String getCollectionName() {
return collectionName;
}
#Override
public String getDatabaseName() {
return getCollectionName();
}
}
I suposed you come from C#, check java style guide. ;)
You should think about the design of your code. You need to use basic OOP principal to solve the problem. There are several ways to solve your problem like using interface/generics etc. Here I am giving one such example.
public class HelloWorld {
public static void main(String[] args) {
Data dt = new Data("Oracle");
DataBase obj = dt.GetObject();
String name = obj.getDatabaseName();
System.out.println("Name : "+name);
}
}
class Data {
public String _type;
public Data(String type) {
_type = type;
}
public DataBase GetObject() {
DataBase dataBase=null;
switch (_type) {
case "Oracle":
dataBase = new Oracle();
break;
case "Mongo":
dataBase = new MongoDb();
break;
}
return dataBase;
}
}
interface DataBase {
String getDatabaseName();
}
class Oracle implements DataBase {
public String getDatabaseName() {
return "Oracle";
}
}
class MongoDb implements DataBase {
public String getDatabaseName() {
return "Mongo";
}
}
Edited:
Here is another way to solve your problem. I believe this approach might solve your problem.
public class HelloWorld {
public static void main(String[] args) {
Data<Oracle> dt = new Data<Oracle>("Oracle");
Oracle obj = dt.getObject();
String name = obj.getDatabaseName();
System.out.println("Name : "+name);
}
}
class Data<T> {
public String _type;
public Data(String type) {
_type = type;
}
public T getObject() {
Object dataBase=null;
switch (_type) {
case "Oracle":
dataBase = new Oracle();
break;
case "Mongo":
dataBase = new MongoDb();
break;
}
return (T)dataBase;
}
}
class Oracle {
public String getDatabaseName() {
return "Oracle";
}
}
class MongoDb {
}

using object functions in java

I'm trying to implement function objects in Java. I have a Unit class, with a default addition function that should be used in most initializations of a Unit object. However, for some issues, I need a different addition function. The code will look something like this:
public class Unit() {
public Unit(unitType) {
if (unitType == "specialType") {
additionFunc = defaultFunc } else {
additionFunc = specialFunc }
}
}
public int swim() {
return additionFunc()
}
// definiion of regularFunc
// definition of specialFunc
}
Then, from the main file:
Unit fish = new Unit(regularTyoe);
Unit fatFish = new Unit(specialType);
fish.swim(); //regular function is called
fatFish.swim(); //special function is called
That's it.. does anyone know how this can be done?
You need to look up inheritance and method overriding. It would probably help to read up on proper Object Oriented Programming as well.
The proper way to do this is:
class Fish {
public void swim() {
// normal swim
}
}
class FatFish extends Fish {
#Override
public void swim() {
// special swim
}
}
Fish fish = new Fish()
Fish fatFish = new FatFish()
fish.swim() // normal swim
fatFish.swim() // slow swim
Make a new FatFish class which extends Unit and overrides swim().
Unit fish = new Unit();
Unit fatFish = new FatFish();
fish.swim(); //regular function is called
fatFish.swim(); //special function is called
There are many solutions for your problem, one of them is using inheritance, that you could have a default implementation of Unit, and extend it overriding the desired method with a new one.
Basically would be something like:
public class FatFish {
#Override
public void swim() {
// new behavior
}
}
Another approach would be to implement Strategy Design Pattern, which allows you to select algorithms on runtime. Therefore you could do something like:
public interface SwimStrategy {
void execute();
}
public class FatFishSwimStrategy implements SwimStrategy {
#Override
public void execute() {
// fat fish swim impl
}
}
public class FishSwimStrategy implements SwimStrategy {
#Override
public void execute() {
// normal fish swim impl
}
}
public class Fish {
private final SwimStrategy swimStrategy;
public Fish(SwimStrategy swimStrategy) {
this.swimStrategy = swimStrategy;
}
public void swim() {
swimStrategy.execute();
}
}
In order to instantiate an object you could do:
new Fish(new FatFishSwimStrategy());
or for the normal behavior:
new Fish(new FishSwimStrategy());
I think it can do by extends and factory method:
public class Unit {
public static Unit createUnit(UnitType type) {
if (UnitType.Special == type) {
return new Unit(type) {
#Override
public int swim() {
System.out.println("special swim");
return 0;
}
};
}
return new Unit(UnitType.Default);
}
private UnitType type;
private Unit(UnitType type) {
this.type = type;
System.out.println("create unit for " + type);
}
public int swim() {
System.out.println("default swim");
return 0;
}
public static void main(String[] args) {
Unit fish = Unit.createUnit(UnitType.Default);
Unit fatFish = Unit.createUnit(UnitType.Special);
fish.swim();
fatFish.swim();
}
}
This is a simple type enum:
public enum UnitType {
Default, Special
}
There are two ways to accomplish this polymorphic behavior in Java. The first is to use a inheritance and a hierarchical set of classes. For example, you could have an abstract base class which defines an abstract method called "swim". Then each concrete fish class would extend this base class and implement the swim method. Later when you have a set of fish objects, you can upcast them to the base class and invoke the swim method on each.
The second way is to use interfaces. You define an interface (e.g. ISwim) which declares the public method swim. Each fish class (whether part of a class hierarchy or no) would implement the ISwim interface, meaning they would define a swim method. Then if you have a set of fish class objects of different types, you can cast each to the ISwim interface and invoke the swim method on each object.
Java does not have function pointers, so the approach you are considering is inappropriate for the language. Even in languages with function pointers, the above two approaches would be most appropriate in my opinion.
One way to do this is with an enum for the types of Unit and with Unit subclasses:
public class Unit {
public enum UnitType {
REGULAR {
public Unit makeUnit() {
return new RegularUnit();
}
},
SPECIAL {
public Unit makeUnit() {
return new SpecialUnit();
}
};
abstract public Unit makeUnit();
}
protected Unit() {}
public abstract int swim();
private static class RegularUnit extends Unit {
RegularUnit() {}
public int swim() {
return 0;
}
}
private static class SpecialUnit extends Unit {
SpecialUnit() {}
public int swim() {
return 1;
}
}
}
Unit fish = UnitType.REGULAR.makeUnit();
Unit fatFish = UnitType.SPECIAL.makeUnit();
Another way is with Callable objects:
public class Unit {
public enum UnitType { REGULAR, SPECIAL }
private Callable<Integer> additionFunc;
public Unit(UnitType type) {
switch (type) {
case REGULAR:
additionFunc = new Callable<Integer>() {
public Integer call() {
return 0;
}
};
break;
case SPECIAL:
additionFunc = new Callable<Integer>() {
public Integer call() {
return 1;
}
};
break;
}
}
public int swim() {
return additionFunc();
}
}
Using a simple if statement:
private String unitType;
public Unit(unitType) {
this.unitType = unitType;
}
public int swim() {
if (unitType.equals("specialType") {
return specialFunc();
}
else {
return regularFunc();
}
}
Or using polymorphism and a factory method :
public abstract class Unit() {
protected Unit() {
}
protected abstract int addition();
public int swim() {
return addition();
}
public static Unit forType(String unitType) {
if (unitType.equals("specialType") {
return new SpecialUnit();
}
else {
return new RegularUnit();
}
}
private static class SpecialUnit extends Unit {
#Override
protected addition() {
// special addition
}
}
private static class RegularUnit extends Unit {
#Override
protected addition() {
// regular addition
}
}
}
Or using an Adder functional interface, defining an addition() method, and two concrete implementations of this interface:
private Adder adder;
public Unit(unitType) {
if (unitType.equals("specialType") {
this.adder = new SpecialAdder();
}
else {
this.adder = new RegularAdder();
}
}
public int swim() {
return adder.addition();
}
This last one is the closest to waht you asked in your question. function objects don't exist per se, but can be replaced by interfaces.

How to 'wrap' two classes with identical methods?

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.

Categories

Resources