I recommend implementing Flyweight Pattern. From wikipedia:
A flyweight is an object that minimizes memory use by sharing as much data as possible with other similar objects; it is a way to use objects in large numbers when a simple repeated representation would use an unacceptable amount of memory.
Java already implements this in Integer
class through the static
factory method Integer#valueOf
method and the internal IntegerCache
class that holds by default Integer
s from -128 til 127. Here's an example:
Integer i1, i2, i3;
i1 = 100; //it will call Integer with value of 100 from cache
i2 = Integer.valueOf(100); //it will call Integer with value of 100 from cache
i3 = new Integer(100); //creates a new instance
System.out.println(i1 == i2); //true
System.out.println(i1 == i3); //false
System.out.println(i1.equals(i2)); //true
System.out.println(i1.equals(i3)); //true
Knowing this, you can create your own flyweight implementation:
public class YourClass {
private final String name;
private final String description;
//more fields...
//making a private constructor in case you don't want other classes
//to create instance of this class carelessly
//like Integer
private YourClass(String name, String description) {
this.name = name;
this.description = description;
//probably more logic here
}
public String getName() {
return name;
}
public String getDescription() {
return description;
}
@Override
public int hashCode() {
//sample implementation
//it can be heavily improved
return name.hashCode();
}
@Override
public boolean equals(Object o) {
//sample implementation
//it MUST be heavily improved
if (o == this) return true;
if (!(o instanceof YourClass)) return false;
YourClass other = (YourClass)o;
return this.name.equals(other.getName());
}
//static flyweight manager
private static class YourClassFlyweight {
//cache with weak entries
//wrapped into a synchronized Map
static final Map<String, YourClass> cache =
Collections.synchronizedMap(
new WeakHashMap<String, YourClass>());
//if you don't want weak entries
//then just use a ConcurrentHashMap
//static final Map<String, YourClass> cache =
// new ConcurrentHashMap<String, YourClass>()));
private YourClassFlyweight() { }
}
//using Factory Method along with this flyweight implementation
public static YourClass create(String name, String description) {
//check if it's not created
if (YourClassFlyweight.cache.containsKey(name)) {
//if it is, then return current instance
return YourClassFlyweight.cache.get(name);
}
//otherwise, create the instance and add it into cache
synchronized(YourClassFlyweight.cache) {
YourClass newInstance = new YourClass(name, description);
YourClassFlyweight.cache.put(name, newInstance);
return newInstance;
}
}
}
Basic test for this:
YourClass ins1 = YourClass.create("Luiggi", "Mendoza");
YourClass ins2 = YourClass.create("Luiggi", "OtherLastName");
System.out.println(ins1.equals(ins2)); // true
System.out.println(ins1 == ins2); // unbelievably, true
Also, instead using Map
with some implementation for a cache, you may use a real cache library like ehcache instead.