Skip to content

Instantly share code, notes, and snippets.

@sheimi
Forked from kavinyao/LimitedInstances.java
Created June 23, 2012 14:14
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save sheimi/2978425 to your computer and use it in GitHub Desktop.
Save sheimi/2978425 to your computer and use it in GitHub Desktop.
A solution to limited instances problem using Proxy Pattern
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;
/*
* A solution using Proxy Pattern to limited instances problem
* Requirement:
* class RareResource must have no more than 3 instances at any run time.
* Note:
* Black magic like reflection is out of consideration as you can never prevent it.
*/
/**
* Clients should use getInstance and destroy methods to
* allocate and release instances properly.
*
*/
class RareResource {
private static final int INSTANCE_LIMIT = 3;
private static RareResource[] rrs = new RareResource[INSTANCE_LIMIT];
private static Queue<RareResource> idle = new LinkedList<RareResource>();
static {
for (int i = 0; i < INSTANCE_LIMIT; i++) {
rrs[i] = new RareResource();
idle.add(rrs[i]);
}
}
private int resource = 1;
/*
* This constructor is protected, of course.
*/
private RareResource() {
}
public int getResource() {
return resource;
}
public void setResource(int r) {
resource = r;
}
/**
* Attempt to get an instance of RareResource
* @return a brand-new instance required
* @throws Exception if number of active instances reaches limit
*/
public static synchronized RareResource getInstance() throws Exception {
if(idle.isEmpty())
throw new Exception("Instance number reaches limit!");
ResourceProxy proxy = new ResourceProxy(idle.poll());
return proxy;
}
/**
* Destroy specified resource
* @param r the resource to destroy
* @return if successfully destroyed, returns true; otherwise, returns false
*/
public static synchronized boolean destroyResource(RareResource r) {
if(r == null)
return false;
if(!(r instanceof ResourceProxy))
return false;
r.destroyResource(); // this is harmless even if the resource has already destroyed
return true;
}
protected void destroyResource() {
RareResource.idle.add(this);
}
/**
* The proxy is internal, so clients won't know what's really going on.
*/
private static class ResourceProxy extends RareResource {
private RareResource protectedResource;
public ResourceProxy(RareResource r) {
protectedResource = r;
}
@Override public int getResource() {
return protectedResource.getResource();
}
@Override public void setResource(int r) {
protectedResource.setResource(r);
}
@Override protected void destroyResource() {
// clear reference to it
if (protectedResource != null) {
protectedResource.destroyResource();
}
protectedResource = null;
}
}
}
public class LimitedInstances {
public static void main(String[] args) throws Exception {
RareResource r1 = RareResource.getInstance();
RareResource r2 = RareResource.getInstance();
RareResource r3 = RareResource.getInstance();// so far so good...
try {
RareResource r4 = RareResource.getInstance();
}catch(Exception e) {
System.out.println("Aha, this exception is expected!");
}
// do something to r1 and they destroy it
r1.setResource(99);
System.out.println("r1.resource = " + r1.getResource());
RareResource.destroyResource(r1);
// now this would be OK
RareResource r4 = RareResource.getInstance();
// try to attach more references to resource?
RareResource r2Ref = r2;
RareResource.destroyResource(r2);
r2Ref.getResource(); // ouch!
RareResource.destroyResource(r3);
RareResource.destroyResource(r4);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment