Next I tried to write a key class which would not have a setter method. But what if the state of the property is changed by the inheritors of this class? For that we need to make the property final. Another point of view would be to make the entire class final. But that would make any enhancements to the parent class impossible. Given that there might be key features which are not immediately visible at the time of parent class creation, this is a usable idea.
Let us see what happens when we leave the state holding property of the parent Class to the manipulation of the future inheritor classes.
The Original parent class is now extended by the above class and a setter method has been added and thereby nullifying the objective. If we use the Parent Class then we don't run into a problem. But any client class which uses an extended version like the one above may run into one. Please check the code below.
Here we create two keys one with the parent class and the other with the child class. With the parent class object we insert the value in the map. And nullify it. On the first attempt the child class is able to retrieve it however on the second attempt the key fails the equality test as the state holding property has been reset by the setter method in the child class.
Below is the Output
Let us see what happens when we leave the state holding property of the parent Class to the manipulation of the future inheritor classes.
/**
*
*
* @param key
*/
public InvalidKey2(String key) {
super();
this.key = key;
}
/**
*
* We re-use the String equals
*
*/
@Override
public boolean equals(Object obj) {
if(obj instanceof InvalidKey2) {
if(((InvalidKey2)obj).getKey().equals(this.key)) return true;
else return false;
}
else return false;
}
/**
*
* We re-use the Object hashCode and the String code hashCode if the key is not null.
*
*/
@Override
public int hashCode() {
if(key!=null) return this.key.hashCode(); // we simply return String's hash code
return super.hashCode(); // if key is null then we return the Object's hash code value.
}
/**
*
*
*/
public String toString() {
StringBuffer buffer = new StringBuffer("");
buffer.append(this.key);
return buffer.toString();
}
}
In the above code the state changing property is protected which means any inheritor class can manipulate the property. And although spoiler setter method is eliminated we will see how access specifier makes the class quite unsuitable for a Key in a Map.
/**
*
* This is invalid because the state-change property has been made as protected and the class is extended
*
* @author Sanjay
*
*/
static class InvalidKey3 extends InvalidKey2 {
/**
*
*
* @param key
*/
public InvalidKey3(String key) {
super(key);
}
/**
* * The Spolier Method
* @param key
*/
public void setKey(String key) {
// TODO Auto-generated method stub
super.key = key;
}
}
The Original parent class is now extended by the above class and a setter method has been added and thereby nullifying the objective. If we use the Parent Class then we don't run into a problem. But any client class which uses an extended version like the one above may run into one. Please check the code below.
package org.home.project21.study.designPatterns;
import java.util.HashMap;
import java.util.Map;
/**
*
*
* Collections : Keys in a Map 2
*
*
*/
public class CollectionsTest2 {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
Map myMap = new HashMap();
InvalidKey2 iKey = new InvalidKey2("InvalidKey1");
InvalidKey2 iKeyRef = new InvalidKey3("InvalidKey1"); // creating a new key with the same value
myMap.put(iKey, "This is Value");
iKey = null; // we remove the link from the first reference to the Object
System.out.println(" myMap has " + myMap.get(iKeyRef) + " against this key " + iKeyRef.toString() + " myMap " + myMap);// this will print the correct value
((InvalidKey3)iKeyRef).setKey("InvalidKey2");
System.out.println(" myMap has " + myMap.get(iKeyRef) + " against this key " + iKeyRef.toString() + " myMap " + myMap);// this will print the correct value
}
Here we create two keys one with the parent class and the other with the child class. With the parent class object we insert the value in the map. And nullify it. On the first attempt the child class is able to retrieve it however on the second attempt the key fails the equality test as the state holding property has been reset by the setter method in the child class.
Below is the Output
myMap has This is Value against this key InvalidKey1 myMap {InvalidKey1=This is Value}
myMap has null against this key InvalidKey2 myMap {InvalidKey1=This is Value}
No comments:
Post a Comment