According to the GoF, the intent of a proxy is to "provide a surrogate or place-holder for another object to control access to it". This is commonly used in a number of situations:
In this project, we will be using virtual proxies. What follows is a description of how these work.
Consider the following Java pseudo-code:
public class A { private B b; private String s; void aMethod(); //uses b and s } public class B { private int i; void bMethod(); //uses i }
Assume that we would like to be able to get A
from the
database, and lazy-load B
at a later stage. Since we can only
interact with the classes by calling their methods, we don't really
care about when the values of b
,s
and
i
are instantiated, only that the method calls work. The
following is a solution to the problem:
public class AProxy { A a; void aMethod() { if (a==null) createA(); //see note later for this method } } public class BProxy { B b; void bMethod() { if (b==null) createB(); //see note later for this method } }
Clearly, this is not transparent to a developer. To make it
transparent, the developer must be able to access (from a typing point
of view) AProxy
in the same manner as he would access
A
. This requires the following modifications:
A
, and an interface B
A
class to something like
AImpl
, and B
to BImpl
AImpl
, AProxy
, BImpl
,
and BProxy
implement A
and B
respectively.
The developer can now use his original code unchanged, always dealing
with A
and B
.
Now, what about the createA
and createB
methods? Well, these are normal Java methods to instantiate the real
A
and B
objects. They are totally
implementation dependent. Assume we are trying to instantiate
A
and B
from a database. Assume furthermore
that BProxy
(and associated classes) now looks like this:
public class BProxy { B b; void bMethod() { if (b instanceof BReference) b=createB(); //see note later for this method } } public class BReference extends Reference implements B { void bMethod() { throw new Exception("Not implemented"); } } public class Reference { int objectIdentifier; }
Then, we could have the following createB()
method:
public B createB() { ... instantiate a B object from the database, based on the fact that we have a reference with an identifier. ... return BImpl }
The bit between the ...
's can be done using either a
helper class or in the code itself. Either way, if code is added to
the system, existing classes do not need to be changed. Looking at
createA
in AProxy
:
createA() { ... b=new BReference(theDatabaseIDForB); ... }
This is the only time we would use a reference rather then the real object in any other class (it may even be possible to get around this).
The whole reference thing is not strictly necessary, it could be
implemented in the proxy class, We believe it is neater however. In
fact, assuming we always use an int id
as a primary key,
we don't even need a BReference
object, a
Reference
will do just fine. one could then do something
like:
public class Proxy { Reference r; boolean instantiated; } public class BProxy extends Proxy implements B { B b; BProxy(Reference r) { super(r); } void bMethod() { if (!instantiated) createB(); b.bMethod(); } }and have the same initialisation code in
A
as above.
So, what does this all mean? It means that on the Java side, all we have are model objects. Each model object, either when defining the proxy class, or via a helper class (similar to a factory class) knows how to perform all database operations on the object - create, commit, delete, and possibly search (which should almost definitely occur in a helper class).
Further references for virtual proxies can be found in the attached handout, as well as at http://www.javaworld.com/javaworld/jw-02-2002/jw-0222-designpatterns.html . Many other resources describing the virtual proxy pattern exist on the web.
<< Previous |
Up
Home |
Next >> |