Posted by : Sushanth Monday, 17 January 2022

 Proxy Design Pattern:

Provide a surrogate or placeholder for another object to control access to it.
Also Known as Surrogate

There are situations in which a client does not or can not reference an object directly, but wants to still interact with the object. A proxy object can act as the intermediary between the client and the target object.

Motivation:

1. The proxy object has the same interface as the target object

2. The proxy holds a reference to the target object and can forward requests to the target as required (delegation!)

3. In effect, the proxy object has the authority the act on behalf of the client to interact with the target object.


Types of Proxies:

1. Remote Proxy - Provides a reference to an object located in a different address space on the same or different machine

2. Virtual Proxy - Allows the creation of a memory intensive object on demand. The object will not be created until it is really needed.

3.Copy-On-Write Proxy - Defers copying (cloning) a target object until required by client actions. Really a form of virtual proxy.

4. Protection (Access) Proxy - Provides different clients with different levels of access to a target object

5. Cache Proxy - Provides temporary storage of the results of expensive target operations so that multiple clients can share the results

6. Firewall Proxy - Protects targets from bad clients (or vice versa)

7. Synchronization Proxy - Provides multiple accesses to a target object

8. Smart Reference Proxy - Provides additional actions whenever a target object is referenced such as counting the number of references to the object.

Copy-On-Write Proxy Example:

Scenario: Suppose we have a large collection object, such as a hash table, which multiple clients want to access concurrently. One of the clients wants to perform a series of consecutive fetch operations while not letting any other client add or remove elements.

Solution 1

Use the collection's lock object. Have the client implement a method which obtains the lock, performs its fetches and then releases the lock.

For example:

public void doFetches(Hashtable ht) {

synchronized(ht) {

// Do fetches using ht reference.

}

}

But this method may require holding the collection object's lock for a long period of time, thus preventing other threads from accessing the collection

 Solution 2:

 Have the client clone the collection prior to performing its fetch operations. It is assumed that the collection object is cloneable and provides a clone method that performs a sufficiently deep copy.

For example, java.util.Hashtable provides a clone method that makes a copy of the hash table itself, but not the key and value objects.

The doFetches() method is now:

public void doFetches(Hashtable ht) {

Hashtable newht = (Hashtable) ht.clone();

// Do fetches using newht reference.

}

The collection lock is held while the clone is being created. But once the clone is created, the fetch operations are done on the cloned copy, without holding the original collection lock. But if no other client modifies the collection while the fetch operations are being done, the expensive clone operation was a wasted effort!

Solution 3:

 It would be nice if we could actually clone the collection only when we need to, that is when some other client has modified the collection. For example, it would be great if the client that wants to do a series of fetches could invoke the clone() method, but no actual copy of the collection would be made until some other client modifies the collection. This is a copy-on-write cloning operation.

We can implement this solution using proxies

 The proxy is the class LargeHashtable. When the proxy's clone() method is invoked, it returns a copy of the proxy and both proxies refer to the same hash table. When one of the proxies modifies the hash table, the hash table itself is cloned. The referenceCountedHashTable class is used to let the proxies know they are working with a shared hash table. This class keeps track of the number of proxies using the shared hash table.

public class LargeHashtable extends Hashtable {

// The ReferenceCountedHashTable that this is a proxy for.

private ReferenceCountedHashTable theHashTable;

// Constructor

public LargeHashtable() {

        theHashTable = new ReferenceCountedHashTable();

}

// Return the number of key-value pairs in this hashtable.

public int size() {

        return theHashTable.size();

}

// Return the value associated with the specified key.

public synchronized Object get(Object key) {

        return theHashTable.get(key);

}

// Add the given key-value pair to this Hashtable

public synchronized Object put(Object key, Object value) {

copyOnWrite();

return theHashTable.put(key, value);

}

// Return a copy of this proxy that accesses the same Hashtable.

public synchronized Object clone() {

Object copy = super.clone();

theHashTable.addProxy();

return copy;

}

// This method is called before modifying the underlying

// Hashtable. If it is being shared then this method clones it.

private void copyOnWrite() {

if (theHashTable.getProxyCount() > 1) {

synchronized (theHashTable) {

theHashTable.removeProxy();

try {

theHashTable = (ReferenceCountedHashTable)

theHashTable.clone();

} catch (Throwable e) {

theHashTable.addProxy();

}

}

}

}

// Private class to keep track of proxies sharing the hash table.

private class ReferenceCountedHashTable extends Hashtable {

private int proxyCount = 1;

// Constructor

public ReferenceCountedHashTable() {

super();

}

// Return a copy of this object with proxyCount set back to 1.

public synchronized Object clone() {

ReferenceCountedHashTable copy;

copy = (ReferenceCountedHashTable)super.clone();

copy.proxyCount = 1;

return copy;

}

// Return the number of proxies using this object.

synchronized int getProxyCount() {

return proxyCount;

}

// Increment the number of proxies using this object by one.

synchronized void addProxy() {

proxyCount++;

}

// Decrement the number of proxies using this object by one.

synchronized void removeProxy() {

proxyCount--;

}

}

}








Leave a Reply

Subscribe to Posts | Subscribe to Comments

- Copyright © Technical Articles - Skyblue - Powered by Blogger - Designed by Johanes Djogan -