Proxy Design pattern in Kotlin — Structure Design Pattern (1)

ahmed shaaban
8 min readJul 27, 2021

--

if you hear about proxy work will be related to internet usage like blocking unappropriated websites for employees in a company it is protects them from open these websites.

Problem

  1. some classes creation and initialization has big cost in memory despite we may not use it
  2. some classes need to be secure (have different access rights)
  3. Proxy is applicable whenever there is a need for a more versatile or sophisticated reference to an object than a simple pointer.

use proxy when object is very resource-intensive or when there are certain conditions which need to be checked before using the actual object. A proxy can also be useful if we’d like to limit the access or functionality of an object.

definition

The Proxy Pattern provides a surrogate or placeholder for another object to control access to it like defer the full cost of its creation and initialization until we actually need to use it.

  • the proxy pattern means using a proxy for some other entity. In other words, a proxy is used as an intermediary in front of or wrapped around, an existing object.
  • The Proxy Pattern is used to create a representative object that controls access to another object, which may be remote, expensive to create, or secure( have different access rights.).
  • maintain middleware things such as transaction, network management

Usage

  • If you need to execute something either before or after the primary logic of the class, the proxy lets you do this without changing that class. (open-close principal)
  • When we want a simplified version of a complex or heavy object. In this case, we may represent it with a skeleton object which loads the original object on demand, also called lazy initialization. This is known as the Virtual Proxy
  • When the original object is present in a different address space, and we want to represent it locally.
  • We can create a proxy that does all the necessary boilerplate stuff like creating and maintaining the connection, encoding, decoding, etc., while the client accesses it as it was present in their local address space. This is called the Remote Proxy
  • When we want to add a layer of security to the original underlying object to provide controlled access based on the access rights of the client. This is called Protection Proxy

Variations to the Proxy Pattern:

1) remote proxy

  • provides a local representative for an object in a different address space.
  • You call methods to the local object which forwards those calls onto the remote object.
  • we need is to contact that object which resides in a remote location to get the result that we want.
  • The Remote Proxy acts as a local representative of a remote object.
  • In this case, the proxy passes the client request over the network, handling all of the nasty details of working with the network.

2) virtual proxy Fake It Till You Make It 😉.

  • creates expensive objects on demand.
  • A memory-saving technique that recommends postponing an object
    creation until it is needed.
  • One way to save time and memory is to avoid loading the objects until required, and this is done using the Virtual Proxy.
  • This technique is also known as Lazy Loading where you are fetching the data only when it is required.

3) protection proxy

  • controls access to the original object.
  • Protection proxies are useful when objects should have different access rights.
  • At times, it may be necessary to restrict the accessibility of an object only to a limited set of client objects based on their access rights.
  • When a client object tries to access such an object, the client is given access to the services provided by the object only if the client can furnish proper
    authentication credentials.

Do I need a Virtual Proxy in Kotlin?

In the world of programming, lazy loading has the following four common ways of implementation :

  1. Lazy Initialization (available in kotlin)
  2. Virtual Proxy (like our example below)
  3. Value Holder
  4. Ghost Pattern

use latinit with var and lazy with val and forget virtual proxy

  • With lazy initialization, the object to be lazily loaded is originally set to null, and every request for the object checks for null and creates it “on the fly” before returning it first
  • A virtual proxy is an object with the same interface as the real object. The first time one of its methods is called it loads the real object and then delegates.
  • A “ghost” is a lazy-loaded object that contains just enough info to instantiate itself on demand. They can be useful because they can trigger a bulk load of similar ghosts on the first access if they register themselves with a loader.
  • A value holder is a generic object that handles the lazy loading behavior, and appears in place of the object’s data fields;

Mechanism

any client who needs to access the original class will talk to a proxy which in turn will call a specific needed method in the original class

  1. create an interface for RealSubject and Proxy so that proxy can be substituted for the real subject.
  2. Since the proxy implements the same interface as the original class, it can be passed to any client that expects a real service object.
  3. create a proxy class that
    - hold a reference that lets the proxy access the real subject.
    - controls access to the real subject and may be responsible for creating and deleting it.

The proxy pattern makes an abstraction layer to provide separation. We exactly define business rules in our application and our proxies bind the supplementary implementations( logging, transaction management, configuration management) to complete achievements.

