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;
}
Related
public abstract class CommonClass {
abstract void send(<what should i put here???>) {}
}
public class ClassA extends CommonClass {
void send(List<Comments> commentsList) {
// do stuff
}
}
public class ClassB extends CommonClass {
void send(List<Post> postList) {
// do stuff
}
}
I am new to OODP, I am trying to have a method that is able to take in any kind of List data so that I can abstract things out. How can i do this?
You could make it generic on some type T. Like,
public abstract class CommonClass<T> {
abstract void send(List<T> al);
}
And then, to implement it - use the generic. Like,
public class ClassA extends CommonClass<Comments> {
#Override
void send(List<Comments> commentsList) {
// do stuff
}
}
public class ClassB extends CommonClass<Post> {
#Override
void send(List<Post> postList) {
// do stuff
}
}
Also, as discussed in the comments, your class names could be improved to be more intuitive; something like,
public abstract class AbstractSender<T> {
abstract void send(List<T> al);
}
and then
public class CommentSender extends AbstractSender<Comment> {
#Override
void send(List<Comment> commentsList) {
// do stuff
}
}
public class PostSender extends AbstractSender<Post> {
#Override
void send(List<Post> postList) {
// do stuff
}
}
That has the advantage(s) of being more readable and easier to reason about (I can tell what a PostSender does by reading the name, ClassB not so much).
Finally, this looks like a case where an interface would work since your abstract class is purely virtual (and should be preferred since you can implement multiple interface, but can only extend from a single parent class);
public interface ISender<T> {
void send(List<T> al);
}
public class CommentSender implements ISender<Comment> {
#Override
void send(List<Comment> commentsList) {
// do stuff
}
}
public class PostSender implements ISender<Post> {
#Override
void send(List<Post> postList) {
// do stuff
}
}
In order to achieve this, you can take multiple approaches, I would suggest looking into Generics: https://docs.oracle.com/javase/tutorial/java/generics/index.html
With that said, there is one approach that is the most elegant and simple: you can supply a List<T> where T is a generic type.
public abstract class CommonClass<T> {
abstract void send(List<T>) {}
}
public class ClassA extends CommonClass<Comment> {
void send(List<Comments> commentsList) {
// do stuff
}
}
public class ClassB extends CommonClass<Post> {
void send(List<Post> postList) {
// do stuff
}
}
You can do that with the help of generics. https://www.tutorialspoint.com/java/java_generics.htm
Example
The abstract class
public abstract class CommonClass {
public abstract <T> void send(List<T> data);
}
Its child
public class Child extends CommonClass {
public <T> void send(List<T> data) {
// code here
}
}
Retrieving the list's contents
Retrieving the generified list's contents is similar to retrieving any list's contents. In the scope of the method, "T" is a type of object contained in the list.
for (T t : data) {
// to check if t is a string
if (t instanceof String) {
// code
}
}
You can also use lambdas to retrieve every element in the list.
I have below code. As you can see I am executing similar logic but once for Bike and once for Car. Can I make use for <K> to reduce duplicate looking code? I have not used <K> so I am not sure where and how exactly I can incorporate it. Where can I make the decision whether to call getCarsWithFeature or getBikesWithFeature?
Is it best practice to reduce number of lines (may make it less readable) or to have such duplicate-looking code?
public Set<Car> getPremiumCars(String filter) {
final Callable<Set<Car>> retryGetCars = new RetryingCallable<>(retryStrategy(), getCars(filter));
return retryGetCars.call();
}
public Callable<Set<Car>> getCars(String feature) {
return new Callable<Set<Car>>() {
#Override
public Set<Car> call() throws Exception {
Set<Car> cars = getCarsWithFeature(feature);
return Collections.unmodifiableSet(cars);
}
};
}
public Set<Bike> getPremiumBikes(String filter) {
final Callable<Set<Bike>> retryGetBikes = new RetryingCallable<>(retryStrategy(), getBikes(filter));
return retryGetBikes.call();
}
public Callable<Set<Bike>> getBikes(String feature) {
return new Callable<Set<Bike>>() {
#Override
public Set<Bike> call() throws Exception {
Set<Bike> bikes = getBikesWithFeature(feature);
return Collections.unmodifiableSet(bikes);
}
};
}
I do not know your whole code, but I would suggest for both classes to implement same interface - let's say Vehicle:
public interface Vehicle {
}
Then you could write code that lately you can reuse:
public <T extends Vehicle> Set<T> getPremiumVehicle(Function<String, Callable<Set<T>>> vehicleSupplier, String filter) throws Exception {
final Callable<Set<T>> retryGetCars = new RetryingCallable<T>(retryStrategy(), vehicleSupplier.apply(filter));
return retryGetCars.call();
}
public <T extends Vehicle> Callable<Set<T>> getVehicle(Function<String, Set<T>> vehicleSupplier, String feature) {
return () -> {
Set<T> vehicles = vehicleSupplier.apply(feature);
return Collections.unmodifiableSet(vehicles);
};
}
Now, you could reuse above code, like:
public Set<Car> getPremiumCars(String filter) throws Exception {
return getPremiumVehicle(this::getCars, filter);
}
public Set<Bike> getPremiumBikes(String filter) throws Exception {
return getPremiumVehicle(this::getBikes, filter);
}
public Callable<Set<Car>> getCars(String feature) {
return getVehicle(this::getCarsWithFeature, feature);
}
public Callable<Set<Bike>> getBikes(String feature) {
return getVehicle(this::getBikesWithFeature, feature);
}
Create a base class of Car and Bike, then put the common method there.
Then extend the Car and Bike from it. Update the common method using the base class. Sample hints for the implementation is given below:
class Vehicle {
public Set<Vehicle> getWithFilter(String filter) {
final Callable<Set<Vehicle>> retryGet = new RetryingCallable<>(retryStrategy(), get(filter));
return retryGet.call();
}
public Callable<Set<Vehicle>> getWithFeature(String feature) {
return new Callable<Set<Vehicle>>() {
public Set<Vehicle> call() throws Exception {
Set<Vehicle> vehicles = getWithFeature(feature);
return Collections.unmodifiableSet(vehicles);
}
};
}
}
class Car extends Vehicle {
}
class Bike extends Vehicle {
}
Now to call use:
Car car = new Car();
car.getWithFilter(/* Pass parameter*/);
Bike bike = new Bike();
bike.getWithFilter(/* Pass parameter*/);
I have a problem with the different type of objects in a collection, in that case ArrayList, here there is an example:
public interface CustomObject {}
public class CustomObjectA implements CustomObjects {}
public class CustomObjectB implements CustomObjects {}
In the main I call myMethod:
ArrayList<CustomObject> list = new ArrayList<>();
for(int i=0; i < list.size(); i++) {
myMethod(list.get(i));
}
myMethod is defined with an overloading as written below:
public void myMethod(CustomObjectA a) { ... }
public void myMethod(CustomObjectB b) { ... }
There is a compile-error. How can I solve? What's the right way to it (Collections, generics, wildcard ?)
One way to work around this is the use of the visitor pattern, which allows you to attach functionality, without touching your domain objects
// A visitor, which can 'visit' all your types
interface CustomObjectVisitor {
void visitA(CustomObjectA a);
void visitB(CustomObjectB b);
}
// Make CustomObject a visitee
public interface CustomObject {
void accept(CustomObjectVisitor visitor);
}
// Implement the classes with the accept method
public class CustomObjectA implements CustomObject {
#Override public void accept(CustomObjectVisitor visitor) {
visitor.visitA(this);
}
}
public class CustomObjectB implements CustomObject {
#Override public void accept(CustomObjectVisitor visitor) {
visitor.visitB(this);
}
}
Now you can make your Main class a visitor like this:
public class Main implements CustomObjectVisitor {
public void methodThatDidntWorkBefore() {
ArrayList<CustomObject> list = new ArrayList<>();
for(CustomObject obj: list) {
obj.accept(this);
}
}
#Override public void visitA(CustomObjectA a) { ... }
#Override public void visitB(CustomObjectB b) { ... }
}
Check out WikiPedia too, it's really useful once you wrap your head around it.
With:
public interface CustomObject { void myMethod(); }
public class CustomObjectA implements CustomObjects {
#Override
public void myMethod() {...}
}
public class CustomObjectB implements CustomObjects {
#Override
public void myMethod() {...}
}
Then:
ArrayList<CustomObject> list = new ArrayList<>();
for(int i=0; i < list.size(); i++) {
list.get(i).myMethod(); // invoke dynamic
}
Which will execute the method corresponding to what the object's dynamic type is.
e.g. If get(i) returns an object with a dynamic type of CustomObjectA it will execute CustomObjectA::myMethod.
You could try something like this:
public class myMethodClass {
public static void main(String[] args) {
ArrayList<CustomObject> list = new ArrayList<>();
for(int i=0; i < list.size(); i++) {
myMethod(list.get(i));
}
}
public static void myMethod(CustomObject o){
if(o instanceof CustomObjectA) myMethod((CustomObjectA) o);
if(o instanceof CustomObjectB) myMethod((CustomObjectB) o);
}
public static void myMethod(CustomObjectA a) { }
public static void myMethod(CustomObjectB b) { }
}
interface CustomObject {}
class CustomObjectA implements CustomObject {}
class CustomObjectB implements CustomObject {}
I'm developing a database application for android devices.
First thing I need to do is creating the data access layer.
For this I want to use DAO-Pattern with abstract factories.
For all DAOs i have one Interface witch contains the declaration that all data object needs to implement. (in my case: IDataObject)
The specific DAOs are all represented by its own interface, extending the base interface of all DAOs.
base interface:
public interface IDataObject {
public IDataId getId();
public void write() throws MyDataWriteException;
public void validate() throws MyDataValidException;
}
a extensions:
public interface IDataSample1 extends IDataObject {
public void setNotice(String notice);
public String getNotice();
public void setDate(Date date);
public Date getDate();
}
To create an data object I want use abstract to use abstract factories, something like:
public interface IDataFactory<Template extends IDataObject> {
public List<Template> getAll();
public Template get(IDataId id);
public List<Template> getList(DataAccessArgument arg);
public List<Template> getList(List<DataAccessArgument> argList);
}
and the implementation:
public class DataSample1Fac implements IDataFactory<IDataSample1> {
public DataSample1Fac () {
}
public List<IDataSample1> getAll() {
return null;
}
public IDataSample1 get(IDataId id) {
return null;
}
public List<IDataSample1> getList(DataAccessArgument arg) {
return null;
}
public List<IDataSample1> getList(List<DataAccessArgument> argList) {
return null;
}
}
I don't get any error so far, but now I want to implement an factory builder:
public class DataFactoryBuilder {
private DataFactoryBuilder() {
}
public static<T extends IDataObject> IDataFactory<T> getFactory(){
if (T instanceof IDataSample1)
return new DataSample1Fac();
return null;
}
}
I get following errors(line 8):
T cannot be resolved to a variable
and (line 9)
Type mismatch: cannot convert from DataSample1Fac to IDataFactory<T>
Don't know how to fix this, any suggestions?
I would refactor Your's DataFactoryBuilder to something like that:
class DataFactoryBuilder {
private DataFactoryBuilder() {
}
public static IDataFactory<? extends IDataObject> getFactory(Class<? extends IDataObject> clazz){
if (IDataSample1.class.isAssignableFrom(clazz)) {
return new DataSample1Fac();
}
return null;
}
}
I got following solution:
public static <T extends IDataObject> IDataFactory<T> getFactory(Class<T> type) {
if (IDataSample1.class.isAssignableFrom(type)) {
DataSample1Facfac = new DataSample1Fac();
return (IDataFactory<T>) fac;
}
}
but i get an warning on: return (IDataFactory) fac;
Type safety: Unchecked cast from DataSample1Fac to IDataFactory<T>
I think that is not a problem, I just have to supress it
I have an third-party RPC-API that provides an interface similar to that of java.sql.ResultSet (for reading values) and java.sql.PreparedStatement (for writing values). Assume it looks something like this:
public interface RemoteDeviceProxy {
public void setBoolean(Boolean value);
public void setInteger(Integer value);
// ...
public Boolean getBoolean();
public Integer getInteger();
// ...
}
I want to write a wrapper for this API that uses generics to create instances of specific types:
public class <T> RemoteVariable {
private final RemoteDeviceProxy wrappedDevice;
public RemoteVariable(RemoteDeviceProxy wrappedDevice) {
this.wrappedDevice = wrappedDevice;
}
public T get() {
// should call wrappedDevice.getBoolean() if T is Boolean, etc.
// how to implement?
}
public void set(T newValue) {
// should call wrappedDevice.setBoolean(newValue) if T is Boolean, etc.
// implement using instanceof
}
}
How can I implement the getter in my generic wrapper? I have found this answer which explains a similar scenario in depth, but I am not able to transfer this to my problem. Specifically, when I write this:
public T get() {
Type[] actualTypeArguments = ((ParameterizedType) getClass())
.getActualTypeArguments();
}
I get a compiler error saying I cannot cast to ParameterizedType, and I do not understand why. Can anyone explain how to achieve this?
Here is one way:
public class <T> RemoteVariable {
private final RemoteDeviceProxy wrappedDevice;
private final Class<T> clazz;
public RemoteVariable(RemoteDeviceProxy wrappedDevice, Class<T> clazz) {
this.wrappedDevice = wrappedDevice;
this.clazz = clazz;
}
public T get() {
if(clazz == Boolean.class){return clazz.cast(wrappedDevice.getBoolean());}
else if(clazz == Integer.class){return clazz.cast(wrappedDevice.getInteger());}
// ...
}
// ...
}
I thought over this quite a while and finally came up with a different approach:
First I added a getter to you RemoteVariable class:
protected RemoteDeviceProxy getWrappedProxy() {
return wrappedProxy;
}
Second I created a builder interface that will be used by a factory later:
public interface RemoteVariableBuilder {
public <T> RemoteVariable<T> buildNewVariable(RemoteDeviceProxy wrappedProxy);
}
Then I created non generic sub classes for Boolean...
public class RemoteBooleanVariable extends RemoteVariable<Boolean> implements RemoteVariableBuilder {
public RemoteBooleanVariable(RemoteDeviceProxy wrappedProxy) {
super(wrappedProxy);
}
#SuppressWarnings("unchecked")
#Override
public <T> RemoteVariable<T> buildNewVariable(RemoteDeviceProxy wrappedProxy) {
return (RemoteVariable<T>) new RemoteBooleanVariable(wrappedProxy);
}
#Override
public Boolean get() {
return getWrappedProxy().getBoolean();
}
#Override
public void set(Boolean value) {
getWrappedProxy().setBoolean(value);
}
}
... and Integer ...
public class RemoteIntegerBuilder extends RemoteVariable<Integer> implements RemoteVariableBuilder {
public RemoteIntegerBuilder(RemoteDeviceProxy wrappedProxy) {
super(wrappedProxy);
}
#SuppressWarnings("unchecked")
#Override
public <T> RemoteVariable<T> buildNewVariable(RemoteDeviceProxy wrappedProxy) {
return (RemoteVariable<T>) new RemoteIntegerBuilder(wrappedProxy);
}
#Override
public Integer get() {
return getWrappedProxy().getInteger();
}
#Override
public void set(Integer value) {
getWrappedProxy().setInteger(value);
}
}
actually eclipse created most of the code once it knew base class and interface.
The final step was to create a factory
public class RemoteVariableFactory {
private static final Map<String, RemoteVariableBuilder> BUILDERS = new HashMap<>();
static {
BUILDERS.put(Boolean.class.getName(), new RemoteBooleanVariable(null));
BUILDERS.put(Integer.class.getName(), new RemoteIntegerBuilder(null));
// add more builders here
}
public static <T> RemoteVariable<T> getRemoteVariable(RemoteDeviceProxy wrappedProxy, Class<T> typeClass) {
RemoteVariableBuilder remoteVariableBuilder = BUILDERS.get(typeClass.getName());
if (remoteVariableBuilder == null) {
return null; // or throw an exception whichever is better in your case
}
return remoteVariableBuilder.buildNewVariable(wrappedProxy);
}
}
Now we are ready to create new RemoteVariables...
RemoteVariable<Boolean> var1 = RemoteVariableFactory.getRemoteVariable(new RemoteDevice(), Boolean.class);
RemoteVariable<Integer> var2 = RemoteVariableFactory.getRemoteVariable(new RemoteDevice(), Integer.class);
To conclude this let's do a quick comparison to the answer of Eng.Fouad:
Disadvantage:
you need to create a new class for every datatype you provide
Advantage:
you only have to add one line to the static block of the factory and not two new if blocks to the getter and setter in RemoteVariable
get and set do not have to work through the if-else-blocks every time