I’m looking for different ways to ensure that each instance of a given class is a uniquely identifiable instance.
For example, I have a Name
class with the field name
. Once I have a Name
object with name
initialised to John Smith I don’t want to be able to instantiate a different Name
object also with the name as John Smith, or if instantiation does take place I want a reference to the orginal object to be passed back rather than a new object.
I’m aware that one way of doing this is to have a static factory that holds a Map
of all the current Name objects and the factory checks that an object with John Smith as the name doesn’t already exist before passing back a reference to a Name
object.
Another way I could think of off the top of my head is having a static Map in the Name
class and when the constructor is called throwing an exception if the value passed in for name
is already in use in another object, however I’m aware throwing exceptions in a constructor is generally a bad idea.
Are there other ways of achieving this?
13
Actually you have already answered your question. Your first way should be more effective here. Using static factory
is always preferable than constructor
wherever you think you can. So, you can avoid using Constructor
in this case, else you would have throw some exception
if an instance already exists with the given name.
So, you can create a static factory method: – getInstanceWithName(name)
which will get the already available instance with that name, and if it does not exist, it will create a new instance, and make your constructor
private, as it should mostly be done when dealing with static factories
.
Also, for that you need to maintain a static List
or Map
of all the unique instances created, in your Factory
class.
EDIT: –
You should certainly go through – Effective Java – Item#1 : Consider Static factories over Constructors. You can’t get better explanation than that book.
7
Mentions of Effective Java seems to add a lot of credibility so this answer draws on:
- Effective Java Item 8: Obey the general contract when overriding equals
- Effective Java Item 9: Always override the hashCode when you override equals
- Effective Java Item 15: Minimise mutability
I would take a step back and question why you care if there are more than one instance of this name object.
I rarely need to do this kind of object pooling. It is my guess that the OP is doing this so they can simply compare their Name
objects with ==
. Or use the Name
objects inside a HashMap
or similar as the key.
If so this is something that can be solved through proper implementation of equals()
.
Like so:
public final class Name {
private final String name;
public Name(String name) {
if (name == null) {
name = ""; //or exception if you like
}
this.name = name;
}
public String getName() {
return name;
}
@Override
public boolean equals(Object o) {
if (!(o instanceof Name)) {
return false;
}
Name other = (Name) o;
return other.name.equals(name);
}
@Override
public int hashCode() {
return name.hashCode();
}
}
Once done the following is true:
Name a = new Name("weston");
Name b = new Name("weston");
assert(a.equals(b)); //same but:
assert(a!=b); //not the same instance
//test out the Name instances in a hashmap:
HashMap<Name,Object> map = new HashMap<Name,Object>();
Object detailsIn = new Object();
map.put(a,detailsIn);
Object detailsOut = map.get(b);
assert(detailsIn==detailsOut); //the map returned the same details object
//even though we put with `a` and got with `b` thanks to our correct equals implementation
I’m guessing your goal, but this way you can use the Name
class in hash maps etc, and they do not have to be the exact same instance.
6
- Make
Name
an interface - Create an interface
NameFactory
with a methodName getByName(String)
- Create an implementation of
NameFactory
with aMap<String,WeakReference<Name>>
inside it synchronize
on the map by name inside thegetByName
method before making new instances ofName
- Optionally, use a static private implementation of the
Name
interface inside your implementation of theNameFactory
This approach would let you ensure that:
- Only a single instance of
Name
exists at any time, - There is no “Lingerer” memory leak in your class, when
Name
s stick around longer than they need to, - The design remains testable with mocked objects, because you use interfaces.
5
you should make the constructors private and create methods like getNameInstance(String)
, if a object with the same name already exists (based on a static class’ hastable for instance), you return that reference, else you create a new object using your private constructor and add it to the hashtable
2
Try following.
You have to keep track of each object you create. For this purpose I’m using List.
And made class constructor private, so that pre-check can be applied before creating an instance
class UniqueName
{
private string Name;
public int ID;
private static int Count=0;
static List<UniqueName> lt=new List<UniqueName>();
private UniqueName(string Name)
{
this.Name = Name;
ID = ++Count;
}
public static UniqueName GetUniqueueInstance(string Name)
{
foreach (UniqueName un in lt)
{
if ( string.Compare( un.Name,Name,StringComparison.InvariantCultureIgnoreCase)==0)
return un;
}
UniqueName temp=new UniqueName(Name);
lt.Add(temp);
return temp;
}
}
2