mercredi 18 mars 2015

Is it ok to break the "is a" relationship if I just want part of a class' functionality?


I asked a question about extending TreeMaps into "sort by value" TreeMaps on the "code review" site on stackoverflow. Based on the response, I re-wrote the code. I like it. But, it feels like I might be just using tricks. Or, maybe this is a legit way to write software? Can someone please take a look:



public class ToolBox {
public interface SortedMapByValue {
void put(Object key, Integer val);
Set<Map.Entry<Object, Integer>> entrySet();
}

public static SortedMapByValue getInstanceSortedMapByValue() {
class MyComp implements Comparator {
Map<Object, Integer> sharedMap;

public int compare(Object key1, Object key2) {
if(key1.equals(key2)) { return 0; }

Integer val1 = sharedMap.get(key1);
Integer val2 = sharedMap.get(key2);

if(val1 > val2) return -1;
return 1;
}
}

class MyMap<K> extends TreeMap<K, Integer> {
Map<Object, Integer> sharedMap = new HashMap<Object, Integer>();
MyMap(Comparator comp) {
super(comp);
}

@Override
public Integer put(K key, Integer val) {
if(sharedMap.containsKey(key)) {
super.remove(key);
val += sharedMap.get(key);
}
sharedMap.put(key, val);
super.put(key, val);
return val;
}
}

class TreeMapByValue implements SortedMapByValue {
private MyMap<Object> realMap;

public TreeMapByValue(MyMap myMap) { this.realMap = myMap; }

public void put(Object key, Integer val) {
realMap.put(key, val);
}

public Set<Map.Entry<Object, Integer>> entrySet() {
return realMap.entrySet();
}
}

MyComp myComp = new MyComp();
MyMap<Object> myMap = new MyMap(myComp);
myComp.sharedMap = myMap.sharedMap;

SortedMapByValue treeMapByValue = new TreeMapByValue(myMap);
return treeMapByValue;
}
}


here is test code:



public class Main {
public static void main(String[] args) {
try {
ToolBox.SortedMapByValue sortedMapByValue = ToolBox.getInstanceSortedMapByValue();

Random rand = new Random();
String[] story = { "The", "quick", "brown", "fox", "jumped", "over", "the", "lazy", "dog" };

for(int repeat = 0; repeat < 22; repeat++) {
for(int i = 0; i < story.length; i++) {
String key = story[i];
int value = rand.nextInt(100);
sortedMapByValue.put(key, value);
System.out.println(key + "-->" + value);
}
}

for(Map.Entry<Object, Integer> entry : sortedMapByValue.entrySet()) {
System.out.println("key = " + entry.getKey() + "___value = " + entry.getValue());
}

System.out.println("sortedMapByValue is a \"" + sortedMapByValue.getClass().getName() + "\"");
} catch(Exception e) {
e.printStackTrace();
}
}
}



  1. Observe that the is a relationship is broken where I extended TreeMap into MyMap. ok. So, "MyMap" is not a "TreeMap", but... no one will ever know. Not even with reflection. So, is that legit? Can I break TreeMap as long as no one knows?

  2. I absolutely gutted the "put(K, V)" method in TreeMap. invoking super.remove(val) looks insane. I did what I had to do, but is that a "trick" / "hack" / "bad programming"?

  3. My instances of "MyComp" and "MyMap" are 101% co-dependent. But, this is all self-contained in one static method. Does that make it ok?


Please ignore my complete ignorance of generics. I will study them soon enough.





Aucun commentaire:

Enregistrer un commentaire