Using interface injection while having to create instances of the underlying object - java

I have an interface to represent a data structure with competing implementations. I need to use this in a class while decoupling the class from having to know the underlying data structure. And within this class, I will need to create several instances of this implementation. How does one do it using interface injection?
class Foo {
Map<String, IDataStructure> map = new HashMap<String, IDataStructure>();
public void addValue(String key, String value) {
if(!map.containsKey(key)) {
map.put(key, new SomeDataStructure(value));
}
}
}
EDIT
I found out an approach to use interface injection. Create a factory interface
class ADataStructureFactory implements DataStructureFactory {
IDataStructure create() {
return new SomeDataStructure();
}
}
And inject this in the constructor
Foo(DataStuctureFactory factory)
Change the add method
public void addValue(String key, String value) {
if(!map.containsKey(key)) {
map.put(key, factory.create());
}
}

This is what you can do :
Define an add method in IDataStructure :
public interface IDataStructure {
public void add(String value);
}
Create an implementation of IDataStrucutre called ListDataStructure as follows :
public class ListDataStructure implements IDataStructure {
private List<String> dataStructure = new ArrayList<String>();
#Override
public void add(String value) {
dataStructure.add(value);
}
}
Create an implementation of IDataStructure called SetDataStructure
public class SetDataStructure implements IDataStructure {
private Set<String> dataStructure = new HashSet<String>();
#Override
public void add(String value) {
dataStructure.add(value);
}
}
Modify your Foo class as follows :
class Foo {
private Map<String, IDataStructure> map;
public Foo(Map<String,IDataStructure> map) {
this.map = map;
}
public void addValue(String key, String value) {
if(map.containsKey(key)) {
map.get(key).add(value);
} else {
/*handle what happens when data structure does not exist. Maybe thow an exception
}
}
}
Example of how to inject the supported data structures. Note that you cannot define data structures on the fly. You need to prepopulate your map in Foo with the supported implementations of data structures.
public class DataStructureExample {
public static void main(String []args) {
Map<String,IDataStructure> dataStrucures = new HashMap<String,IDataStructure>();
//injecting different data structures into Foo
dataStrucures.put("List", new ListDataStructure());
dataStrucures.put("Set", new SetDataStructure());
Foo foo = new Foo(dataStrucures);
//add some value to a list data structure
foo.addValue("List", "Value1");
//add some valu to a set data structure
foo.addValue("Set", "Value1");
}
}

I found out an approach to use interface injection. Create an abstract factory.
class ADataStructureFactory implements DataStructureFactory {
IDataStructure create() {
return new SomeDataStructure();
}
}
And inject this in the constructor
Foo(DataStuctureFactory factory)
Change the add method
public void addValue(String key, String value) {
if(!map.containsKey(key)) {
map.put(key, factory.create());
}
}

Related

How to capture and propagate a wildcard type argument?

I have a couple of classes having identical methods, except with respect to certain parameter types:
interface ICls<T> {
void doSomething(String key, T value);
Map<String, T> getSomething();
}
class ClsA implements ICls<Boolean> {
#Override public void doSomething(String key, Boolean value) { }
#Override public Map<String, Boolean> getSomething() { return Map.of(); }
}
class ClsB implements ICls<String> {
#Override public void doSomething(String key, String value) {}
#Override public Map<String, String> getSomething() { return Map.of(); }
}
Now I'm trying to have a main class that stores a mixed list of these class objects and for each of these instances, passes info between its two methods:
class Main {
List<ICls<?>> list = List.of(
new ClsA(),
new ClsB()
);
void run() {
list.forEach(cls -> {
Map<String, ?> data = cls.getSomething();
data.keySet().forEach(key -> cls.doSomething(key, data.get(key)));
});
}
The List<ICls<?>> and Map<String, ?> statements are OK. However, the map.get(key) throws an IDE error:
'doSomething(<String, capture<?>>) in '...ICls' cannot be applied to 'String, capture<?>'
Hovering the mouse cursor over the offending statement shows:
Required type: capture of ?
Provided: capture of ?
Assuming that I can't/don't want to change the generic type T to Object, and don't want to change the architecture either, what can I do to make the code here compile?
I've tried changing the signature of doSomething so that it accepts the entire Map<String, T> and call it like so, with no luck either:
cls.doSomething(cls.getSomething());
This compiles for me:
import java.util.List;
import java.util.Map;
public class Comparison {
interface ICls<T> {
void doSomething(String key, T value);
Map<String, T> getSomething();
}
static class ClsA implements ICls<Boolean> {
public void doSomething(String key, Boolean value) {}
public Map<String, Boolean> getSomething() { return null; }
}
static class ClsB implements ICls<String> {
public void doSomething(String key, String value) {}
public Map<String, String> getSomething() { return null; }
}
static class Main {
List<ICls<?>> list = List.of(
new ClsA(),
new ClsB()
);
void run() {
list.forEach(cls -> {
doIt(cls);
});
}
<T> void doIt(ICls<T> cls) {
Map<String, T> data = cls.getSomething();
data.keySet().forEach(key -> cls.doSomething(key, data.get(key)));
}
}
}
It makes clear the relationship between the map and the cls.
In the original context, because the type of the List is ICls<?> we can't get that relationship, but once we get a single ICls we can introduce a type variable T which allows us to express the relationship between getSomething and doSomething.

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

Java Overriding function that one of the parameters are constant in the child class

I have a service that read and write data based on a key-value pairs. The service is generic.
I want to implement a similar class, that extends the class I described, but in the base class the key is constant.
The problem is, that If I try to override the read and write functions, they both will have the key parameter in them, although it is const.
How can I implement and override in this case? Is it possible or only without the inheritence?
My BaseService.java
class BaseService {
private HashMap<String, String> storage = new HashMap<String, String>();
void write(String key, String value) {
storage.put(key, value);
}
String read(String key) {
return storage.get(key);
}
}
and ChildService.java
class ChildService extends BaseService {
static final String KEY = 'const-key';
#override
void write(String value) {
storage.put(KEY, value);
}
#override
String read() {
return storage.get(KEY);
}
}
It isn't possible to override this way since the signature is now different.
Try something like this:
public abstract class BaseService {
HashMap<String, String> storage = new HashMap<String, String>();
abstract String getKey();
void write(String key, String value) {
storage.put(key, value);
}
String read(String key) {
return storage.get(key);
}
String read() {
return storage.get(getKey());
}
void write(String value) {
storage.put(getKey(), value);
}
}
public class ChildService extends BaseService {
static final String KEY = "const-key";
#Override
String getKey() {
return KEY;
}
}

Find specific object in an arraylist

Currently have an issue getting a specific object in an arraylist. So I have multiple classes that implements the same interface, and I create objects of the different classes. The problem is that I don't know how to differentiate the classes in the arraylist.
ArrayList<Interface> arraylist = new ArrayList<>();
public static void main(String[] args) {
addInterface(new interfaceA());
addInterface(new interfaceB());
addInterface(new interfaceC());
}
public static void addInterface(Interface foo) {
arraylist.add(foo);
}
Let say that I want to get interfaceA(), I could call it by arraylist.get(0) but I don't want to hardcode it. Each class has the same methods but the code is different.
I would use a Map instead of a List. In this case an IdentityHashMap is a good fit.
interface Thing {
}
IdentityHashMap<Class<? extends Thing>, Thing> things = new IdentityHashMap<>();
class ThingA implements Thing {
#Override
public String toString() {
return "ThingA{}";
}
}
class ThingB implements Thing {
#Override
public String toString() {
return "ThingB{}";
}
}
class ThingC implements Thing {
#Override
public String toString() {
return "ThingC{}";
}
}
public void registerThing(Thing thing) {
things.put(thing.getClass(), thing);
}
public void test(String[] args) {
registerThing(new ThingA());
registerThing(new ThingB());
registerThing(new ThingC());
System.out.println(things.get(ThingB.class));
}
You could filter using a predicate, by checking runtime classes:
List<Interface> interfaceAList = arraylist.stream()
.filter(e -> InterfaceA.class.isInstance(e))
.collect(Collectors.toList());
public Interface getInterfaceA(List<Interface> interfaces) {
for (Interface i : interfaces) {
if (i instanceof InterfaceA)
return i;
}
return null;
}

Read and write into shared thread variables

first of all i am new to threads and shared variables. So please be kind with me ;-)
I'm having a class called Routing. This class recieves and handles messages. If a message is of type A the Routing-Object should pass it to the ASender Object which implements the Runnable Interface. If the message is of type B the Routing-Class should pass it to the BSender Object.
But the ASender and BSender Objects have common variables, that should be stored into the Routing-Object.
My idea now is to declare the variables as synchronized/volatile in the Routing-Object and the getter/setter also.
Is this the right way to synchronize the code? Or is something missing?
Edit: Added the basic code idea.
RoutingClass
public class Routing {
private synchronized Hashtable<Long, HashSet<String>> reverseLookup;
private ASender asender;
private BSender bsender;
public Routing() {
//Constructor work to be done here..
reverseLookup = new Hashtable<Long, HashSet<String>>();
}
public void notify(TopicEvent event) {
if (event.getMessage() instanceof AMessage) {
asender = new ASender(this, event.getMessage())
} else if (event.getMessage() instanceof BMessage) {
bsender = new BSender(this, event.getMessage())
}
}
public synchronized void setReverseLookup(long l, Hashset<String> set) {
reverseLookup.put(l, set);
}
public synchronized Hashtable<Long, Hashset<String>> getReverseLookup() {
return reverseLookup;
}
}
ASender Class
public class ASender implements Runnable {
private Routing routing;
private RoutingMessage routingMessage;
public ASender(Routing r, RoutingMessage rm) {
routing = r;
routingMessage = rm;
this.run();
}
public void run() {
handleMessage();
}
private void handleMessage() {
// do some stuff and extract data from the routing message object
routing.setReverseLookup(somethingToSet)
}
}
Some comments:
Hashtable is a thread-safe implementation, you do not need another "synchronized" keyword see this and this for more information
Avoid coupling, try to work with interfaces or pass the hashtable to your senders, see this for more information
Depending on the amount of senders, you might want to use a ConcurrentHashMap, it greatly improves the performance, see ConcurrentHashMap and Hashtable in Java and Java theory and practice: Concurrent collections classes
This would conclude something like...:
public interface IRoutingHandling {
void writeMessage(Long key, HashSet<String> value);
}
public class Routing implements IRoutingHandling {
private final Hashtable<Long, HashSet<String>> reverseLookup;
private ASender asender;
private BSender bsender;
public Routing() {
//Constructor work to be done here..
reverseLookup = new Hashtable<Long, HashSet<String>>();
}
public void notify(TopicEvent event) {
if (event.getMessage() instanceof AMessage) {
asender = new ASender(this, event.getMessage())
} else if (event.getMessage() instanceof BMessage) {
bsender = new BSender(this, event.getMessage())
}
}
#Override
public void writeMessage(Long key, HashSet<String> value) {
reverseLookup.put(key, value);
}
}
public class ASender implements Runnable {
private IRoutingHandling _routingHandling;
public ASender(IRoutingHandling r, RoutingMessage rm) {
_routingHandling = r;
routingMessage = rm;
this.run();
}
public void run() {
handleMessage();
}
private void handleMessage() {
// do some stuff and extract data from the routing message object
_routingHandling.writeMessage(somethingToSetAsKey, somethingToSetAsValue)
}
}

Categories

Resources