Right now I have about 60 Message types which are passed to a getStuff(Message) method of a class which implements ContainerOfThings. There are multiple variations of an ContainerOfThings such as BoxOfStuff and BagOfTricks both of which realize the getStuff(Message) method which generates a string based on member variables. The result may also have pre-pended or post-pended data such as labels or concatenated data. See code below.
public class BoxOfStuff implements ContainerOfThings
{
private String var1;
private String var2;
private String varN;
public String getStuff(Message message)
{
if (message.equals(Message.GET_STUFF1))
return var1;
else if (message.equals(Message.GET_STUFF2))
return "Var2 is: " + var2;
else if (message.equals(Message.GET_STUFFN))
return varN + "\n";
// Etc. for each Message.GET_*
}
// getters and setters for each var*
}
public class Message
{
private String id = null;
private Message(String id)
{ this.id = id; }
public final String toString()
{ return this.id; }
public static final Message GET_STUFF1 = new Message("V1");
public static final Message GET_STUFF2 = new Message("V2");
public static final Message GET_STUFFN = new Message("VN");
}
I am trying to find a design that meets the following objectives. (1) The string returned from getStuf() needs to reflect the current state of the implementing class's member fields. (2) Also I would prefer to get away from an incredibly long series of if / else if blocks. One concern is ease of potentially changing to a persistent data-driven configurable object approach which a Map lends well towards. (3) Design should allow for simple maintenance and/or edits.
One design that could work but is a little messy is to create a Map with all key/values initialized in the constructor and also reset any key/value pair inside each setter method. In this way, the response to getStuff(Message) is updated to the new content after changes (ie: in a setVar*() method). Any other thoughts?
I think you'll need two maps. One will be a Map<Message, String> where the value will be a format string (i.e. something that will get passed into String.format()). The second map will be a Map<Message, Field> which should be fairly self explanatory once you take a look at the reflection libs. These will need to be setup at init time but after that the getStuff() method should be fairly clean and your setters won't be affected at all.
BTW, Java doesn't generally prefix interfaces with I.
I'm not 100% sure I understand your problem, but it sounds like you want to memoize the result of your getStuff() call.
One easy way to do this is to use the makeComputingMap() method from the MapMaker class in the Google Guava library.
For example, you could do:
Map<Message, String> map = new MapMaker()
.expireAfterWrite(10, TimeUnit.MINUTES)
.makeComputingMap(
new Function<Message, String>() {
public String apply(Message message) {
// Your getStuff() implementation here
}
});
Does that make sense?
How about this:
public abstract class BaseOfBox implements IContainerOfThings {
protected final Map<Message, String> stuffs =
new HashMap<Message, String>();
public final String getStuff(Message message) {
return stuffs.get(message);
}
}
public class BoxOfStuff extends BaseOfBox {
private String var1;
private String var2;
public BoxOfStuff() {
super();
}
public setVar1(String var1) {
this.var1 = var1;
stuffs.put(Message.GET_STUFF1, var1);
}
public setVar2(String var2) {
this.var2 = var2;
stuffs.put(Message.GET_STUFF2, "Var2 is: " + var2);
}
...
}
Frankly, I think this is a pretty ugly solution, but so are the requirements, IMO. I suspect a more elegant solution can only be found if we review the (real) requirements
Related
We have an exception Class A with a few fault codes defined as public static final and it is referenced in many files (more than 100) in our source code.
We want all these fault codes in Class B for some processing.
Currently we have implemented a method called getFaultCodes() in Class A to build a list of fault codes and return the same. The problem with this approach is that whenever an fault code is introduced, it has to be added in getFaultCode method as well. This is error prone, as a user may forget to add the new code to the method.
Moving these fault codes under an enum requires changes in many files all over the source code, so we don't want do this.
class ExceptionA {
public static final String faultCode1 = "CODE1";
public static final String faultCode2 = "CODE1";
public static final String faultCode3 = "CODE1";
List<String> getFaultCodes(){
list.add(faultCode1);
......
return list;
}
}
We are thinking about using reflection, but I'm posting in this forum just to check if there is a better solution. Please provide your suggestion to solve this problem.
Maybe you can go through an interface:
public interface FaultCodeProvider
{
String getFaultCode();
}
Then have your enums implement it:
public enum DefaultFaultCodes
implements FaultCodeProvider
{
FAULT1("text for fault 1"),
// etc
;
private final String value;
DefaultFaultCodes(final String value)
{
this.value = value;
}
#Override
public String getFaultCode()
{
return value;
}
}
Collecting them from the enum is then as easy as cycling through the enum's values().
I have modified code code like below:
class ExceptionA {
public enum codes {
CODE1("CODE1"),
CODE2("CODE2"),
CODE3("CODE3"),
private String code;
codes(String code){
this.code = code;
}
public String getCode() {
return this.code;
}
}
public static final String faultCode1 = code.CODE1;
public static final String faultCode2 = code.CODE2;
public static final String faultCode3 = code.CODE3;
}
So that I need not to change the variables occurrences "faultCode" in the source code, I can access the list of fault codes from other class.
I was asked this question in an interview to improve the code that was provided. The provided code used lot of if statements and therefore I decided to use HashMap as retrieval would be faster. Unfortunately, I was not selected for the position. I am wondering if someone knows a better way than what I did to improve the code?
/* The following Java code is responsible for creating an HTML "SELECT" list of
U.S. states, allowing a user to specify his or her state. This might be used,
for instance, on a credit card transaction screen.
Please rewrite this code to be "better". Submit your replacement code, and
please also submit a few brief comments explaining why you think your code
is better than the sample. (For brevity, this sample works for only 5
states. The real version would need to work for all 50 states. But it is
fine if your rewrite shows only the 5 states here.)
*/
/* Generates an HTML select list that can be used to select a specific U.S.
state.
*/
public class StateUtils {
public static String createStateSelectList() {
return
"<select name=\"state\">\n"
+ "<option value=\"Alabama\">Alabama</option>\n"
+ "<option value=\"Alaska\">Alaska</option>\n"
+ "<option value=\"Arizona\">Arizona</option>\n"
+ "<option value=\"Arkansas\">Arkansas</option>\n"
+ "<option value=\"California\">California</option>\n"
// more states here
+ "</select>\n"
;
}
/* Parses the state from an HTML form submission, converting it to the
two-letter abbreviation. We need to store the two-letter abbreviation
in our database.
*/
public static String parseSelectedState(String s) {
if (s.equals("Alabama")) { return "AL"; }
if (s.equals("Alaska")) { return "AK"; }
if (s.equals("Arizona")) { return "AZ"; }
if (s.equals("Arkansas")) { return "AR"; }
if (s.equals("California")) { return "CA"; }
// more states here
}
/* Displays the full name of the state specified by the two-letter code. */
public static String displayStateFullName(String abbr) {
{
if (abbr.equals("AL")) { return "Alabama"; }
if (abbr.equals("AK")) { return "Alaska"; }
if (abbr.equals("AZ")) { return "Arizona"; }
if (abbr.equals("AR")) { return "Arkansas"; }
if (abbr.equals("CA")) { return "California"; }
// more states here
}
}
My solution
/* Replacing the various "if" conditions with Hashmap<key, value> combination
will make the look-up in a constant time while using the if condition
look-up time will depend on the number of if conditions.
*/
import java.util.HashMap;
public class StateUtils {
/* Generates an HTML select list that can be used to select a specific U.S.
state.
*/
public static String createStateSelectList() {
return "<select name=\"state\">\n"
+ "<option value=\"Alabama\">Alabama</option>\n"
+ "<option value=\"Alaska\">Alaska</option>\n"
+ "<option value=\"Arizona\">Arizona</option>\n"
+ "<option value=\"Arkansas\">Arkansas</option>\n"
+ "<option value=\"California\">California</option>\n"
// more states here
+ "</select>\n";
}
/* Parses the state from an HTML form submission, converting it to the
two-letter abbreviation. We need to store the two-letter abbreviation
in our database.
*/
public static String parseSelectedState(String s) {
HashMap<String, String> map = new HashMap<String, String>();
map.put("Alabama", "AL");
map.put("Alaska", "AK");
map.put("Arizona", "AZ");
map.put("Arkansas", "AR");
map.put("California", "CA");
// more states here
String abbr = map.get(s);
return abbr;
}
/* Displays the full name of the state specified by the two-letter code. */
public static String displayStateFullName(String abbr) {
{
HashMap<String, String> map2 = new HashMap<String, String>();
map2.put("AL", "Alabama");
map2.put("AK", "Alaska");
map2.put("AZ", "Arizona");
map2.put("AR", "Arkansas");
map2.put("CA", "California");
// more state abbreviations here here
String full_name = map2.get(abbr);
return full_name;
}
}
}
I think there are many things wrong with your code, not least the recreation of the Map for each method call.
I would start at the very beginning, with interfaces. We need two things; a State and a StateResolver. The interfaces would look like this:
public interface State {
String fullName();
String shortName();
}
public interface StateResolver {
State fromFullName(final String fullName);
State fromShortName(final String shortName);
Set<? extends State> getAllStates();
}
This allows the implementation to be swapped out for something more sensible at a later stage, like a database. But lets stick with the hardcoded states from the example.
I would implement the State as an enum like so:
public enum StateData implements State {
ALABAMA("Alabama", "AL"),
ALASKA("Alaska", "AK"),
ARIZONA("Arizona", "AZ"),
ARKANSAS("Arkansas", "AR"),
CALIFORNIA("Californiaa", "CA");
private final String shortName;
private final String fullName;
private StateData(final String shortName, final String fullName) {
this.shortName = shortName;
this.fullName = fullName;
}
#Override
public String fullName() {
return fullName;
}
#Override
public String shortName() {
return shortName;
}
}
But, as mentioned above, this can be replaced with a bean loaded from a database. The implementation should be self-explanatory.
Next onto the resolver, lets write one against our enum:
public final class EnumStateResolver implements StateResolver {
private final Set<? extends State> states;
private final Map<String, State> shortNameSearch;
private final Map<String, State> longNameSearch;
{
states = Collections.unmodifiableSet(EnumSet.allOf(StateData.class));
shortNameSearch = new HashMap<>();
longNameSearch = new HashMap<>();
for (final State state : StateData.values()) {
shortNameSearch.put(state.shortName(), state);
longNameSearch.put(state.fullName(), state);
}
}
#Override
public State fromFullName(final String fullName) {
final State s = longNameSearch.get(fullName);
if (s == null) {
throw new IllegalArgumentException("Invalid state full name " + fullName);
}
return s;
}
#Override
public State fromShortName(final String shortName) {
final State s = shortNameSearch.get(shortName);
if (s == null) {
throw new IllegalArgumentException("Invalid state short name " + shortName);
}
return s;
}
#Override
public Set<? extends State> getAllStates() {
return states;
}
}
Again this is self explanatory. Variables are at the instance level. The only dependency on the StateData class is in the initialiser block. This would obviously need to be rewritten for another State implementation but that should be not big deal. Notice this class throws an IllegalArgumentException if the state is invalid - this would need to be handled somewhere, somehow. It is unclear where this would happen but something that needs to be considered.
Finally we implement the required methods in the class
public final class StateUtils {
private static final StateResolver STATE_RESOLVER = new EnumStateResolver();
private static final String OPTION_FORMAT = "<option value=\"%1$s\">%1$s</option>\n";
public static String createStateSelectList() {
final StringBuilder sb = new StringBuilder();
sb.append("<select name=\"state\">\n");
for (final State s : STATE_RESOLVER.getAllStates()) {
sb.append(String.format(OPTION_FORMAT, s.fullName()));
}
sb.append("</select>\n");
return sb.toString();
}
public static String parseSelectedState(final String s) {
return STATE_RESOLVER.fromFullName(s).shortName();
}
public static String displayStateFullName(final String abbr) {
return STATE_RESOLVER.fromShortName(abbr).fullName();
}
}
Notice we only reference the implementation at the top of the utility class, this makes swapping out the implementation quick and painless. We use a static final reference to that the StateResolver is created once and only once. I have also replaced the hardcoded creation of the select with a dynamic loop based one. I have also used a formatter to build the select.
It should be noted that it is never a good idea to build HTML in Java and anyone that does so should have unspeakable things done to them.
Needless to say you should have thorough unit tests against each and every line of the above code.
In short your answer doesn't really come close to a proper, extensible, enterprise solution to the problem at hand. My solution might seem overkill, and you may be right. But I think it's the correct approach because abstraction is key to reusable code.
To avoid manually maintaining 2 maps and keeping them in sync I would just create the second one as the first one inverted. See here on how to do it.
Also as pointed out by others you need to create your maps only once outside of method call.
** Just for fun a way to do it in Scala **
val m = Map("AL" -> "Alabama", "AK" -> "Alaska")
m map { case (k, v) => (v, k) }
// gives: Map(Alabama -> AL, Alaska -> AK)
Everyone seems focused on the parse, but the create can be improved, too. Get all of the state names, sort them alphabetically, and iterate over that collection to create each option. That way, the states used for parsing are always in sync with the states used for cresting. If you add a new state, you only need to add it to the "master" Enum (or whatever), and both methods will reflect the change.
The only mistake you made was to rebuild the map every time around. If you had built the Map just once - perhaps in a constructor I suspect you would have done fine.
public class StateUtils {
class State {
final String name;
final String abbreviation;
public State(String name, String abbreviation) {
this.name = name;
this.abbreviation = abbreviation;
}
}
final List<State> states = new ArrayList<State>();
{
states.add(new State("Alabama", "AL"));
states.add(new State("Alaska", "AK"));
states.add(new State("Arizona", "AZ"));
states.add(new State("Arkansas", "AR"));
states.add(new State("California", "CA"));
}
final Map<String, String> nameToAbbreviation = new HashMap<String, String>();
{
for (State s : states) {
nameToAbbreviation.put(s.name, s.abbreviation);
}
}
final Map<String, String> abbreviationToName = new HashMap<String, String>();
{
for (State s : states) {
nameToAbbreviation.put(s.abbreviation, s.name);
}
}
public String getStateAbbreviation(String s) {
return nameToAbbreviation.get(s);
}
public String getStateName(String abbr) {
return abbreviationToName.get(abbr);
}
}
One thing I don't like about your code is that you create a hashmap each time the method is called. The map should be created just once, at class init time, and referenced from the method.
What you did wrong is what guys are saying - you are creating a new HashMap every time the method is invoked - a static field could rather congaing the data, and populating it only once the class is being loaded my the JVM.
I'd rather use simple switch on strings - the search is not worse than that of HashMap (at least asymptotically) but you don't use extra memory. Though you need two long switches - more code.
But than again HashMap solution the the later one would be the same for me.
For now, I have a class with fields.
#Entity
public class Fuel {
#Id #GeneratedValue
private Long id;
private boolean diesel;
private boolean gasoline;
private boolean etanhol;
private boolean cng;
private boolean electric;
public Fuel() {
// this form used by Hibernate
}
public List<String> getDeclaredFields() {
List<String> fieldList = new ArrayList<String>();
for(Field field : Fuel.class.getDeclaredFields()){
if(!field.getName().contains("_") && !field.getName().equals("id") && !field.getName().equals("serialVersionUID") ) {
fieldList.add(field.getName());
}
Collections.sort(fieldList);
}
return fieldList;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public boolean isDiesel() {
return diesel;
}
public void setDiesel(boolean diesel) {
this.diesel = diesel;
}
public boolean isGasoline() {
return gasoline;
}
public void setGasoline(boolean gasoline) {
this.gasoline = gasoline;
}
public boolean isEtanhol() {
return etanhol;
}
public void setEtanhol(boolean etanhol) {
this.etanhol = etanhol;
}
public boolean isCng() {
return cng;
}
public void setCng(boolean cng) {
this.cng = cng;
}
public boolean isElectric() {
return electric;
}
public void setElectric(boolean electric) {
this.electric = electric;
}
}
I think it makes sense, but when I asked another question (maybe a stupid example since there can only be either automatic or manual gearbox) https://stackoverflow.com/questions/11747644/selectonemenu-from-declared-fields-list-in-pojo , a user recommend me to use enums instead. Like this way:
public enum Fuel {
DIESEL("diesel"),
GASOLINE("gasoline"),
ETANHOL("etanhol"),
CNG("cng"),
ELECTRIC("electric");
private String label;
private Fuel(String label) {
this.label = label;
}
public String getLabel() {
return label;
}
}
However, since there exists hybrids on the market (like Toyota Prius) the parent class would implement the boolean class at this way:
private Fuel fuel = new Fuel();
and if using enumerated list at this way:
private List<Fuel> fuelList = new ArrayList<Fuel>();
What is the best practice? Keep in mind that I might have 100 different fuels (just for example =). Do not forget that it is an entity and hence persisted in a database.
Thanks in advance =)
It sounds to me like you want an EnumSet, yes, definitely over a bunch of bool's.
This reminds me a lot of the design patterns for flags and I recently posted an SO question on exactly that: Proper design pattern for passing flags to an object
This supports having 100 different fuel types easily. However it doesn't support a car using 100 different fuel types simultaneously easily. But that to me sounds perfectly fine - it would be very hard to build such a car and this is perfectly reflected in the programmatic complexity of coding this :) (Unless of course it really was just supporting all corn-based fuels - in which you might prefer a polymorphic pattern.)
You should definetly use enums.
Image you want to get the fuel-type of an object.
If you would use bools you would end up with something like this:
if (myClass.IsGasoline())
else if (myClass.IsOtherFuel())
else if
...
If you use enums you can simply do something like:
Fuel fuel = myClass.GetFuelType()
(This is just pseudo-code ;))
If the number of hybrids is low, and I guess it will be better to use Enums, and include hybrids as a different case.
Otherwise you will have to manage the logic in a way that can be cumbersome, as when you set a certain Fuel to true you, most likely, will have also to set to false the current one set to true. I am saying this as you have setters for your fuel categories and you don't only define at construction.
EDIT: the way on how to ask for the type of fuel you are using would also be an argument in favor of enums.
I have a number of setter methods which take an enum. These are based on incoming objects attribute. Rather than write a bunch of these is there a way around having to hard code say 10 different case statements. Would there be a way to create a reusable method?
//Side class declared as
public final enum Side
//How I initialise side
static Side side = Side.SELL;//default
//method to set object
Obj.setSide(sideEnum(zasAlloc.getM_buySellCode()));
//How I am implementing it
public static Side sideEnum(String buysell)
{
if(buysell.equalsIgnoreCase("S"))
{
side = Side.SELL; //default
}
else if(buysell.equalsIgnoreCase("B"))
{
side = Side.BUY;
}
return side;
}
You can implement that functionality in your Enum.
public enum Side {
BUY("B"), SELL("S"), ...
private String letter;
private Side(String letter) {
this.letter = letter;
}
public static Side fromLetter(String letter) {
for (side s : values() ){
if (s.letter.equals(letter)) return s;
}
return null;
}
}
You could also do this as a helper static method if you can't edit Side.
public static Side fromString(String from) {
for (Side s: Side.values()) {
if (s.toString().startsWith(from)) {
return s;
}
}
throw new IllegalArgumentException( from );
}
The above method assumes your strings correspond to the names of you enums.
Enums have valueOf() method that can be used to convert from String. Is it what you are looking for?
I ended up using a simple object map:
private static HashMap<String, Side> sideMap = new HashMap<String, Side>(7);
static{
sideMap.put("B", Side.BUY);
sideMap.put("S", Side.SELL);
}
and simply using
Obj.setSide(sideMap.get(zasAlloc.getM_buySellCode()));
I think you need smth like:
Obj.setSide(Side.valueOf(zasAlloc.getM_buySellCode()));
I am creating a helper class in parsing XML elements, so the developer do not need to know the exact name and capitalization of the XML fields.
private static class TagNames{
public static String RESOURCE_ID = "ResourceId";
public static String RESOURCE_NAME = "ResourceName";
public static String RESOURCE_PRICE = "ResourcePrice";
}
This makes it easier to do things like:
someXMLParser.getValueByTagName(TagNames.RESOURCE_ID);
My question is this. If I want to iterate over all the fields declared in class TagNames, how do I do that? Pseudocode:
For tag in TagNames:
someXMLParser.getValueByTagName(tag)
I know I will probably have to restructure all of this. But I can't figure out a way to make the names easily accessible as well as iterable, without any duplication.
Any suggestions?
You're literally asking for a solution based on reflection, but I think a Java Enum may be a better choice in this case. Building on Frederick's example:
public class EnumTest {
public enum Tags {
RESOURCE_ID("ResourceId"),
REOURCE_NAME("ResourceName"),
RESOURCE_PRICE("ResourcePrice");
private final String tagName;
Tags(String tagName) {
this.tagName = tagName;
}
public String getTagName() {
return tagName;
}
}
public static void main(String[] args) {
for(Tags tag : Tags.values()) {
System.out.println("const:" + tag.name()
+ " tagName:" + tag.getTagName());
}
// API user might do e.g.:
// document.getValueForTag(Tags.REOURCE_NAME);
}
}
Although I agree that you should probably use enums or ResourceBundles, here's a solution to your actual question. A method that generates a Map name -> value from all public constants in a given class (the only thing that's missing should be try / catch or throws)
public static Map<String, Object> getConstantValues(Class<?> clazz){
Map<String, Object> constantValues = new LinkedHashMap<String, Object>();
for(Field field : clazz.getDeclaredFields()){
int modifiers = field.getModifiers();
if(Modifiers.isPublic(mod)
&& Modifiers.isStatic(mod) && Modifiers.isFinal(mod)){
constantValues.put(field.getName(), field.get(null));
}
}
return constantValues;
}
You may want to consider using a ResourceBundle instead of a class to store the tag names. May require a little bit of reworking of your code but it will be easier to produce a list of tags compared to what you are doing now, and adding a new tag won't require much work other then adding a line to the properties file.
You can do this quite easily using enum and an accompanying array:
public class Main {
public enum TagName { RESOURCE_ID, REOURCE_NAME, RESOURCE_PRICE }
private static String[] tags = {"ResourceID", "ResourceName", "ResourcePrice"};
public static String getValueByTagName(TagName tag) {
return tags[tag.ordinal()];
}
public static void main(String[] args) {
System.out.println("Calling by getValueByTagName:");
System.out.println(getValueByTagName(TagName.RESOURCE_ID));
System.out.println("Calling TagName.values() for loop:");
for (TagName t : TagName.values()) {
System.out.println(getValueByTagName(t));
}
}
}
Using an enum is a good fit, especially if you use a custom constructor and the built in "values" method:
public class Main {
public static enum TagName {
RESOURCE_ID("ResourceId"),
RESOURCE_NAME("ResourceName"),
RESOURCE_PRICE("ResourcePrice"),
;
private String s;
private TagName(String s) { this.s = s; }
public String toString() { return this.s; }
public static String[] strings() {
List<String> ss = new ArrayList<String>();
for (TagName tagName : TagName.values()) {
ss.add(tagName.toString());
}
return ss.toArray(new String[ss.size()]);
}
}
public static void main(String[] args) {
// Use TagName.values() for the enums, or for strings...
for (String s : TagName.strings()) {
System.out.println(s);
}
}
}
This way you can simply add new tags and they'll automatically get picked up by the "strings" method; for extra performance you could compute that string array just once, statically, since you can't change the set of enums dynamically. You could get even fancier by auto-generating the tag strings from their constant values, if they are really normalized...