-
-
Save sheimi/2978425 to your computer and use it in GitHub Desktop.
A solution to limited instances problem using Proxy Pattern
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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