How to create a class that add some stuff to a map and display it.
I was wondering about the best interface considering that all the code usually need to be covered with unit tests and it's a problem to test a method that display data.
This was my first thought:
class MyFirstProgram {
private Map<String, String> map = new HashMap<String,String>();
public int insertData(...) {...}
public void displayData(...) {...}
}
...but it's not possible to test anything about the retrieval and there is this display method... so I thougt this:
class MyFirstProgram {
private Map<String, String> map = new HashMap<String,String>();
public int insertData(...) {...}
private Map<String, String> retrieveData(...) {...}
public int displayData(...) {...call ; return status}
}
In this it's possible to test the private method with reflection but there is still this display method...
Any idea about the design?
The pragmatic way is to allow access to the Map (via a default/package access method with a comment // for unit tests, and access that. Actually, even better, name the method forUnitTestGetMap() to make it extra clear and avoid confusion with the standard getXXX naming convention. I'm usually fine with just calling toString() on the Map and comparing to what it should be, YMMV. If your insertData() is just calling standard methods on HashMap (e.g. put()) there isn't that much you can and should test, as most of the code is Java library code.
Alternatively, in the displayData() method, does it create an alternative representation of the Data? Such as XML, JSON, maybe a JPanel? If so, look at that to see that the contents of the Data are correct. Obviously XML is much easier than a JPanel for that, but you can still do something like checking that the JPanel has 3 children and the first is a Button named "OK"...
You can try creating getter and setter for the Map variable.
class MyFirstProgram {
private Map<String, String> map = new HashMap<String,String>();
public setMap(Map data) {...}
public Map getMap(...) {...}
}
And then wherever you want to print the map value use getMap method.
If you don't want to use the setters and getters we can have any method which takes a Map as input and print it.
public void PrintMap(Map data){print(data)}
Related
I have a class which basically just contains a HashMap.
The class also has a simple getter method which allows other parts of my application to send the "key" and get back the value from the map.
That much works, however, I don't want to keep instantiating that class every time I need to access it, because this particular data doesn't really change, and I only want it in the map for the sake of querying it quickly for the value I need.
I would like my main application class to create an instance of this, and then have it be available to all of my other classes automatically.
I have been reading about this a lot this morning, but am kind of confused about how it could be achieved, am I trying to do some sort of singleton? Or am I trying to use a service?
Anyway, if anyone has a snippet I can learn from - that would really help me out. I am currently using Annotations for most stuff in spring, and would LIKE to keep it that way.
I think you may not even need a separate class to hold your map. Directly create a bean of the Map which you may want and then Autowire the map where ever you need them.
#Configuration
public class MapConfiguration {
#Bean
public Map<String, Object> dataMap() {
// Create and return your Map here
}
}
Whereever you want your map, just use autowiring.
#Autowired
#Qualifier("dataMap")
private Map<String, Object> dataMap;
If you want to continue to use Spring, you can use the #Component to create a simple component. By default all components are singletons. You can use the #PostConstruct to initialize the data. Below is an example. I'm using a String as the map key, but you can modify it to match your application.
#Component
public class MyMap {
private Map<String, Object> theMap = new HashMap<>();
// PostConstruct runs after the application context instantiates the bean
#PostConstruct
public void init() {
// initialize the data in theMap
}
public Object get(String key) {
return theMap.get(key);
}
}
You can then use the #Autowired annotation or your application context to retrieve the bean:
public class AnotherClass {
#Autowired
MyMap myMap;
// ...
}
If you would like to avoid Spring, another option is to create a simple Java singleton. Here's an example
public class MyMap {
private final static Map<String, Object> theMap = new HashMap<>();
// Use a static block to initialize the map with data
static {
// populate theMap with data
}
public Object get(String key) {
return theMap.get(key);
}
}
One thing to note is that if your map ever does actually get updated, then you will need to handle concurrent reads and updates.
Say I have a class which stores a weapon Arsenal
public class Arsenal{
List<RocketLauncher> rocketLaunchers;
List<HandGrenade> handGrenades;
List<LandMine> landMines;
//Followed by a few more weapons
}
The weapons are part of an enum, Weapon
Now, I am trying to display a summary screen or report elsewhere and I am preparing a map. See the snippet below. I have shown two approaches
public Map<Weapon,Integer> generateReport(Arsenal arsenal){
Map<Weapon,Integer> weaponCountMap = //suitable map impl
//Technique 1
//Create and use a larger num of getters from the Arsenal Class
weaponCountMap.put(Weapon.HAND_GRENADE, arsenal.getHandGrenades);
//.. and so on
//Technique 2
//Create a single method in Arsenal which returns a Map
weaponCountMap = arsenal.getSummary();
return weaponCountMap;
}
Question : Is it just me or does everyone feel 'not right' to use a large number of getters. Suppose Arsenal stores around 50 weapons, it's like 50 methods in the class. Double with setters.
Also. I feel less flexible using the 2nd method, with no accessor methods.
Can you guys please critically evaluate both approaches and possibly suggest new ones?
How about not hard-coding types of weapon inside of your Arsenal? The following is simple implementation of heterogeneous container for your specific case. However, as I don't quite familiar with Generics in enum, this implementation is when you have Weapon and their subclasses, e.g. HardGrenade extends Weapon, etc.
public class Arsenal{
private Map<Class<?>, Collection<?>> weaponArsenal;
public <T extends Weapon> Collection<T> get(Class<T> weaponClass) {
if (weaponArsenal.containsKey(weaponClass) {
return (Collection<T>) weaponArsenal.get(weaponClass);
}
return new ArrayList<T>(); // to avoid checking null everytime in client code
}
public <T extends Weapon> void put(T weapon) {
if (!weaponArsenal.containsKey(weapon.class)) {
Collection<T> weaponList = // initialize correct collection here
weaponArsenal.put(weapon.class, weaponList);
}
weaponArsenal.get(weapon.class).add(weapon);
}
}
and in the client code
Arsenal arsenal = new Arsenal();
arsenal.put(new HandGrenade());
arsenal.put(new RocketLauncher());
Collection<HandGrenade> handGrenades = arsenal.get(HandGrenade.class);
Collection<RocketLauncher> rocketLaunchers = arsenal.get(RocketLauncher.class);
In the arsenal you can duplicate the map instead of using lists. Then in the generateReport method you can iterate over the enum and use the enum value to get the suitable list from the map.
Something like
Arsenal:
Map<Weapon,List<Weapon>> weaponsMap;
arsenalMap.put(Weapon.HAND_GRENADE,handGrenades);
generate report:
for (Weapon weapon: Weapon.values()) {
weaponCountMap.put(Weapon.HAND_GRENADE, arsenal.weaponsMap.get(weapon));
}
Might not be the best solution but you will remove some of the getters.
If you make Arsenal immutable and construct it using a builder (to avoid having a bunch of constructors), you can make the instance variables public.
This approach allows you to use technique 1 from your question but without getters, and still keep state management of the object internal to the object.
public class Arsenal {
public final List<RocketLauncher> rocketLaunchers;
public final List<HandGrenade> handGrenades;
public final List<LandMine> landMines;
//Followed by a few more weapons
private Arsenal(final Arsenal.Builder builder) {
this.rocketLaunchers = Collections.unmodifiableList(builder.rocketLaunchers);
this.handGrenades = Collections.unmodifiableList(builder.handGrenades );
this.landMines= Collections.unmodifiableList(builder.landMines);
// and so on
}
public static class Builder {
private final List<RocketLauncher> rocketLaunchers = new ArrayList<>();
private final List<HandGrenade> handGrenades = new ArrayList<>();
private final List<LandMine> landMines = new ArrayList<>();
public Builder rocketLaunchers(List<RocketLauncher> rocketLaunchers) {
this.rocketLaunchers.addAll(rocketLaunchers);
return this;
}
public Builder handGrenades(List<HandGrenade> handGrenades) {
this.handGrenades.addAll(handGrenades);
return this;
}
public Builder landMines (List<LandMines> landMines ) {
this.landMines .addAll(landMines );
return this;
}
public Arsenal build() {
return new Arsenal(this);
}
}
}
You can now use this in the following way.
List<RocketLauncher> rocketLaunchers = //whatever
Arsenal arsenal = new Arsenal.Builder().rocketLaunchers(rocketLaunchers).build();
....
weaponCountMap.put(Weapon.HAND_GRENADE, arsenal.handGrenades);
//.. and so on
All fields of the arsenal are non-null, and can't be modified. If you define the builder in an external class (i.e. not a static class within Arsenal) your Arsenal class will be very small - just fields and the constructor, plus logic methods.
Please have a look at other posts like this one...Java Conventions: use getters/setters WITHIN the class? to obtain an idea on when you could use getters instead of direct access.
Its kind of a design question depending upon what you would like to encapsulate within your arsenal class and what you would like to expose to the outside world for viewing your arsenal.
Its like the UN trying to inspect your arsenal and you tell them hey I wont tell you what weapons I am dealing with in my arsenal but I can give you a report and that is the report you externalize to the outside world. Now it depends on you what report you want to give out and which weapons will land in that map of yours.
Now looking at your second technique, are you planning to shift the map creation logic into your Arsenal class.
Another design question to answer .... is this logic just to obtain reports then my suggestion is to keep it out of the arsenal class and keep it light.
Otherwise you might end up putting in all kind of report logics into the arsenal class and it will get heavier and might explode.
See https://projectlombok.org/ or https://github.com/google/auto/tree/master/value.
Add separate field for each weapon, Lombok or AutoValue will create getters/setters/hashcode/equals/toString methods for you.
So I have a data class that is somewhat laid out as:
class MyData {
String str1,str2,str3;
Boolean bool1,bool2;
}
The attributes are to be populated based upon a String input, something like:
public void populate(String s) {
if(s.contains("somevalue") myData.setStr1("xxx");
if(s.constains("something else") myData.setBool1(true);
else myData.setBool1(false);
}
This is, of course, a pretty horrible way to do things as s.contains are actually some pretty hairy conditions, so instead I defined an interface:
public interface DataFinderInterface {
public String findStringData(final String input);
public Boolean findBooleanData(final String input);
}
Therefore the populate method could be rewritten as:
public void populate(String s) {
myData.setStr1(str1Finder.findStringData(s));
myData.setBool1(bool1Finder.findBooleanData(s);
}
The implementations of this interface either define a findStringData or a findBooleanData, which is quite unsatisfying. The populate method needs to know if we are expecting to use the findStringData method or the findBooleanData method.
Is there a better way to do this? Am I being overly picky, because the populate method needs to know what instance of DataFinderInterface to assign to what field anyway?
A single findData method returning a String should be sufficient: the code that processes Booleans can put a call to Boolean.getBoolean() on top of it:
public interface DataFinderInterface {
public String findData(final String input);
}
...
myData.setBool1(Boolean.getBoolean(bool1Finder.findData(s));
The problem with the above (or ONE of the problems) is that you are always calling setStr1 AND setBool1 and I assume you will be calling all of the others as well.
If you MUST use something like the above pattern you might want to consider having MyData hold AtomicRefernce<String> and AtomicReference<Boolean>. Then have getSettableString and getSettableBoolean methods that returns the appropriate reference or null if no match.
If it is only the interface method signature you are worried about this could be solved using generics. However it does seem a little weird to initialize an object from a string that way. Perhaps if you add more details about what problem you are trying to solve, there might be a better solution.
public interface DataFinder<T> {
public T findData(final String input);
}
DataFinder<String> str1Finder = new ... // a class implementing DataFinder<String>
DataFinder<Boolean> bool1Finder = new ... // a class implementing DataFinder<Boolean>
public void populate(String s) {
myData.setStr1(str1Finder.findData(s));
myData.setBool1(bool1Finder.findData(s);
}
Consider using regular expressions to extract the data you need from the input string. I would leave the MyData class as a simple data container and build a separate class for populating it - for example, a MyDataBuilder. This class could use string matching in order to extract the fields and populate them on the object.
I have data type which contains 100 properties and 100 getter methods (getproperty1....getproperty100).
I get an input from the user like
Property1
Property2
.
.
Property100
How can I invoke in a quick way the method in this logic
For property1 I need to invoke getproperty1
For propertyI I need to invoke getpropertyI
How can I do this with out using if else, or switch statement or reflection in an efficient way.
Thanks
Your best bet is probably going to be an array or hashmap of some type, and access it by index/key:
public class DataType {
private Map<String, DataProperty> data = new HashMap<String, DataProperty>();
public DataProperty getProperty(String key) {
return data.get(key);
}
public void setProperty(String key, DataProperty value) {
data.put(key, value);
}
}
Although, 100 properties seems like a lot... see if you should break it up or otherwise re-organize it.
You could refactor the class to be a Map. If you have a large number of objects like that it seems more along the lines of a map than an object.
Map<String, Object>
1. If you need to invoke multiple methods I would suggest using the Strategy design pattern. In it's simplest form you could try
public interface Command<T> {
public T getProperty();
}
and then create as many implementations as necessary.
2. If you are only interested in the return type and not the actual invokation the Map<String, T> would be a better alternative.
3. If you want to pass around the information in your program a good alternative would be to use the enum approach
public enum Command {
Property1("some value"),
Property2("some other value");
private String str;
public Command(String str) {
this.str = str;
}
public String getVal() {
return str;
}
}
Which can be used like
Command cmd = ...
String value = cmd.getVal();
What is the best practice in implementing/providing getters/setters for a class containing a map?
The most common implementation I see is:
public class MyClass {
private Map<String, String> myMap;
public getMyMap() { /* Return an unmodifiable map */ }
public setMyMap(Map<String, String> myMap) { ... }
}
Or would it be better to provide an interface like:
public getMyMap() { /* Return a modifiable map */ }
public addToMap(String key, String value) { myMap.put(key, value); }
And why is such method better?
Both have their uses. The methods exposed by a class should be of a proper level of abstraction. For example if the class is a registry of dogs backed by a Map<String, Dog>, then it could provide methods like:
void addDog(String name, Dog dog);
Dog findByName(String name);
If it's say a rule engine that allows clients to specify the entire rule set in one call, then it could expose methods like:
void setRules(Map<String, Rule> rules);
Map<String, Rule> getRules();
In general I would say try not to return the map at all. Have a method that takes the key and returns the value. Taking a map is ok, as long as you copy it, but a method that takes the key/value and puts it into the map would be my preference.
If you must return the map you should return a read-only version or a copy of it. A set method should also copy the map.
It is a bad idea to allow callers to mutate the data inside of a class without the class knowing, passing or holding onto mutable data is a bad idea.
It totally depends on your requirement. This may suffice in most of the cases.
You may not even have a getter method that returns the map. If you use my plug-in, it may help you creating those methods : http://fast-code.sourceforge.net/documentation.htm#create-list-map as eclipse will not help you create the add method.
I would just provide one. Something like...
public Map<String,String> getMyMap()
{
return myMap;
}
and when you want to use it then
myClass.getMyMap().put(key,value);
DISCLAIMER: I did not compile this and test this answer ;)