Small question regarding the diamond operator and design pattern strategy for Java, please.
I would like to implement a very specific requirement:
there are some objects to store (in my example called MyThingToStore)
and the requirement is to store them with different kinds of data structures, for comparison.
Therefore, I went to try with a strategy pattern, where each of the strategies is a different way to store, I think this pattern is quite lovely.
The code is as follows:
public class MyThingToStore {
private final String name;
public MyThingToStore(String name) {
this.name = name;
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
MyThingToStore that = (MyThingToStore) o;
return Objects.equals(name, that.name);
}
#Override
public int hashCode() {
return Objects.hash(name);
}
#Override
public String toString() {
return "MyThingToStore{" +
"name='" + name + '\'' +
'}';
}
}
public class MyStorage {
private final StorageStrategy storageStrategy;
public MyStorage(StorageStrategy storageStrategy) {
this.storageStrategy = storageStrategy;
}
public void addToStore(MyThingToStore myThingToStore) {
storageStrategy.addToStore(myThingToStore);
}
public int getSize() {
return storageStrategy.getSize();
}
}
public interface StorageStrategy {
void addToStore(MyThingToStore myThingToStore);
int getSize();
}
public class StorageUsingArrayListStrategy implements StorageStrategy {
private final List<MyThingToStore> storeUsingArrayList = new ArrayList<>();
#Override
public void addToStore(MyThingToStore myThingToStore) {
storeUsingArrayList.add(myThingToStore);
}
#Override
public int getSize() {
return storeUsingArrayList.size();
}
}
public class StorageUsingHashSetStrategy implements StorageStrategy{
private final Set<MyThingToStore> storeUsingHashSet = new HashSet<>();
#Override
public void addToStore(MyThingToStore myThingToStore) {
storeUsingHashSet.add(myThingToStore);
}
#Override
public int getSize() {
return storeUsingHashSet.size();
}
}
public class Main {
public static void main(String[] args) {
final StorageStrategy storageStrategy = new StorageUsingArrayListStrategy();
final MyStorage myStorage = new MyStorage(storageStrategy);
myStorage.addToStore(new MyThingToStore("firstItem"));
myStorage.addToStore(new MyThingToStore("duplicatedSecondItem"));
myStorage.addToStore(new MyThingToStore("duplicatedSecondItem"));
System.out.println(myStorage.getSize()); //changing strategy will return a different size, working!
}
}
And this is working fine, very happy, especially tackled the requirement "easy to change the data structure to do the actual store".
(By the way, side question, if there is an even better way to do this, please let me know!)
Now, looking online at different implementations of strategy patterns, I see this diamond operator which I am having a hard time understanding:
MyThingToStore stays the same.
public class MyStorage {
private final StorageStrategy<MyThingToStore> storageStrategy; //note the diamond here
public MyStorage(StorageStrategy<MyThingToStore> storageStrategy) {
this.storageStrategy = storageStrategy;
}
public void addToStore(MyThingToStore myThingToStore) {
storageStrategy.addToStore(myThingToStore);
}
public int getSize() {
return storageStrategy.getSize();
}
#Override
public String toString() {
return "MyStorage{" +
"storageStrategy=" + storageStrategy +
'}';
}
}
public interface StorageStrategy<MyThingToStore> {
//note the diamond, and it will be colored differently in IDEs
void addToStore(MyThingToStore myThingToStore);
int getSize();
}
public class StorageUsingArrayListStrategy implements StorageStrategy<MyThingToStore> {
private final List<MyThingToStore> storeUsingArrayList = new ArrayList<>();
#Override
public void addToStore(MyThingToStore myThingToStore) {
storeUsingArrayList.add(myThingToStore);
}
#Override
public int getSize() {
return storeUsingArrayList.size();
}
}
public class StorageUsingHashSetStrategy implements StorageStrategy<MyThingToStore> {
private final Set<MyThingToStore> storeUsingHashSet = new HashSet<>();
#Override
public void addToStore(MyThingToStore myThingToStore) {
storeUsingHashSet.add(myThingToStore);
}
#Override
public int getSize() {
return storeUsingHashSet.size();
}
}
public class Main {
public static void main(String[] args) {
final StorageStrategy<MyThingToStore> storageStrategy = new StorageUsingArrayListStrategy();
final MyStorage myStorage = new MyStorage(storageStrategy);
myStorage.addToStore(new MyThingToStore("firstItem"));
myStorage.addToStore(new MyThingToStore("duplicatedSecondItem"));
myStorage.addToStore(new MyThingToStore("duplicatedSecondItem"));
System.out.println(myStorage.getSize()); //changing strategy will return a different size, working!
}
}
And both versions will yield the same good result, also be able to answer requirements.
My question is: what are the differences between the version without a diamond operator, and the version with the diamond operator, please?
Which of the two ways are "better" and why?
While this question might appear to be "too vague", I believe there is a reason for a better choice.
I think the confusion comes from how you named type parameter for StorageStrategy in your 2nd example.
Let's name it T for type instead. T in this case is just a placeholder to express what type of objects your StorageStrategy can work with.
public interface StorageStrategy<T> {
void addToStore(T myThingToStore);
int getSize();
}
E.g.
StorageStrategy<MyThingToStore> strategy1 = // Initialization
StorageStrategy<String> strategy2 = // Initialization
strategy1.addToStore(new MyThingToStore("Apple"));
// This works fine, because strategy2 accepts "String" instead of "MyThingToStore"
strategy2.addToStore("Apple");
// Last line doesn't work, because strategy1 can only handle objects of type "MyThingToStore"
strategy1.addToStore("Apple");
To make it work properly, you need to change your different StorageStrategy implementations to also include the type parameter.
public class StorageUsingHashSetStrategy<T> implements StorageStrategy<T> {
private final Set<T> storeUsingHashSet = new HashSet<>();
#Override
public void addToStore(T myThingToStore) {
storeUsingHashSet.add(myThingToStore);
}
#Override
public int getSize() {
return storeUsingHashSet.size();
}
}
And lastly you also want to have a type paremeter for MyStorage
public class MyStorage<T> {
private final StorageStrategy<T> storageStrategy;
public MyStorage(StorageStrategy<T> storageStrategy) {
this.storageStrategy = storageStrategy;
}
public void addToStore(T myThingToStore) {
storageStrategy.addToStore(myThingToStore);
}
public int getSize() {
return storageStrategy.getSize();
}
}
Now you can create a MyStorage and can use it to store essentially any object into it and not just MyThingToStore. Whether that is something you want or not is up to you.
In the second code sample in the declaration of the interface StorageStrategy<MyThingToStore>, MyThingToStore is a Type Variable.
I.e. it's not the actual type, only a placeholder for a type, like T. The common convention is to use single-letter generic type variables (T, U, R, etc.), otherwise it might look confusing like in this case.
Note that in the class declarations, like:
public class StorageUsingArrayListStrategy
implements StorageStrategy<MyThingToStore>
MyThingToStore is no longer a type variable, but the name of the class MyThingToStore because in this case parameterized interface is implemented by a non-parameterized class (i.e. the actual type known to the compile is expected to be provided).
Related
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
Hi I'm new to java and I currently have two classes(useForce and Attack) that are working fine but these two classes share a lot of code.To reduce duplicated code I extended use Force class from Attack class but I'm not sure how to modify the code?
For example in my attack.java
public class Attack extends SWAffordance implements SWActionInterface {
some code here...
#Override
public boolean canDo(SWActor a) {
SWEntityInterface target = this.getTarget();
return !a.isDead() && target.getHitpoints()>0;
}
#Override
public void act(SWActor a) {
SWEntityInterface target = this.getTarget();
boolean targetIsActor = target instanceof SWActor;
SWActor targetActor = null;
int energyForAttackWithWeapon = 1;//the amount of energy required to attack with a weapon
if (targetIsActor) {
targetActor = (SWActor) target;
}
But the same two methods in my useForce.java is
public class UseForce extends Attack {
some code here....
#Override
public boolean canDo(SWActor a) {
return a.getForcepoints()>=minUsePoints;
}
#Override
public void act(SWActor a) {
SWEntityInterface target = this.getTarget();
boolean targetIsActor = target instanceof SWActor;
SWActor targetActor = null;
int energyForForceAttack = 2;//the amount of energy required to use force
if (targetIsActor) {
targetActor = (SWActor) target;
}
As you can see these two share many similar lines of code in act method except in Attack.java int energyForAttackWithWeapon = 1 whereas in useForce int energyforAttackWithWeapon=2...
How do I use super or override to reduce the lines of duplicated code?Any help will be appreciated.
EDIT:If I use a thirdparty class to extract the duplicated code, how do I do it because Attack already extends from SWAffordance?
The template method pattern could help to solve your duplication issue.
It allows to define a common algorithm in a base class while leaving the subclasses to custom some parts of the algorithm.
So define both common concrete operations and custom operations to define by subclasses in an abstract class : AbstractAttack.
public abstract class AbstractAttack extends SWAffordance implements SWActionInterface {
public abstract int getEnergyForAttack();
public abstract boolean canDo(SWActor a);
public void act(SWActor a) {
SWEntityInterface target = this.getTarget();
boolean targetIsActor = target instanceof SWActor;
SWActor targetActor = null;
int energyForAttack = getEnergyForAttack();
... // use energyForAttack
if (targetIsActor) {
targetActor = (SWActor) target;
}
}
}
Now Attack and Other subclasses inherit from AbstractAttack to benefit from concrete operations and also implement theirs own specificities :
public class DefaultAttack extends AbstractAttack {
#Override
public boolean canDo(SWActor a) {
SWEntityInterface target = this.getTarget();
return !a.isDead() && target.getHitpoints()>0;
}
#Override
public int getEnergyForAttack(){
return 1;
}
}
public class UseForce extends AbstractAttack {
#Override
public boolean canDo(SWActor a) {
return a.getForcepoints()>=minUsePoints;
}
#Override
public int getEnergyForAttack(){
return 2;
}
}
I have a class hierarchy like below
Vehicle
|_ TransaportationVehicle has method getLoadCapacity
|_ PassengerVehicle has method getPassengerCapacity
and I have one more class Booking it have a reference to Vehicle.
Now whenever I have to call getPassengerCapacity or getLoadCapacity on vehicle reference I need to type cast vehicle to its concrete implementation like ((PassengerVehicle)vehicle).getPassengerCapacity() and this type of calls spans over multiple parts in the project. So is there any way with which I can avoid these type of casts and my code will look beautiful and clean?
Note: These are not actual classes I have taken these as an example to demonstrate current problem.
Obviously, when booking a Vehicle you need to distinguish at some point whether it’s a TransportationVehicle or a PassengerVehicle as both have different properties.
The easiest way would be to initiate two different Booking processes: one for vehicles that can transport goods, and one for vehicles that can transport passengers. As for how to differentiate between these two types of vehicles: you could add canTransportPassengers() and canTransportGoods() methods to Vehicle, the subclasses would then override these methods to return true where appropriate. Also, this way a vehicle that can transport both is possible, like a train.
If You want to use different method names then You must cast to concrete class.
But if You can make this methods return same type value and have same names You can use polymorphism for it. Create abstract method in Vehicle class and override it in each child.
A quick way I would accomplish this is to create a Generified Booking parent class.
public abstract class Booking<V extends Vehicle> {
protected abstract V getVehicle();
}
public class TransportationVehicleBooking extends Booking<TransaportationVehicle> {
#Override
protected TransaportationVehicle getVehicle() {
return new TransaportationVehicle();
}
}
public class PassengerVehicleBooking extends Booking<PassengerVehicle> {
#Override
protected PassengerVehicle getVehicle() {
return new PassengerVehicle();
}
}
Your Booking class will have all the logic that spans all the booking subclasses and some abstract method each subclasses will need to do effective calculations.
Then all you have to do is have reference to a Booking class and calling the relevant method required without having to worry about the "logistics" (get it) of the booking itself.
I hope this helps.
You method overriding concepts. You need to have all these method in the Parent class and same can be overriden in the child clasees.
You can then access all the methods from super class using Runtime polymorphism
Vehicle
public interface Vehicle {
public int getCapacity();
}
TransaportationVehicle
public class TransaportationVehicle implements Vehicle {
#Override
public int getCapacity() {
return getLoadCapacity();
}
private int getLoadCapacity() {
return 0;
}
}
PassengerVehicle
public class PassengerVehicle implements Vehicle {
#Override
public int getCapacity() {
return getPassengerCapacity();
}
private int getPassengerCapacity() {
return 0;
}
}
USAGE
Vehicle passenger = new PassengerVehicle();
passenger.getCapacity();
Vehicle transaportation = new TransaportationVehicle();
transaportation.getCapacity()
First try to extract an abstract method suitable for all vehicles. If you can't do this you can also use an often forgotten pattern - the visitor pattern. E.g.
Introduce a visitor interface
public interface VehicleVisitor {
public void visit(TransportationVehicle transportationVehicle);
public void visit(PassengerVehicle passengerVehicle);
}
add an accept method to the Vehicle
public interface Vehicle {
public void accept(VehicleVisitor visitor);
}
implement the accept method in the sub classes
public class PassengerVehicle implements Vehicle {
private int passengerCapacity;
public static PassengerVehicle withPassengerCapacity(int passengerCapacity) {
return new PassengerVehicle(passengerCapacity);
}
private PassengerVehicle(int passengerCapacity) {
this.passengerCapacity = passengerCapacity;
}
public int getPassengerCapacity() {
return passengerCapacity;
}
#Override
public void accept(VehicleVisitor visitor) {
visitor.visit(this);
}
}
public class TransportationVehicle implements Vehicle {
private int loadCapacity;
public static TransportationVehicle withLoadCapacity(int loadCapacity) {
return new TransportationVehicle(loadCapacity);
}
private TransportationVehicle(int loadCapacity) {
this.loadCapacity = loadCapacity;
}
public int getLoadCapacity() {
return loadCapacity;
}
#Override
public void accept(VehicleVisitor visitor) {
visitor.visit(this);
}
}
implement a visitor...
public class LoadSupported implements VehicleVisitor {
private boolean supported;
private int load;
public LoadSupported(int load) {
this.load = load;
}
public boolean isSupported() {
return supported;
}
#Override
public void visit(TransportationVehicle transportationVehicle) {
int loadCapacity = transportationVehicle.getLoadCapacity();
supported = load <= loadCapacity;
}
#Override
public void visit(PassengerVehicle passengerVehicle) {
supported = false;
}
}
...and use it
public class Main {
public static void main(String[] args) {
TransportationVehicle transportationVehicle1 = TransportationVehicle
.withLoadCapacity(5);
TransportationVehicle transportationVehicle2 = TransportationVehicle
.withLoadCapacity(10);
PassengerVehicle passengerVehicle = PassengerVehicle
.withPassengerCapacity(5);
LoadSupported loadSupported = new LoadSupported(7);
supportsLoad(transportationVehicle1, loadSupported);
supportsLoad(transportationVehicle2, loadSupported);
supportsLoad(passengerVehicle, loadSupported);
}
private static void supportsLoad(Vehicle vehicle,
LoadSupported loadSupported) {
vehicle.accept(loadSupported);
System.out.println(vehicle.getClass().getSimpleName() + "[" + System.identityHashCode(vehicle) + "]" + " does"
+ (loadSupported.isSupported() ? " " : " not ")
+ "support load capacity");
}
}
The output will be something like this
TransportationVehicle[778966024] does not support load capacity
TransportationVehicle[1021653256] does support load capacity
PassengerVehicle[1794515827] does not support load capacity
Assuming that passenger capacity is always an integer and load capacity could very well a big number depending on what is the unit for load. I would go ahead and create Vehicle class as follow:
class Vehicle {
Number capacity;
public Number getCapacity() {
return capacity;
}
public void setCapacity(Number capacity) {
this.capacity = capacity;
}
}
The reason I am using Number is so that I then use Integer in PassengerVehicle class and Double in TransporatationVehicle and that is because Integer and Double are subtype of Number and you can get away with a cast.
class TransportationVehicle extends Vehicle {
#Override
public Double getCapacity() {
//all I have to do is cast Number to Double
return (Double) capacity;
}
#Override
public void setCapacity(Number capacity) {
this.capacity = capacity;
}
}
Similarly the PassengerVehicle class as follow:
class PassengerVehicle extends Vehicle {
#Override
public Integer getCapacity() {
//Cast to Integer and works because Integer is subtype of Number
return (Integer) capacity;
}
#Override
public void setCapacity(Number capacity) {
this.capacity = capacity;
}
}
You can then use above classes to create vehicle object as follow:
public class Booking {
public static void main(String[] args) {
//
Vehicle transportationVehicle = new TransportationVehicle();
//assigning Double to setCapacity
transportationVehicle.setCapacity(new Double(225.12));
Vehicle passengerVehicle = new PassengerVehicle();
//assigning Integer to setCapacity
passengerVehicle.setCapacity(5);
System.out.println(transportationVehicle.getCapacity());
// output: 225.12
System.out.println(passengerVehicle.getCapacity());
// output: 5
}
}
On the side notes if you try to pass TransportationVehicle anything but Number or Double then you will get Exception and similarly if you pass PassengerVehicle anything but Number or Integer you will get exception.
I know that I am deviating from the scope of your question but, I really want to show how you can make your methods generics. This allow you to decide to return type of getCapacity() during coding which is very flexible. See below:
class Vehicle<T> {
//generic type T
T capacity;
//generic method getCapacity
public T getCapacity() {
return capacity;
}
//generic method setCapacity
public void setCapacity(T capacity) {
this.capacity = capacity;
}
}
class TransportationVehicle<T> extends Vehicle<T> {
#Override
public T getCapacity() {
return capacity;
}
#Override
public void setCapacity(T capacity) {
this.capacity = capacity;
}
}
class PassengerVehicle<T> extends Vehicle<T> {
#Override
public T getCapacity() {
return capacity;
}
#Override
public void setCapacity(T capacity) {
this.capacity = capacity;
}
}
As you can see above the generic methods and you can use them as follow:
Vehicle<String> vehicleString = new TransportationVehicle<String>();
vehicleString.setCapacity("Seriously!"); //no problem
Vehicle<Integer> vehicleInteger = new PassengerVehicle<Integer>();
vehicleInteger.setCapacity(3); //boxing done automatically
Vehicle<Double> vehicleDouble = new PassengerVehicle<Double>();
vehicleDouble.setCapacity(2.2); //boxing done automatically
You can decide the type while coding and if you supply a Vehicle<String> with capacity as Integer then you will get compile time error, so you won't be allowed.
System.out.println(vehicleString.getCapacity());
//output: Seriously!
System.out.println(vehicleInteger.getCapacity());
//output: 3
System.out.println(vehicleDouble.getCapacity());
//output: 2.2
I don't understand the example. How do you realize that you are dealing with a concrete type in the first place? Are you instanceOf-ing? Are you type matching?
If so your problem is way past casting...
Anyways when you have objects that must belong to the same family and algorithms which are not abstract and change according to the object being handled you typically use some sort of behavioral pattern like visitor, or the Bridge pattern.
In a Java class that belongs in a library, I have a field size that indicates size of image. It must be int, but some values are depending to devices, so other developers can set various types for it:
thumbnail (value depends on device)
real size (value depends on device)
custom (arbitrary integer)
I want to restrict other developers (that use this library) to set value of size with one option from set of specific and meaningful options.My purpose is to show list of legal options to developer and also type safety, like Enum. But I think it is impossible to do that only by enum, so I create an interface and some classes:
public interface SizeMode {
}
public enum DevicePreDefinedImageSizeMode implements SizeMode {
THUMBNAIL, REAL_SIZE
}
public enum CustomImageSizeMode implements SizeMode {
CUSTOM_SIZE
}
public abstract class Size {
private final SizeMode mode;
public SizeMode getMode() {
return mode;
}
public abstract int getDownSampleFactor();
protected Size(SizeMode mode) {
this.mode = mode;
}
}
public class DevicePreDefinedImageSize extends Size {
public DevicePreDefinedImageSize(DevicePreDefinedImageSizeMode mode) {
super(mode);
}
#Override
public int getDownSampleFactor() {
throw new UnknownError("????");
}
}
public class CustomImageSize extends Size {
private final int downSampleFactor;
private CustomImageSize(CustomImageSizeMode mode, int downSampleFactor) {
super(mode);
this.downSampleFactor = downSampleFactor;
}
#Override
public int getDownSampleFactor() {
return downSampleFactor;
}
}
Now I can declare field size of type Size class and other developers are restricted to use one of sub classes of Size and initialize them with THUMBNAIL, REAL_SIZE or CUSTOM_SIZE.
But is there a better approach to achieve my purpose?
Another option is to use Size implementation that can only be created using set of static factory methods (or Builder pattern if you want):
public class Size {
private final int sampleFactor;
private Size(int sampleFactor) {
this.sampleFactor = sampleFactor;
}
public static Size thumbnail() {
return new Size(THUMBNAIL_FACTOR);
}
public static Size real() {
return new Size(REAL_FACTOR);
}
public static Size custom(int factor) {
return new Size(factor);
}
}
In java Enums are classes and they can have members.
public interface ISize {
public int getDownSampleSize();
}
enum Size implements ISize {
THUMBNAIL(THUMBNAIL_SIZE); // Defined elsewhere.
private int downSampleSize;
Size(int downSampleSize) {this.downSampleSize = downSampleSize;}
public int getDownSampleSize() {return downSampleSize;}
}
public class RealSize implements ISize {
public int getDownSampleSize() {return /* do something complicated */;}
}
public class CustomSize implements ISize {
private final int downSampleSize;
public CustomSize(int downSampleSize) {
this.downSampleSize = downSampleSize;
}
public int getDownSampleSize() {return downSampleSize;}
}
Then usage would be:
ISize s;
void resize() {
int downSampleSize = s.getDownSampleSize();
...
}
This is similar to what you did but a little cleaner. It saves you from having both Size and SizeMode.
I have a requirement that is close to extending enums and since that is not possible, after doing some research online, I came up with this approach of using interfaces and making the enums extend them.
My problem is that I have a few basic types A,B and a flag for each type that says if that has to be checked. Similarly I have some extended types C... which do the same stuff after checking their flags.
Here is the code that does this
Type Interface:
public interface Type {
public String name();
}
Here is the class that uses the basic types
public class BasicChecker {
private static boolean checkA = false;
private static boolean checkB = false;
public enum BasicType implements Type {
A, B;
}
public static boolean isCheckA() {
return checkA;
}
public static void setCheckA(boolean checkA) {
BasicChecker.checkA = checkA;
}
public static boolean isCheckB() {
return checkB;
}
public static void setCheckB(boolean checkB) {
BasicChecker.checkB = checkB;
}
public static void doStuff(String message, Type type) {
if (type.name().equalsIgnoreCase(BasicType.A.name())) {
doStuff(message, isCheckA());
} else if (type.name().equalsIgnoreCase(BasicType.B.name())) {
doStuff(message, isCheckB());
}
}
protected static void doStuff(String message, boolean flag) {
if (someCheckMethod() && flag) {
doStuff(message, flag);
}
}
private static boolean someCheckMethod() {
return false;
}
}
And this is the class that uses extended types
public class ExtendedChecker extends BasicChecker {
private static boolean checkC = false;
public enum ExtendedType implements Type {
C;
}
public static boolean isCheckC() {
return checkC;
}
public static void setCheckC(boolean checkC) {
ExtendedChecker.checkC = checkC;
}
public static void doStuff(String message, Type type) {
BasicChecker.doStuff(message, type);
if (type.name().equalsIgnoreCase(ExtendedType.C.name())) {
doStuff(message, isCheckC());
}
}
}
What I am trying to solve now is to remove all the if else cases from log method. I am also trying to see if there is a better way to do this. Please ignore the statics. I do want them to be static fields and methods.
I'm having trouble understanding exactly what you're trying to do from your description, but you may find abstract methods in enums to be useful.
For example, you could add an abstract method "foo" to your enums:
public enum BasicType implements Type {
A {
public void foo(String message) {
// Do special A stuff
}
}, B {
public void foo(String message) {
// Do special B stuff
}
};
public abstract void foo(String message);
}
And you could then use that method like this:
public static void doStuff(String message, Type type) {
type.foo(message);
}
Naturally, you could put any such abstract methods in an interface you extend, if that's useful.
public class BasicChecker {
private static final Set<Type> _doCheck = Collections.newSetFromMap(new ConcurrentHashMap<Type,Boolean>());
public enum BasicType implements Type {
A, B;
}
public static boolean isCheck(Type type) {
return return _doCheck.contains(type);
}
public static void setCheck(Type type, boolean check) {
if(check) {
_doCheck.add(type);
} else {
_doCheck.remove(type);
}
}
public static void doStuff(String message, Type type) {
doStuff(message, isCheck(type));
}
}