Proxy Design Pattern

Filed Under: Design Patterns

Proxy Design pattern is one of the Structural design pattern and in my opinion one of the simplest pattern to understand.

Proxy Design Pattern

proxy design pattern
Proxy design pattern intent according to GoF is:

Provide a surrogate or placeholder for another object to control access to it.

The definition itself is very clear and proxy design pattern is used when we want to provide controlled access of a functionality.

Let’s say we have a class that can run some command on the system. Now if we are using it, its fine but if we want to give this program to a client application, it can have severe issues because client program can issue command to delete some system files or change some settings that you don’t want.

Here a proxy class can be created to provide controlled access of the program.

Proxy Design Pattern – Main Class

Since we code Java in terms of interfaces, here is our interface and its implementation class.

CommandExecutor.java


package com.journaldev.design.proxy;

public interface CommandExecutor {

	public void runCommand(String cmd) throws Exception;
}

CommandExecutorImpl.java


package com.journaldev.design.proxy;

import java.io.IOException;

public class CommandExecutorImpl implements CommandExecutor {

	@Override
	public void runCommand(String cmd) throws IOException {
                //some heavy implementation
		Runtime.getRuntime().exec(cmd);
		System.out.println("'" + cmd + "' command executed.");
	}

}

Proxy Design Pattern – Proxy Class

Now we want to provide only admin users to have full access of above class, if the user is not admin then only limited commands will be allowed. Here is our very simple proxy class implementation.

CommandExecutorProxy.java


package com.journaldev.design.proxy;

public class CommandExecutorProxy implements CommandExecutor {

	private boolean isAdmin;
	private CommandExecutor executor;
	
	public CommandExecutorProxy(String user, String pwd){
		if("Pankaj".equals(user) && "J@urnalD$v".equals(pwd)) isAdmin=true;
		executor = new CommandExecutorImpl();
	}
	
	@Override
	public void runCommand(String cmd) throws Exception {
		if(isAdmin){
			executor.runCommand(cmd);
		}else{
			if(cmd.trim().startsWith("rm")){
				throw new Exception("rm command is not allowed for non-admin users.");
			}else{
				executor.runCommand(cmd);
			}
		}
	}

}

Proxy Design Pattern Client Program

ProxyPatternTest.java


package com.journaldev.design.test;

import com.journaldev.design.proxy.CommandExecutor;
import com.journaldev.design.proxy.CommandExecutorProxy;

public class ProxyPatternTest {

	public static void main(String[] args){
		CommandExecutor executor = new CommandExecutorProxy("Pankaj", "wrong_pwd");
		try {
			executor.runCommand("ls -ltr");
			executor.runCommand(" rm -rf abc.pdf");
		} catch (Exception e) {
			System.out.println("Exception Message::"+e.getMessage());
		}
		
	}

}

Output of above proxy design pattern example program is:


'ls -ltr' command executed.
Exception Message::rm command is not allowed for non-admin users.

Proxy design pattern common uses are to control access or to provide a wrapper implementation for better performance.

Java RMI package uses proxy pattern. That’s all for proxy design pattern in java.

Comments

  1. Amit says:

    Just one thing wanted to check with you , should not it be good design if we do not expose proxy class to outer world and get it functionality done as kind of a filter before actually getting command fired.

    That is exactly kind of reference from your proxy class mentioned in serialization process blog. By doing this way outer world does not know internal structure whether there is any filter in place in middle.

  2. Ben qu says:

    In class CommandExecutorProxy, it looks like changing “private CommandExecutor executor;” to “private CommandExecutorImpl executor;” is more efficient. Why not use its implementation directly?

  3. Yogesh says:

    Client application can directly create instance of CommandExecutorImpl class and invoke runCommand.

    How this can be avoided?

    1. DEBARATI MAJUMDER says:

      Are you talking about overriding? We can declare the class or method as final to avoid overriding.

      1. Nina says:

        Hi, I have the same doubt as Yogesh. CommandExecutorImpl can not be overriden by declaring it to be final, but how to avoid directly creating instances of it by new CommandExecutorImpl(); ? Thanks.

        1. Pankaj says:

          Note that it’s hidden from Client side. In normal scenarios, you won’t even know how the executor is running the commands.

        2. Shubham says:

          Make the constructor private. In this case, the client won’t be able to get an instance of IMPL class.

          1. zahou says:

            If we make the constructor private, even the proxy class won’t be able to create an instance of the executor. On the other hand, we can make the executor class protected.

    2. Nimesh Nuwanjana says:

      Since both CommandExecutorImpl and CommandExecutorProxy are in the same package can’t we make CommandExecutorImpl final and use a protected constructor? So the clients won’t be able to create instance and still the CommandExecutorProxy could.

  4. Vijay Raj R says:

    Please explain all the 4 types of proxy pattern.

  5. prasad says:

    there is a chance of throwing NUllPointer Exception in the above program in case of the user is not an admin and the command he is issuing is not containing rm………………

    1. Paul says:

      Prasad I think you are wrong, there are no braces around the “if(“Pankaj”.equals(user) && “J@urnalD$v”.equals(pwd))” and this is legal if the if statement only has a songle line.

      So the command executor object is created every time, and the default for the boolean value is false. So you are incorrect.

  6. aneesh says:

    awsem one ….clearly understood the proxy pattern

  7. Amit says:

    Thanks, great tutorial. I will use it in future to provide restricted access.

Leave a Reply

Your email address will not be published. Required fields are marked *

close
Generic selectors
Exact matches only
Search in title
Search in content
Search in posts
Search in pages