This post is part of a series of reviews on the book Design Patterns in Ruby. Check out the Introduction post for a full table of contents along with some generic principles regarding Design Patterns.

A Proxy is like an impostor. Much like the Adapter, it stands in the way between a client and the real object, which is useful when you need to create a protection barrier on your object without having to pollute it with authorization code, or when your object is really big and is on the other side of the world, so you want to delay at most any request to it.
Similar to the Adapter, the Proxy Pattern is heavily built on top of object composition and delegation, since it’s just a ‘fake’ object who passes over requests to a real object.

Let’s start with the protection proxy in the context of a BankAccount class, where you’d need the user to have permission to access his account. First, the BankAccount class:

class BankAccount
	attr_reader :balance
	
	def initialize(starting_balance = 0)
		@balance = starting_balance
	end
	
	def deposit(amount)
		@balance += amount
	end
	
	def withdraw(amount)
		@balance -= amount
	end
end

And now the proxy:

class AccountProtectionProxy
	def initialize(real_account, owner_name)
		@subject = real_account
		@owner_name = owner_name
	end
	
	def deposit(amount)
		check_access
		@subject.deposit(amount)
	end
	
	def withdraw(amount)
		check_access
		@subject.withdraw(amount)
	end
	
	def balance
		check_access
		@subject.balance
	end
	
	def check_access
		#for the sake of simplicity
		raise 'Not permitted'  unless @owner_name == 'pedro'
	end
end

proxy = AccountProtectionProxy.new(BankAccount.new, 'pedro')
proxy.deposit(50)
puts proxy.balance

We’re making sure on each method that the user has permission, and putting this code in the BankAccount class itself wouldn’t make sense (and would cause horrible coupling) since it’s not a bank account’s duty to deal with permissions, it should only deal with operations related to money, so we shove all the permission mess into a proxy, which works perfectly.

Now we’ll look at the virtual proxy, which delays creation of an object until he’s really needed, which is required when you have an object standing across a network and is expensive to be creating all the time. Sticking with the BankAccount class, let’s create a new proxy for it:

class VirtualAccountProxy
	def initialize(starting_balance=0)
		@starting_balance = starting_balance
	end
	
	def deposit(amount)
		subject.deposit(amount)
	end
	
	def withdraw(amount)
		subject.withdraw(amount)
	end
	
	def balance
		subject.balance
	end
	
	def subject
		@subject ||= BankAccount.new(@starting_balance)
	end
end

account = VirtualAccountProxy.new
account.deposit(50)
puts account.balance

A problem with this implementation of the virtual proxy is that the account object is being created inside it, which kind of couples the proxy to the BankAccount class. We can avoid this with the use of code blocks:

class VirtualProxy
	def initialize(&block)
		@block = block
	end
	
	#other methods
	
	def subject
		@subject ||= @block.call
	end
	
end

account = VirtualProxy.new {BankAccount.new}
account.deposit(50)
puts account.balance

One of the disavantages of the Proxy pattern is that you have to write a bunch of ‘decoy’ methods, such as the ones I omitted at this last piece of code, code that might not seem much for our little BankAccount class, but that would be a hassle with classes such as String with 142 methods or Array with 118. This is where Ruby shines.

When you call for a method that Ruby doesn’t find, it looks for a method named ‘method_missing’, which, if you don’t define yourself, is defined in the Object class from which every object in Ruby extends from. With that knowledge, we can define our own method_missing and redirect any method to the original object. Let’s refactor our virtual proxy to use this technique instead:

class VirtualProxy
	def initialize(&block)
		@block = block
	end
	
	def method_missing(name, *args)
		subject.send(name, *args)
	end
	
	def subject
		@subject ||= @block.call
	end
end
account = VirtualProxy.new {BankAccount.new}
account.deposit(50)
puts account.balance

What’s happening is:

  1. You call deposit(50), which the VirtualProxy class doesn’t know about.
  2. Since there’s no such method in our class, then Ruby searches for a method_missing method and passes it the name of the method that was called along with its parameters.
  3. We defined method_missing, telling it to send basically any incoming method to our subject.

And since our proxy is so decoupled from any implementation, we can use it with basically any class, such as Array:

array = VirtualProxy.new {  [] }
array << 'hello world'
puts array.first

The downside of this technique is performance. Since Ruby has to look at the class’ whole method table first and then send the method to the real object, things do get a bit slower than it would if the method simply existed, so you’d end up trading messiness for perfomance, which compensates sometimes.