I have a question on how to call an objects base member when instantiated through an interface.
Suppose I have the following interface and concrete classes in a framework I am trying to build:
public interface UsedClass {
public boolean getBool();
}
public class User implements UsedClass {
private String userName;
private String userRole;
public User(String userName, String userRole){
this.userName = userName;
this.userRole = userRole;
}
public boolean getBool() {
// some code
}
public int getUserName() {
return userName;
}
public int getUserRole() {
return userRole;
}
And an implementing class:
public class Run implements UsedClass {
private String runName;
private int runNumber;
public Run(String runName, int runNumber){
this.runName = runName;
this.runNumber = runNumber;
}
public boolean getBool() {
// some code
}
public String getRunName() {
return runName;
}
public int getRunNumber() {
return runNumber;
}
}
But I cannot put methods getRunName() or getUserRole() into the interface!
The end goal is to create a FactoryClass to handle the objects passed from a database GUI.
I would like to know if there is a better way then using class reference be able to safely call methods of Run or User such as:
public class EntityFactory {
public static Object getValueAt(int rowIndex, int columnIndex, UsedClass usedClass) {
if (usedClass.getClass().getSimpleName().equals("User")) {
switch (columnIndex) {
case 0:
return ((User) usedClass).getUserName();
case 1:
return ((User) usedClass).getUserRole();
default:
return null;
}
} else if (usedClass.getClass().getSimpleName().equals("Run")) {
switch (columnIndex) {
case 0:
return ((Run) usedClass).getRunName();
case 1:
return ((Run) usedClass).getRunNumber();
default:
return null;
}
}
I have read several SO posts
type casting when objects are of interface references in Java and Java cast interface to class
where it is implied that reference casting is not advised, but since I cannot put all methods into the interface, what would be advised?
static interface ColumnSource<T> {
String getColumn(T value, int index);
}
static Map<Class, ColumnSource> map = new HashMap();
static {
map.put(User.class, new UserNameAndRoleSource<User>() {
public String getColumn(User user, int index) {
switch (index) {
case 0: return user.getUserName();
case 1: return user.getUserRole();
default: throw new RuntimeException();
}
}
});
map.put(Run.class, new ColumnSource<Run>() {
public String getColumn(Run run, int index) {
switch (index) {
case 0: return run.getRunName();
case 1: return run.getRunNumer();
default: throw new RuntimeException();
}
}
});
}
public static Object getValueAt(int rowIndex, int columnIndex, Object o) {
Class type = o.getClass();
ColumnSource source = map.get(type);
if (source == null) throw new RuntimeException(type.getName() + " not supported");
return source.getColumn(o, columnIndex);
}
You should use instanceof rather than looking at the simpleName of the class.
Beyond that you are correct. You either need to have an interface containing the common methods which you can then call them in or you need to identify that the object is an instance of a specific class and then do the cast and make the method call.
You could consider using a Map<Class<? extends UsedClass>, Map<Integer, Function<___>>> handlers.
Then your processing would be
handlers.get(usedClass.getClass()).get(columnIndex).apply(usedClass);
Obviously you would want to consider how to handle the unexpected class/index case. The inner Map<Integer,... could potentially be a List<...> depending on how it is being used.
Two things:
if at all, you use instanceof instead of string / class name comparison
you build your interfaces / classes to be helpful. They are the base of all the things you are doing. If you start with broken abstractions, you are broken. Simple as that.
What I mean is: if there is "common" behavior; then you should express that using a common interface. If not, you start your efforts on an already broken base; and you will be need to create "creative workarounds" all over the place in order to fight the symptoms of that disease.
Maybe one small solution could be to have at least multiple interfaces, like
interface UsedClass { ...
interface SpecialUsedClassA extends UsedClass { ...
interface SpecialUsedClassB extends UsedClass { ...
than you can at least return UsedClass instead of Object.
Related
In my program, the user needs to input what type of players the game will have. The players are "human", "good" (for a good AI), "bad" (for a bad AI) and "random" (for a random AI). Each of these players have their own class that extend one abstract class called PlayerType.
My struggle is mapping a String to the object so I can A) create a new object using the String as sort of a key and B) get the related String from an object of its subclass
Ultimately, I just want the implicit String to only appear once in the code so I can change it later if needed without refactoring.
I've tried using just a plain HashMap, but that seems clunky with searching the keys via the values. Also, I'm guessing that I'll have to use the getInstance() method of Class, which is a little less clunky, which is okay if it's the only way.
What I would do is create an enum which essentially functions as a factory for the given type.
public enum PlayerTypes {
GOOD {
#Override
protected PlayerType newPlayer() {
return new GoodPlayer();
}
},
BAD {
#Override
protected PlayerType newPlayer() {
return new BadPlayer();
}
},
RANDOM {
#Override
protected PlayerType newPlayer() {
return new RandomPlayer();
}
};
protected abstract PlayerType newPlayer();
public static PlayerType create(String input) {
for(PlayerTypes player : PlayerTypes.values()) {
if(player.name().equalsIgnoreCase(input)) {
return player.newPlayer();
}
}
throw new IllegalArgumentException("Invalid player type [" + input + "]");
}
)
Because then you can just call it like so:
String input = getInput();
PlayerTypes.create(input);
Of course, you'll get an IllegalArgumentException which you should probably handle by trying to get the input again.
EDIT: Apparently in this particular case, you can replace that loop with just merely
return PlayerTypes.valueOf(input).newPlayer();
And it'll do the same thing. I tend to match for additional constructor parameters in the enum, so I didn't think of using valueOf(), but it's definitely cleaner.
EDIT2: Only way to get that information back is to define an abstract method in your PlayerType class that returns the PlayerTypes enum for that given type.
public class PlayerType {
public abstract PlayerTypes getType();
}
public class GoodPlayer extends PlayerType {
#Override
public PlayerTypes getType() {
return PlayerTypes.GOOD;
}
}
I like the answer provided by Epic but I don't find maps to be clunky. So it's possible to keep a map and get the constructor call directly.
Map<String, Supplier<PlayerType> map = new HashMap<>();
map.put("human", Human::new);
Human h = map.get("human").get();
The two main options I can think of:
Using Class.newInstance(), as you mentioned (not sure if you had this exact way in mind):
// Set up your map
Map<String, Class> classes = new HashMap<String, Class>();
classes.put("int", Integer.class);
classes.put("string", String.class);
// Get your data
Object s = classes.get("string").newInstance();
You could use Class.getDeclaredConstructor.newInstance if you want to use a constructor with arguments (example).
Another option is using switch:
Object getObject(String identifier) {
switch (identifier) {
case "string": return new String();
case "int": return new Integer(4);
}
return null; // or throw an exception or return a default object
}
One potential solution:
public class ForFunFactory {
private ForFunFactory() {
}
public static AThing getTheAppropriateThing(final String thingIdentifier) {
switch (thingIdentifier) {
case ThingImplApple.id:
return new ThingImplApple();
case ThingImplBanana.id:
return new ThingImplBanana();
default:
throw new RuntimeException("AThing with identifier "
+ thingIdentifier + " not found.");
}
}
}
public interface AThing {
void doStuff();
}
class ThingImplApple implements AThing {
static final String id = "Apple";
#Override
public void doStuff() {
System.out.println("I'm an Apple.");
}
}
class ThingImplBanana implements AThing {
static final String id = "Banana";
#Override
public void doStuff() {
System.out.println("I'm a Banana.");
}
}
I have RecipientTypesFactory that is going to create objects of the type RecipientType. For RecipientTypes object I have the followin hierarchy:
public interface RecipientType{
public abstract Object accept(RecipientTypeVisitor v);
}
public class DynamicGroupType implemetns RecipientType{
private Integer dynamicGroupId;
public Object accept(RecipientTypeVisitor visitor){
return visitor.visit(this);
}
//GET, SET
}
public class StaticGroupType implements RecipientType{
private Integer staticGroupId;
public Object accept(RecipientTypeVisitor visitor){
return visitor.visit(this);
}
//GET, SET
}
RecipientTypesFactory itself looks as follows:
public enum RecipientTypeEnum {
STATIC_GROUP, DYNAMIC_GROUP
}
public class RecipientTypesFactory{
private Map<RecipientTypeEnum, RecipientTypeCreator> creators;
public RecipientType createRecipientType(RecipientTypeEnum t){
return creators.get(t).create();
}
}
I'm not going to provide the actual definition of RecipientTypeCreator and its hierarchy because I don't think it's very important.
Now I have the controller:
public class CreateMailingController{
private RecipientTypesFactory recipientTypesFactory;
private Integer dynamicGroupId;
private Integer staticGroupId;
private RecipientTypeEnum selectedType;
//GET, SET, other staff
public void createMailing(){
Type t = recipientTypesFactory.createRecipientType(selectedType);
//How to initialize t's field with an appropriate value?
}
}
The thing is RecipientTypesFactory and its creators know nothing about CreateMailingController's dynamicGroupId and staticGroupId values. Those values are setting up by some user from web-interface. Therefore the factory cannot initialize the corresponding field of a type to create with these values.
RecipientTypesFactory and its creators are spring beans.
Question: How can I pass the values of dynamicGroupId and staticGroupId to the Factory in a flexible way and avoid wiriting switch-case like code? Is that possible?
Maybe there's another patter for that purposes. In fact the factory is creating the prototype of an object.
You can use map to avoid switch cases,like below:
private static final Map<String, RecipientType> factoryMap = Collections
.unmodifiableMap(new HashMap<String, RecipientType>() {
{
put("dynamicGroupId", new RecipientType() {
public RecipientType accept() {
return new DynamicGroupType();
}
});
put("staticGroupId", new RecipientType() {
public RecipientType accept() {
return new StaticGroupType();
}
});
}
});
public RecipientType createRecipientType(String type) {
RecipientType factory = factoryMap.get(type);
if (factory == null) {
}
return factory.accept();
}
I have an enum FileType
public static enum FileType {
CSV, XML, XLS, TXT, FIXED_LENGTH
}
FileType fileType = FileType.CSV;
Is there a better (cleaner) way to check fileType for multiple values than the following (like "myString".matches("a|b|c");)?
if(fileType == FileType.CSV || fileType == FileType.TXT || fileType == FileType.FIXED_LENGTH) {}
Option 1: Add a boolean field to your enum.
public static enum FileType {
CSV(true), XML(false), XLS(false), TXT(true), FIXED_LENGTH(true);
private final boolean interesting;
FileType(boolean interesting) {
this.interesting = interesting;
}
public boolean isInteresting() {
return this.interesting;
}
}
...
if (fileType!=null && fileType.isInteresting()) {
...
}
Option 2: use an EnumSet.
EnumSets use bitfields under the hood, so they are very fast and low memory.
Set<FileType> interestingFileTypes = EnumSet.of(FileType.CSV, FileType.TXT, FileType.FIXED_LENGTH);
...
if (interestingFileTypes.contains(fileType)) {
...
}
Option 3: use a switch, as kocko suggests
Why not use a switch:
switch(fileType) {
case CSV:
case TXT:
case FIXED_LENGTH:
doSomething();
break;
}
This does the same as your if statement check, but it's more readable, imho.
But the problem with this code is not the switch or the if/else statement(s). The problem is that it breaks the Open-closed principle.
In order to fix that, I would completely remove the enum and create an interface:
interface FileType {
boolean isInteresting();
}
Then, for each enum constant we used to have, I would create a separate interface implementation:
public class Txt implements FileType {
#Override
public boolean isInteresting() {
return false;
}
}
How does the switch statement change? We used to pass a fileType parameter, on which we checked the value. Now, we will pass an instance of FileType.
public void method(FileType fileType) {
if (fileType.isInteresting()) {
doSomething();
}
}
The advantage of this is that when you introduce a new FileType (which you would introduce as a new enum constant), you don't have to modify the switch/if/else statement to handle the case when this new file type is interesting or not. The code will simply work here without modification, which is the essence of the Open-closed principle: "Open for extensions, closed for modifications".
I ended up writing a method:
public static enum FileType {
CSV, XML, XLS, TXT, FIXED_LENGTH;
// Java < 8
public boolean in(FileType... fileTypes) {
for(FileType fileType : fileTypes) {
if(this == fileType) {
return true;
}
}
return false;
}
// Java 8
public boolean in(FileType... fileTypes) {
return Arrays.stream(fileTypes).anyMatch(fileType -> fileType == this);
}
}
And then:
if(fileType.in(FileType.CSV, FileType.TXT, FileType.FIXED_LENGTH)) {}
Nice and clean!
Adding a different example:
public class JavaApplication {
public enum CustomerStatus {
ACTIVE("Active"),
DISCONNECTED("Disconnected"),
PENDING("Pending"),
CANCELLED("cancelled"),
NEW("new");
}
public static void main(String[] args) {
EnumSet<CustomerStatus> setA = EnumSet.of(CustomerStatus.ACTIVE, CustomerStatus.NEW);
EnumSet<CustomerStatus> setB = EnumSet.of(CustomerStatus.PENDING, CustomerStatus.CANCELLED);
if (setA.contains(CustomerStatus.ACTIVE)) {
System.out.println("ACTIVE : customer active");
}
if (setB.contains(CustomerStatus.ACTIVE)) {
System.out.println("ACTIVE: Customer is no longer active");
}
if (setB.contains(CustomerStatus.CANCELLED) {
System.out.println("CANCELLED: Customer is no longer active");
}
}
}
**Output**:
ACTIVE : customer active
CANCELLED: Customer is no longer active
I need to build a process which will validate a record against ~200 validation rules. A record can be one of ~10 types. There is some segmentation from validation rules to record types but there exists a lot of overlap which prevents me from cleanly binning the validation rules.
During my design I'm considering a chain of responsibility pattern for all of the validation rules. Is this a good idea or is there a better design pattern?
Validation is frequently a Composite pattern. When you break it down, you want to seperate the what you want to from the how you want to do it, you get:
If foo is valid
then do something.
Here we have the abstraction is valid -- Caveat: This code was lifted from currrent, similar examples so you may find missing symbology and such. But this is so you get the picture. In addition, the
Result
Object contains messaging about the failure as well as a simple status (true/false).
This allow you the option of just asking "did it pass?" vs. "If it failed, tell me why"
QuickCollection
and
QuickMap
Are convenience classes for taking any class and quickly turning them into those respected types by merely assigning to a delegate. For this example it means your composite validator is already a collection and can be iterated, for example.
You had a secondary problem in your question: "cleanly binding" as in, "Type A" -> rules{a,b,c}" and "Type B" -> rules{c,e,z}"
This is easily managed with a Map. Not entirely a Command pattern but close
Map<Type,Validator> typeValidators = new HashMap<>();
Setup the validator for each type then create a mapping between types. This is really best done as bean config if you're using Java but Definitely use dependency injection
public interface Validator<T>{
public Result validate(T value);
public static interface Result {
public static final Result OK = new Result() {
#Override
public String getMessage() {
return "OK";
}
#Override
public String toString() {
return "OK";
}
#Override
public boolean isOk() {
return true;
}
};
public boolean isOk();
public String getMessage();
}
}
Now some simple implementations to show the point:
public class MinLengthValidator implements Validator<String> {
private final SimpleResult FAILED;
private Integer minLength;
public MinLengthValidator() {
this(8);
}
public MinLengthValidator(Integer minLength) {
this.minLength = minLength;
FAILED = new SimpleResult("Password must be at least "+minLength+" characters",false);
}
#Override
public Result validate(String newPassword) {
return newPassword.length() >= minLength ? Result.OK : FAILED;
}
#Override
public String toString() {
return this.getClass().getSimpleName();
}
}
Here is another we will combine with
public class NotCurrentValidator implements Validator<String> {
#Autowired
#Qualifier("userPasswordEncoder")
private PasswordEncoder encoder;
private static final SimpleResult FAILED = new SimpleResult("Password cannot be your current password",false);
#Override
public Result validate(String newPassword) {
boolean passed = !encoder.matches(newPassword,user.getPassword());
return (passed ? Result.OK : FAILED);
}
#Override
public String toString() {
return this.getClass().getSimpleName();
}
}
Now here is a composite:
public class CompositePasswordRule extends QuickCollection<Validator> implements Validator<String> {
public CompositeValidator(Collection<Validator> rules) {
super.delegate = rules;
}
public CompositeValidator(Validator<?>... rules) {
super.delegate = Arrays.asList(rules);
}
#Override
public CompositeResult validate(String newPassword) {
CompositeResult result = new CompositeResult(super.delegate.size());
for(Validator rule : super.delegate){
Result temp = rule.validate(newPassword);
if(!temp.isOk())
result.put(rule,temp);
}
return result;
}
public static class CompositeResult extends QuickMap<Validator,Result> implements Result {
private Integer appliedCount;
private CompositeResult(Integer appliedCount) {
super.delegate = VdcCollections.delimitedMap(new HashMap<PasswordRule, Result>(), "-->",", ");
this.appliedCount = appliedCount;
}
#Override
public String getMessage() {
return super.delegate.toString();
}
#Override
public String toString() {
return super.delegate.toString();
}
#Override
public boolean isOk() {
boolean isOk = true;
for (Result r : delegate.values()) {
isOk = r.isOk();
if(!isOk)
break;
}
return isOk;
}
public Integer failCount() {
return this.size();
}
public Integer passCount() {
return appliedCount - this.size();
}
}
}
and now a snippet of use:
private Validator<String> pwRule = new CompositeValidator<String>(new MinLengthValidator(),new NotCurrentValidator());
Validator.Result result = pwRule.validate(newPassword);
if(!result.isOk())
throw new PasswordConstraintException("%s", result.getMessage());
user.obsoleteCurrentPassword();
user.setPassword(passwordEncoder.encode(newPassword));
user.setPwExpDate(DateTime.now().plusDays(passwordDaysToLive).toDate());
userDao.updateUser(user);
Chain of responsibility implies that there is an order in which the validations must take place. I would probably use something similar to the Strategy pattern where you have a Set of validation strategies that are applied to a specific type of record. You could then use a factory to examine the record and apply the correct set of validations.
I'm trying to define a class (or set of classes which implement the same interface) that will behave as a loosely typed object (like JavaScript). They can hold any sort of data and operations on them depend on the underlying type.
I have it working in three different ways but none seem ideal. These test versions only allow strings and integers and the only operation is add. Adding integers results in the sum of the integer values, adding strings concatenates the strings and adding an integer to a string converts the integer to a string and concatenates it with the string. The final version will have more types (Doubles, Arrays, JavaScript-like objects where new properties can be added dynamically) and more operations.
Way 1:
public interface DynObject1 {
#Override public String toString();
public DynObject1 add(DynObject1 d);
public DynObject1 addTo(DynInteger1 d);
public DynObject1 addTo(DynString1 d);
}
public class DynInteger1 implements DynObject1 {
private int value;
public DynInteger1(int v) {
value = v;
}
#Override
public String toString() {
return Integer.toString(value);
}
public DynObject1 add(DynObject1 d) {
return d.addTo(this);
}
public DynObject1 addTo(DynInteger1 d) {
return new DynInteger1(d.value + value);
}
public DynObject1 addTo(DynString1 d)
{
return new DynString1(d.toString()+Integer.toString(value));
}
}
...and similar for DynString1
Way 2:
public interface DynObject2 {
#Override public String toString();
public DynObject2 add(DynObject2 d);
}
public class DynInteger2 implements DynObject2 {
private int value;
public DynInteger2(int v) {
value = v;
}
#Override
public String toString() {
return Integer.toString(value);
}
public DynObject2 add(DynObject2 d) {
Class c = d.getClass();
if(c==DynInteger2.class)
{
return new DynInteger2(value + ((DynInteger2)d).value);
}
else
{
return new DynString2(toString() + d.toString());
}
}
}
...and similar for DynString2
Way 3:
public class DynObject3 {
private enum ObjectType {
Integer,
String
};
Object value;
ObjectType type;
public DynObject3(Integer v) {
value = v;
type = ObjectType.Integer;
}
public DynObject3(String v) {
value = v;
type = ObjectType.String;
}
#Override
public String toString() {
return value.toString();
}
public DynObject3 add(DynObject3 d)
{
if(type==ObjectType.Integer && d.type==ObjectType.Integer)
{
return new DynObject3(Integer.valueOf(((Integer)value).intValue()+((Integer)value).intValue()));
}
else
{
return new DynObject3(value.toString()+d.value.toString());
}
}
}
With the if-else logic I could use value.getClass()==Integer.class instead of storing the type but with more types I'd change this to use a switch statement and Java doesn't allow switch to use Classes.
Anyway... My question is what is the best way to go about something thike this?
What you are trying to do is called double dispatch. You want the method called to depend both on the runtime type of the object it's called on, and on the runtime type of its argument.
Java and other C derivatives support single dispatch only, which is why you need a kludge like the visitor pattern you used in option 1. This is the common way of implementing it. I would prefer this method because it uses no reflection. Furthermore, it allows you to keep each case in its own method, without needing a big "switchboard" method to do the dispatching.
I'd choose the second option, with the third, I'd better be using generics so you don't rely on that Enum. And with the first option you could be implementing methods for the rest of your life. Anyways you could use "instanceof" operator for Class matching.