Proxy Design Pattern: Structural pattern that provides a surrogate or placeholder to control access to another object.
Some real-world examples where Proxy Design Pattern can be applied:
Web Browsers Caching: Web browsers utilize caching proxies to store frequently accessed web pages, enhancing browsing speed by serving locally stored copies.
Smart Home Access Control: In smart home systems, proxies enforce access control policies for devices, ensuring only authorized users can interact with them.
Lazy Loading in Web Applications: Proxies enable lazy loading of large resources in web apps, improving performance by loading resources only when needed.
RPC in Distributed Systems: Proxies facilitate remote procedure calls in distributed systems, handling communication between components seamlessly.
Virtual Private Networks (VPNs): VPNs utilize proxies to create secure tunnels, safeguarding user privacy by encrypting internet traffic and masking IP addresses.
public class Movie {
    private String name;
    public Movie(String name) {
        this.name = name;
    }
    @Override
    public String toString() {
        return name;
    }
}
public interface MovieBooking {
    public int bookMovie(String client, Movie movie) throws Exception;
    public void cancelMovie(String client, int ticketId) throws Exception;
    public Movie searchMovie(String client, String movieName) throws Exception;
}
//Implementation Class
public class MovieBookingImpl implements MovieBooking{
    @Override
    public int bookMovie(String client, Movie movie) throws Exception {
        Random random = new Random();
        // Generate a random number using the timestamp
        int randomNumber = random.nextInt();
        System.out.println("Book a Ticket");
        return randomNumber;
    }
    @Override
    public void cancelMovie(String client, int ticketId) throws Exception {
        System.out.println("Cancel a Ticket with ticket ID" + ticketId);
    }
    @Override
    public Movie searchMovie(String client, String movieName) throws Exception {
        System.out.println("Fetching data from datastore..!");
        System.out.print("We found the following show timing for the movie: ");
        return new Movie(movieName);
    }
}
//proxy Class: It will control access, based on user type
public class MovieBookingProxy implements MovieBooking{
    MovieBooking movieBookingObj;
    MovieBookingProxy(){
        movieBookingObj = new MovieBookingImpl();
    }
    @Override
    public int bookMovie(String client, Movie movie) throws Exception {
        if (client.equals("USER") || client.equals("AGENT")) {
            return movieBookingObj.bookMovie(client, movie);
        } else if(client.equals("GUEST")){
            System.out.println("Return to signUp Page..!!");
        }
        throw new Exception("Access Denied");
    }
    @Override
    public void cancelMovie(String client, int ticketId) throws Exception {
        if(client.equals("USER")) {
            movieBookingObj.cancelMovie(client, ticketId);
            return;
        }
        throw new Exception("Access Denied");
    }
    @Override
    public Movie searchMovie(String client, String movieName) throws Exception {
        if(client.equals("USER")||client.equals("AGENT")|| client.equals("GUEST")) {
            return movieBookingObj.searchMovie(client, movieName);
        }
        throw new Exception("Access Denied");
    }
}
public class ProxyDesignPatternExample {
    public static void main(String[] args) {
        try{
            MovieBooking movieBooking = new MovieBookingProxy();
            String client = "AGENT";
            String movieName = "Tare Jameen Paar";
            Movie movie  = movieBooking.searchMovie(client, movieName);
            System.out.println(movie);
            System.out.println("Please wait..!! Connecting to Server...");
            movieBooking.bookMovie(client, movie);
            System.out.println("Movie Booking Successful..!!");
        } catch(Exception e){
            System.out.println(e.getMessage());
        }
    }
}