The second pattern that we will talk about in this chapter is the proxy pattern. It is often used for security or optimization purposes.
The objective of the proxy pattern is to substitute an object (the subject) with another one that will control its access. The object that substitutes the subject shares the same interface, so it is transparent from the consumer's perspective. The proxy is often a small (public) object that stands in for a more complex (private) object that is activated once certain circumstances are clear. The proxy adds a level of indirection by accepting requests from a client object and passing them to the real subject as necessary.
The proxy pattern is used in object-oriented programming. There are several types of proxies, which are as follows:
The following class diagram is quite simple; we have an interface that defines our subject, both the proxy and RealSubject
implement this interface.
The client will call the proxy, not the RealSubject
object himself. The proxy contains a reference to the RealSubject
object. When the proxy receives a request, it can analyze it, and if the request is considered to be valid, it can be rerouted to the RealSubject.request()
method. The proxy can decide when to create, or not, the RealSubject
object avoiding to have to manage too big object in memory if useless. The following figure represent the generic class diagram of the proxy pattern:
There are only three participants in this pattern:
ISubject
: This is the common interface of the Proxy
and RealSubject
objectRealSubject
: This is the object that is controlled and manipulated by the proxy.Proxy
: This is the object that substitutes RealSubject
. It has the same interface of the RealSubject
object (the ISubject
interface). It creates, controls, enhances, and authenticates access to a RealSubject
object.The proxy receives the incoming request from a client instead of the RealSubject
. If necessary, the message is then delegated to the RealSubject
object. In this case, prior to the delegation, the proxy creates the RealSubject
object if it has not already been done.
We are developing a new software; this software presents a video catalog in a list. For each video in the list, we have a placeholder for the video and a description. The placeholder of the video first displays a screenshot of the video. If we click on this image, the video will be launched.
The video catalog contains videos, so it will be too heavy to have all of these videos in memory and transferring them through the network will take too long. The proxy pattern will help us organize all of this. We will create the subject only when we will need it, once the screenshot is clicked.
The two advantages are as follows:
The Screenshot
class that represents the video is called the proxy of the Video
subject. The proxy substitutes the Video
subject for the display. The Screenshot
class implements the same interface as the Video
subject (the RealSubject
object).
In our example, the proxy pattern design is as follows:
When the proxy receives the display()
message, it will display the video if this one already exists. If it receives the click()
message, it will first create the Video
subject and then load the video.
We will first define the interface that will be used by our proxy and real subject.
When we simulate the real behavior of these methods with Playground, these methods return a string, telling us what the code is expected to do. We can ensure what we are coding is correct by checking the message returned by Playground.
The interface will have only two methods: click()
and display()
:
protocol IAnimation{ func display() -> String func click() -> String }
The RealSubject
object is represented here with the video class. We implement the interface and display the message according to the action:
class Video:IAnimation{ func click() -> String{ return "" } func display()->String{ return "Display the video" } func load()->String{ return "Loading the video" } func play()->String{ return "Playing the video" } }
The proxy now implements the same interface as the RealSubject
object: the IAnimation
interface but has the intelligence to create the RealSubject
object, here the video
object, when needed in the click
method:
class ScreenShot:IAnimation{ var video:Video? func click() -> String { if let video = video { return video.play() } else { video = Video() return video!.load() } } func display() -> String { if let video = video { return video.display() } else { return "Display the screenshot of the video" } } }
The cool part is to simulate the client.
We first create a new proxy, Screenshot
, and then we simulate the operation. We call display
from the proxy. As the video is not created or loaded, it is the screenshot that will be displayed.
Then, we simulate a click. We can see that when we call the click
method, the video gets loaded. As the video is created and loaded, we call the display
method, which informs us that the video is now playing (instead of the screenshot of the video):
var animation = ScreenShot() animation.display() animation.click() animation.display()
The result in Playground is as follows:
Use the proxy pattern when you have objects, which are as follows:
Also, use the proxy pattern when you want to: