I have below Enum from which I am calling appropriate execute method basis on what type of enum (eventType) is passed.
public enum EventType {
EventA {
#Override
public Map<String, Map<String, String>> execute(String eventMapHolder) {
final Map<String, String> holder = parseStringToMap(eventMapHolder);
if (holder.isEmpty() || Strings.isNullOrEmpty(holder.get("m_itemId"))) {
return ImmutableMap.of();
}
String itemId = holder.get("m_itemId");
Map<String, String> clientInfoHolder = getClientInfo(itemId);
holder.putAll(clientInfoHolder);
return ImmutableMap.<String, Map<String, String>>builder().put(EventA.name(), holder)
.build();
}
},
EventB {
#Override
public Map<String, Map<String, String>> execute(String eventMapHolder) {
final Map<String, String> holder = parseStringToMap(eventMapHolder);
if (holder.isEmpty() || Strings.isNullOrEmpty(holder.get("m_itemId"))) {
return ImmutableMap.of();
}
return ImmutableMap.<String, Map<String, String>>builder().put(EventB.name(), holder)
.build();
}
},
EventC {
#Override
public Map<String, Map<String, String>> execute(String eventMapHolder) {
final Map<String, String> holder = parseStringToMap(eventMapHolder);
if (holder.isEmpty() || Strings.isNullOrEmpty(holder.get("m_itemId"))) {
return ImmutableMap.of();
}
String itemId = holder.get("m_itemId");
Map<String, String> clientInfoHolder = getClientInfo(itemId);
holder.putAll(clientInfoHolder);
return ImmutableMap.<String, Map<String, String>>builder().put(EventC.name(), holder)
.build();
}
};
public abstract Map<String, Map<String, String>> execute(String eventMapHolder);
public Map<String, String> parseStringToMap(String eventMapHolder) {
// parse eventMapHolder String to Map
}
public Map<String, String> getClientInfo(final String clientId) {
// code to populate the map and return it
}
}
For example: If I get "EventA", then I am calling it's execute method. Similarly if I get "EventB" then I am callings it's execute method and so on.
String eventType = String.valueOf(payload.get("eventType"));
String eventMapHolder = String.valueOf(payload.get("eventMapHolder"));
Map<String, Map<String, String>> processedMap = EventType.valueOf(eventType).execute(eventMapHolder);
In general I will have more event types (around 10-12) in the same enum class and mostly they will do same operation as EventA, EventB and EventC.
Question:
Now as you can see, code in execute method of EventA and EventC are identically similar but the only difference is what I put as "key" (event name) in the returned immutable map. Is there any way to remove that duplicated code but still achieve the same functionality in the enum.
For example, something on this ground. By writing multiple enums side by side separated by comma (if the execute method functionality is same). I know this doesn't work because I have a abstract method which I need to implement it everywhere but is it still possible by making some changes or any other better way?
public enum EventType {
EventA,
EventC {
#Override
public Map<String, Map<String, String>> execute(String eventMapHolder) {
// same code which is there in execute method for EventA and EventC
}
},
EventB {
#Override
public Map<String, Map<String, String>> execute(String eventMapHolder) {
// same code which is there in execute method of EventB
}
};
// other methods which are there already
}
I know one way is to make a method with all the common things and call those method by passing appropriate Event type enum name. Is there any other way apart from that by using enum features or any other changes?
If there is any other better way or any other design pattern to do this then I am open for suggestions as welll which can help me remove duplicated code.
Idea is - basis on what type of event is passed, I want to call its execute method and avoid duplication if possible.
There are two simple mechanisms (that can of course be combined).
The first one consists in having the execute() in the base class, delegating to specific code defined in each subclass (i.e. the template method pattern):
enum Foo {
A {
#Override
protected void specificCode() {
//...
}
},
B {
#Override
public void specificCode() {
//...
}
};
public void execute() {
// ... common code
specificCode();
// ... common code
}
protected abstract void specificCode();
}
The second one consists in having the execute() overridden in each subclass but delegating to a common method defined in the base class:
enum Foo {
A {
#Override
public void execute() {
//...
commonCode();
// ...
}
},
B {
#Override
public void execute() {
//...
commonCode();
// ...
}
};
public abstract void execute();
protected void commonCode() {
// ...
}
}
Something like this?
package enumCodeReuse;
import java.util.Map;
import com.google.common.collect.ImmutableMap;
public enum EventType2 {
EventA
, EventB
, EventC
;
public Map<String, Map<String, String>> execute(String eventMapHolder) {
final Map<String, String> holder = parseStringToMap(eventMapHolder);
if (holder.isEmpty() || Strings.isNullOrEmpty(holder.get("m_itemId"))) {
return ImmutableMap.of();
}
String itemId = holder.get("m_itemId");
Map<String, String> clientInfoHolder = getClientInfo(itemId);
holder.putAll(clientInfoHolder);
return ImmutableMap.<String, Map<String, String>>builder()
.put(this.name(), holder)
.build();
};
public Map<String, String> parseStringToMap(String eventMapHolder) {
// parse eventMapHolder String to Map
return null; // FIXME
}
public Map<String, String> getClientInfo(final String clientId) {
// code to populate the map and return it
return null; // FIXME
}
}
Related
I have a Class like this:
public class MyClass
{
private int id;
private Map<String, String> myMap;
public Map<String, String> getMyMap()
{
return myMap;
}
public void setMyMap(Map<String, String> myMap)
{
this.myMap = myMap;
}
}
I added new setter method(overloading) because i didn't want to do set HashMap directly, and that's what you see now :
public class MyClass
{
private int id;
private Map<String, String> myMap;
public Map<String, String> getMyMap()
{
return myMap;
}
public void setMyMap(Map<String, String> myMap)
{
this.myMap = myMap;
}
public void setMyMap(String key , String value)
{
setMyMap(new HashMap<>(){{put(key, value);}});
}
}
But because i used new HashMap<>(){{put(key, value);}} keyword every time i use this method , it create new Map and last items deleted .
So i have 2 question:
1-correct solution for set items by 2nd setter method
2-how i could use this setter method for multiple put's for this situations:
MyClass.setMyMap(new HashMap<>()
{{
put("title", title);
put("id", id);
}});
Thank you guys for your time .
It depends on what your class does. But in general, I would not expose a setter for a map field.
It makes sense to add a constructor with a map argument, then do something like this:
public class MyClass
{
private final int id;
private final Map<String, String> myMap;
public MyClass(int id, Map<String, String> myMap) {
this.id = id;
this.myMap = myMap;
}
public Map<String, String> getMyMap()
{
return myMap;
}
public void addPairs(Map<String, String> pairs)
{
myMap.putAll(pairs);
}
public void addPair(String key, String value)
{
myMap.put(key, value);
}
}
Of course, you can expose an additional constructor:
public MyClass(int id) {
this.id = id;
this.myMap = new HashMap<>();
}
Try some thing like this:
public void setMyMap(String key , String value) {
if(myMap == null)
myMap = new HashMap<String, String>();
myMap.put(key, value);
}
You've already declared class field myMap and you want to use it in setMyMap method.
Do null check. If the field is null then create a new map. Then use put method to store data in the map.
I have either one of following Objects, ObjOne and ObjTwo, going into my function, both sharing similar getters/setters.
Currently I have an intermediary, a mapper, used across internal methods, but there might be a cleaner way to do this without a mapper but lacking specific syntax.
public String mapper(Object obj){
Map<String, String> map = new HashMap<>();
if(obj instanceof ObjOne){
ObjOne obj1 = (ObjOne)obj;
map.put("firstKey", obj1.getFirstValue());
}
else if(obj instanceof ObjTwo){
ObjTwo obj2 = (ObjTwo)obj
map.put("firstKey", obj1.getFirstValue());
}
return secondFunction(map);
}
private String secondFunction(Map<String, String> map){
return thirdFunction(map.get("firstKey"));
}
Is there such syntax for (ObjOne || ObjTwo)obj).getFirstValue() to feed into thirdFunction herein?
Edit: I imported these Objects, so I can't declare a parent class for them, they do share getters/setters that are convenient for my scenario.
A more OO approach is to compose the objects you don't control within a new object that you do control. Then write your API in terms of the object you control.
final class ObjOne {
String getFirstValue() {
return "foo";
}
}
final class ObjTwo {
String getFirstValue() {
return "bar";
}
}
class MyAdapter {
final Map<String, String> map = new HashMap<>();
MyAdapter(ObjOne o1) {
this(o1.getFirstValue());
}
MyAdapter(ObjTwo o2) {
this(o2.getFirstValue());
}
MyAdapter(String firstKey) {
map.put("firstKey", firstKey);
}
}
public String secondFunction(MyAdapter adapter) {
return thirdFunction(adapter.map.get("firstKey"));
}
One suggestion don't pass Object instead do something like this create a base model use here polymorphism. for example.
abstract class BaseObj {
abstract public String getFirstValue();
}
class ObjOne extends BaseObj{
#Override
public String getFirstValue() {
return "something useful";
}
}
class ObjTwo extends BaseObj{
#Override
public String getFirstValue() {
return "something useful";
}
}
not sure what is the use case here but you can always mold accordingly.
public String mapper(BaseObj obj){
Map<String, String> map = new HashMap<>();
map.put("firstKey", obj.getFirstValue()); //common function call
return secondFunction(map);
}
private String secondFunction(Map<String, String> map){
return thirdFunction(map.get("firstKey"));
}
private String thirdFunction(String firstKey) {
return null;
}
I am struggling to find a way to dispatch this to functions in java8
Person p = registry.getPerson();
if (field == Field.LASTNAME) {
p.setLastName(str);
}
if (field == Field.FIRSTNAME) {
p.setFirstName(str);
}
if (field == Field.MIDDLENAME) {
p.setMiddleName(str);
}
My idea is to use some kind of function dispatch table to replace the if statements in the case of more cases:
Map<Integer, Function> map = new HashMap<Integer, Function>
static {
map.put(1, new Function<String, String>() {
#Override
public Object apply(String str) {
person.setLastName(str);
return str;
}
}
}
But the code cannot compile, because i need to pass the person object some place. Anyone knows a pattern for this?
Assuming Field is an enum, you can add BiConsumer<Person,String> as an enum field:
class Person {
static enum Field {
FIRSTNAME(Person::setFirstName),
MIDDLENAME(Person::setMiddleName),
LASTNAME(Person::setLastName)
;
private BiConsumer<Person, String> setter;
private Field(BiConsumer<Person, String> setter) {
this.setter = setter;
}
}
public void set(Field field, String str) {
field.setter.accept(this, str);
}
......
}
Instead of storing Function<String,String>, you can store BiFunction<Person,String,String> and pass the Person instance in as a parameter.
Map<Integer, BiFunction<Person,String,String>> map =
new HashMap<Integer, BiFunction<Person,String,String>>();
static {
map.put(1, (person, str)->person.setLastName(str));
}
In the interest of simplicity, you could also just store a List of the functions, if you're just going to index them by an integer, it's faster for random access and makes for less complicated generic code:
List<BiFunction<Person,String,String>> list = new ArrayList<BiFunction<Person,String,String>>();
static {
list.add((person, str)->person.setLastName(str));
}
I have two similar methods. One of them prints something and one of them save somethings. As you can see there are a lot of duplicate code. How should I refactor it and remove this duplication ?
public static void printSomething(List<String> list) {
for (String item : list) {
if (item.contains("aaa")) {
System.out.println("aaa" + item);
}
if (item.contains("bbb")) {
System.out.println("bbb" + item);
} else {
System.out.println(item);
}
}
}
public static Map<String, String> getSomething(List<String> list) {
Map<String, String> map = new HashMap<String, String>();
for (String item : list) {
if (item.contains("aaa")) {
map.put("aaa", item);
}
if (item.contains("bbb")) {
map.put("bbb", item);
} else {
//do nothing
}
}
return map;
}
UPDATE:
Code was updated to solve problem when method are not exactly similar
Assuming the order of which the println of "aaa" and "bbb" appear does not matter, you could replace the implementation of printSomething with
public static void printSomething(List<String> list) {
Map<String, String> map = getSomething(list);
for(Map.Entry<String, String> entry : map) {
System.out.println(entry.getKey() + entry.getValue());
}
}
A generic Interface Action that have a method action(T t) can reduce the code.
public interface Action<E> {
void action(E e);
}
Example:
public static void forEach(List<String> list, Action <String> action) {
for(String s : list){
action.action(s);
}
Now you just need 2 different implementations of Action.
You can use annonymous types if you don't want to create a class.
If you know c# this is similar to lambdas.
edit:
Using annonymous type:
public static Map<String, String> getSomething(List<String> list) {
final Map<String, String> map = new HashMap<String, String>();
forEach(list, new Action<String>() {
#Override
public void action(String e) {
if (e.contains("aaa")) {
map.put("aaa", e);
}
if (e.contains("bbb")) {
map.put("bbb", e);
} else {
// do nothing
}
}
});
return map;
}
Creating the class:
public static Map<String, String> getSomething2(List<String> list) {
final Map<String, String> map = new HashMap<String, String>();
forEach(list, new ListToMapAction(map));
return map;
}
public class ListToMapAction implements Action<String> {
Map<String, String> map;
public ListToMapAction(Map<String, String> map) {
this.map = map;
}
#Override
public void action(String e) {
if (e.contains("aaa")) {
map.put("aaa", e);
}
if (e.contains("bbb")) {
map.put("bbb", e);
} else {
// do nothing
}
}
}
In a programming language with first-class functions, you'd pass around a function as a parameter indicating what you want to do inside the loop (for an example see the update, below). Java is going to have lambdas in version 8, but they're not quite up to the job.
In the current state of Java, you'll have to settle with something uglier - for example, passing an extra parameter to the method; or you could pass around anonymous inner classes that implement an interface, but IMHO that's even uglier than what I'm about to suggest:
static void printSomething(List<String> list, boolean print)
If print is true then print inside the loop, otherwise add to the Map. Of course, you'll have to add a couple of ifs inside the loop for checking this condition, and at the beginning, one extra if to determine if the Map is to be initialized. Either way, the method returns a Map, but the Map can be null for the printing case. This is what I mean:
static Map<String, String> processSomething(List<String> list, boolean print) {
Map<String, String> map = null;
if (!print)
map = new HashMap<String, String>();
for (String item : list) {
if (item.contains("aaa")) {
if (print)
System.out.println("aaa" + item);
else
map.put("aaa", item);
}
if (item.contains("bbb")) {
if (print)
System.out.println("bbb" + item);
else
map.put("bbb", item);
} else if (print) {
System.out.println(item);
}
}
return map;
}
UPDATE
For example, in Python - which allows passing functions as parameters, this is how you'd solve the problem in an elegant fashion:
def processSomething(lst, func):
result = None
for item in lst:
if 'aaa' in item:
result = func(item, 'aaa', result)
elif 'bbb' in item:
result = func(item, 'bbb', result)
else:
result = func(item, '', result)
return result
def printer(item, key, result):
print key + item
def mapper(item, key, result):
if not result:
result = {}
if key:
result[key] = item
return result
See how it works:
processSomething(['aaa', 'bbb', 'ccc'], printer)
=> aaaaaa
bbbbbb
ccc
processSomething(['aaa', 'bbb', 'ccc'], mapper)
=> {'aaa': 'aaa', 'bbb': 'bbb'}
I need a mapping from a list of keys to a value. I know I could write my own code like this:
Map<Person, Map<Daytime, Map<Food, Integer>>> eaten = ...;
Now I want to have some get and put methods like these:
Integer numberOfEggsIAteInTheMorning = eaten.get(me, morning, scrambledEggs);
eaten.put(me, evening, scrambledEggs, 1);
Do you know of an existing class that has this kind of API? I'm too lazy of writing it myself. ;)
If you look for a more generic approach, and you might have more than 2 or 3 'chain steps', I would suggest in applying some different structural approach, rather than sticking to using only basic collection classes. I have feeling that Composite Pattern could be the right choice if it's correctly applied.
EDIT: due to example requested
The full example would be somewhat time consuming, so let me just explain my idea with dirty Java/pseudocode mix (I'm not even sure if I've missed something!!!). Let's consider we have class BaseMap:
abstract class BaseMap {
public abstract Object getValue(Object.. keys);
public abstract void putValue(Object value, Object.. keys);
}
Then we could have ObjectMap that would be the 'leaf' of our composite structure:
class ObjectsMap extends BaseMap {
private Map<Object, Object> map = new [...]
public Object getValue(Object.. keys) {
// assert that keys.length == 1
return map.get(keys[0]);
}
public void putValue(Object value, Object.. keys) {
// assert that keys.length = 1
map.put(keys[0], value);
}
}
And the actual composite would be as such:
class CompositeMap extends BaseMap {
private Map<Object, BaseMap> compositeMaps = new [...]
public Object getValue(Object.. keys) {
// assert that keys.length > 1
return compositeMap.get(keys[0]).getValue(/* System.arrayCopy => subset of elements {keys_1, .. ,keys_max} */);
}
public void putValue(Object value, Object.. keys) {
// assert keys.length > 1
BaseMap newMap = null;
if (keys.length = 2) -> newMap = new ObjectsMap()
else newMap = new CompositeMap();
newMap.putValue(value, /*subset of keys {keys_1, .. , keys_max}*/);
}
}
You can use org.apache.commons.collections.keyvalue.MultiKey for that: Map<Multikey, Object>
It would be hard to implement a general chained map.
How would the declaration of the class look like? (You can't have a variable number of type parameters.
class ChainedMap<K1..., V>
Another option would be to have a ChainedMapUtil class that performs put / get recursively.
Here is an example of a recursive get. (Quite ugly solution though I must say.)
import java.util.*;
public class Test {
public static Object chainedGet(Map<?, ?> map, Object... keys) {
Object k = keys[0];
if (!map.containsKey(k)) return null;
if (keys.length == 1) return map.get(k);
Object[] tailKeys = Arrays.copyOfRange(keys, 1, keys.length);
return chainedGet((Map<?,?>) map.get(k), tailKeys);
}
public static void main(String[] arg) {
Map<String, String> m1 = new HashMap<String, String>();
m1.put("ipsum", "dolor");
Map<Integer, Map<String, String>> m2 =
new HashMap<Integer, Map<String, String>>();
m2.put(17, m1);
Map<String, Map<Integer, Map<String, String>>> chained =
new HashMap<String, Map<Integer, Map<String, String>>>();
chained.put("lorem", m2);
System.out.println(chainedGet(chained, "lorem", 17, "ipsum")); // dolor
System.out.println(chainedGet(chained, "lorem", 19, "ipsum")); // null
}
}
If you are going to write your own, I would suggest
eaten.increment(me, evening, scrambledEggs);
You could use a composite key
eaten.increment(Key.of(me, evening, scrambledEggs));
(TObjectIntHashMap supports increment and adjust)
You may not even need a custom key.
eaten.increment(me + "," + evening + "," + scrambledEggs);
It is fairly easy to decompose the key with split()
I once made a map using 3 keys just for fun.May be you can use it instead of using chained maps:
public class ThreeKeyMap<K1,K2,K3,V>{
class wrap{
K1 k1;
K2 k2;
K3 k3;
public wrap(K1 k1,K2 k2,K3 k3) {
this.k1=k1;this.k2=k2;this.k3=k3;
}
#Override
public boolean equals(Object arg0) {
// TODO Auto-generated method stub
wrap o=(wrap)arg0;
if(!this.k1.equals(o.k1))
return false;
if(!this.k2.equals(o.k2))
return false;
if(!this.k2.equals(o.k2))
return false;
return true;
}
#Override
public int hashCode() {
int result=17;
result=37*result+k1.hashCode();
result=37*result+k2.hashCode();
result=37*result+k3.hashCode();
return result;
}
}
HashMap<wrap,V> map=new HashMap<wrap, V>();
public V put(K1 k1,K2 k2,K3 k3,V arg1) {
return map.put(new wrap(k1,k2,k3), arg1);
}
public V get(Object k1,Object k2,Object k3) {
return map.get(new wrap((K1)k1,(K2)k2,(K3)k3));
}
public static void main(String[] args) {
ThreeKeyMap<Integer,Integer,Integer,String> birthDay=new ThreeKeyMap<Integer, Integer, Integer, String>();
birthDay.put(1, 1,1986,"Emil");
birthDay.put(2,4,2009, "Ansih");
birthDay.put(1, 1,1986,"Praveen");
System.out.println(birthDay.get(1,1,1986));
}
}
UPDATE:
As #Arturs Licis suggested.I looked up in net for composite pattern and I wrote a sample using it.I guess this is composite..Please comment if it is not so.
Person class:
public class Person {
private final String name;
private Map<Time, Food> map = new HashMap<Time, Food>();
public Person(String name) {
this.name = name;
}
void addTimeFood(Time time, Food food) {
map.put(time, food);
}
public String getName() {
return name;
}
Food getFood(Time time) {
Food tmp = null;
return (tmp = map.get(time)) == null ? Food.NoFood : tmp;
}
// main to test the person class
public static void main(String[] args) {
Person p1 = new Person("Jack");
p1.addTimeFood(Time.morning, Food.Bread);
p1.addTimeFood(Time.evening, Food.Chicken);
Person p2 = new Person("Jill");
p2.addTimeFood(Time.morning, Food.Egg);
p2.addTimeFood(Time.evening, Food.Rice);
Map<String, Person> map = new HashMap<String, Person>();
map.put(p1.getName(), p1);
map.put(p2.getName(), p2);
System.out.println(map.get("Jack").getFood(Time.evening));
}
#Override
public String toString() {
StringBuilder b = new StringBuilder();
b.append(name).append("\n");
b.append(map);
return b.toString();
}
}
Food class:
public enum Food {
Rice,
Egg,
Chicken,
Bread,
NoFood;
}
Time class:
public enum Time {
morning,
evening,
night
}