Search code examples
javadesign-patternshashmapdecorator

Decorator Design Pattern with HashMap returning empty HashMap


I am trying to implement Decorator design pattern for HashMap.

I have two Decorators - "UpperCaseHashMap" and "AddHashMap".

Implementation 1 :-

However, the result map contains only the effect of one of the decorators, example :-

  • Only AddHashMap effect i.e. result is - {AA=AA}

    Map<String, String> map = new AddHashMap<>(new UpperCaseHashMap<>(new HashMap<> ())); map.add("aa", "aa"); System.out.println(map);

  • Only UpperCaseHashMap effect i.e. result is - {aaADDED_BY_DECORATOR=aa}

    Map<String, String> map = new UpperCaseHashMap<>(new AddHashMap<>(new HashMap<> ())); map.add("aa", "aa"); System.out.println(map);

Below is the code of the decorator classes:-

    public class UpperCaseHashMap<K, V> extends HashMap<K, V> {

    /**
     * 
     */
    private static final long serialVersionUID = 1L;
    
    Map<K, V> map;
    
    public UpperCaseHashMap() {
        map = new HashMap<>();
    }

    UpperCaseHashMap(Map<K, V> map) {
        this.map = map;
    }

    public V put(K key, V value) {
        String temp = key.toString().toUpperCase();
        key = (K) temp;
        return super.put(key, value);
    }
    
}

    public class AddHashMap<K, V> extends HashMap<K, V> {

    /**
     * 
     */
    private static final long serialVersionUID = 1L;
    
    Map<K, V> map;
    AddHashMap(Map<K, V> map) {
        this.map = map;
    }

    public V put(K key, V value) {
        String temp = key.toString().concat("ADDED_BY_DECORATOR");
        key = (K) temp;
        return super.put(key, value);
        
    }
    
}

Implementation 2 :- - The resulted map is empty

public class AddHashMapImpl2<K, V> extends HashMapDecorator<K, V> {

/**
 * 
 */
private static final long serialVersionUID = 1L;

Map<K, V> map;
AddHashMapImpl2(Map<K, V> map) {
    this.map = map;
}

public V put(K key, V value) {
    String temp = key.toString().concat("ADDED_BY_DECORATOR");
    key = (K) temp;
    return map.put(key, value);
    
}

}

public class UpperCaseHashMapImpl2<K, V> extends HashMapDecorator<K, V> {

/**
 * 
 */
private static final long serialVersionUID = 1L;

Map<K, V> map;

public UpperCaseHashMapImpl2() {
    map = new HashMap<>();
}

UpperCaseHashMapImpl2(Map<K, V> map) {
    this.map = map;
}

public V put(K key, V value) {
    String temp = key.toString().toUpperCase();
    key = (K) temp;
    return map.put(key, value);
}

}


Solution

  • Your line:

    return super.put(key, value);
    

    Is calling HashMap.put irrespective of the implementation of the map passed to the constructor. Instead you need:

    return map.put(key, value);
    

    However I feel you are probably misunderstanding how decorators work. If you are using subclassing you will need to forward every method to the delegate. At the moment your classes are extending HashMap but then delegating put specifically. This isn't going to work. All the other methods are going to go to the extended HashMap and won't find the data you've put into the delegate. You need to rethink your design.

    You might want to consider a design like:

    @FunctionalInterface
    interface MapDecorator<V> {
        V decorate(V value);
    }
    
    class DecoratedMap<K, V> extends HashMap<K, V> {
        private final List<MapDecorator<V>> decorators = new ArrayList<>();
    
        public void addDecorator(MapDecorator<V> decorator) {
            decorators.add(decorator);
        }
    
        @Override
        public V put(K key, V value) {
            for (MapDecorator<V> decorator: decorators)
                value = decorator.decorate(value);
            return super.put(key, value);
        }
    }
    

    I've used 'decorator' in this code to match your original question but, in reality, this is not using the decorator design pattern so, in reality, I'd use a different name such as 'transformer'.