Use of the proxy can simply be forwarding to the real object, or can provide additional logic. In the proxy extra functionality can be provided, for example caching when operations on the real object are resource intensive, or checking preconditions before operations on the real object are invoked.

Example

we will focus on protection Proxy

Story

guess we had two cart repository in our eCommerce app according to user type
- authorized person who make register or login
- guest that browses the app and can add to cart and when logged in and move that cart to an authorized user

  • Imagine this is our network and database classes :)
  • before using proxy we will make two repositories to support single responsibility

we want to make the addToCart Method don’t care about the type of user just care about one job adding to cart (single Responsibility)

So our proxy class gives access to certain repositories and hence their different implementations and functionalities.

  1. we will create an interface
  2. make the two repositories implement it

3. create a Proxy class that control to decided which repository function will use according to user type

another situation

  1. Logging requests (logging proxy). This is when you want to keep a history of requests to the service object. The proxy can log each request before passing it to the service.
  2. access cart and you are not logged in
  3. The proxy can implement caching for recurring requests that always yield the same results. The proxy may use the parameters of requests as the cache keys.

AndroidVideoCache is a good example for caching video stream

Advantage:

  • One of the advantages of Proxy patterns is security.
  • This pattern avoids duplication of objects which might be huge in size and memory intensive. This in turn increases the performance of the application.
  • The remote proxy also ensures security by installing the local code proxy (stub) in the client machine and then accessing the server with help of the remote code.
  • You can manage the lifecycle of the real object when clients don’t care about it.
  • Open/Closed Principle. You can introduce new proxies without changing the real object or clients.

Disadvantages:

  • Performance: a proxy object is used to wrap an object existing somewhere across the network. Since this is a proxy, it can hide from the client the fact that remote communication is involved.
    This can in turn make the client inclined to write inefficient code because they will not be aware that an expensive network call is being made in the background.
  • This pattern introduces another layer of abstraction which sometimes may be an issue if the RealSubject code is accessed by some of the clients directly and some of them might access the Proxy classes. This might cause disparate behavior.

if network object takes time to initialize does retrofit use proxy ??!!

  • of course, it uses it in create method not just for it takes more time but also protection proxy
  • it first validateServiceInterface method to validate interface
  • but as u can see retrofit code in java you will find it uses dynamic proxy

Do I need a dynamic proxy as retrofit doing?

  • the problem with manual proxy is it works only with one interface and This contradicts with re-usability.
  • useful if the logic is generic or quite generic like adding logger for network call

With Proxy.newProxyInstance(..) we create a new proxy object. This method takes three arguments:

  • The classloader that should be used
  • A list of interfaces that the proxy should implement (here UserProvider)
  • An InvocationHandler implementation

InvocationHandler is an interface with a single method: invoke(..). This method is called whenever a method on the proxy object is called.

Another example we will use proxy

1. Cache Proxy/Server Proxy: required to store the results of most frequently used target operations. The proxy object stores these results in some kind of a repository. When a client object requests the same operation, the proxy returns the operation results from the storage area without actually accessing the target object.

2. Firewall Proxy: The primary use of a firewall proxy is to protect target objects from bad clients. A firewall proxy can also be used to provide the functionality required to prevent clients from accessing harmful targets.

3. Synchronization Proxy: To provide the required functionality to allow safe concurrent access to a target object by different client objects.

4. Smart Reference Proxy: To provide the functionality to prevent the accidental disposal/deletion of the target object when there are clients currently with references to it. To accomplish this, the proxy keeps a count of the number of references to the target object. The proxy deletes the target object if and when there are no references to it.

5. Counting Proxy: To provide some kind of audit mechanism before executing a method on the target object.

Smart reference.

This is when you need to be able to dismiss a heavyweight object once there are no clients that use it.

The proxy can keep track of clients that obtained a reference to the service object or its results. From time to time, the proxy may go over the clients and check whether they are still active. If the client list gets empty, the proxy might dismiss the service object and free the underlying system resources.

The proxy can also track whether the client had modified the service object. Then the unchanged objects may be reused by other clients.

Conclusion

use Proxy pattern in situations where an object is severely constrained and cannot live up to its responsibility. Typically this occurs when there is a dependency on a remote resource (resulting in network latency) or when an object takes a long time to load.

  • Control access to another object
  • Lazy initialization
  • Implement logging
  • Facilitate network connection
  • Count references to an object

--

--

No responses yet