Published: February 26, 2021 • 2 min read
I had the opportunity recently to implement a simple version of a proxy class. In this post, I’d like to talk about what a proxy class is, and share my implementation.
Proxies reflect a service interface. The proxy must match the interface of its service object, the thing it is proxying. If the service object quacks, so must the proxy.
Proxies hold their service object in a reference called a reference field. This is how proxies memoize their service object and delegate requests.
Another feature of a proxy is supporting methods. These can report information, handle side effects, and more. Often, these methods are the reason for building the proxy.
Here’s my implementation, and then again with comments.
class Proxy
def initialize(service_object)
@call_history = []
@service_object = service_object
end
def method_missing(method, *args)
@call_history.push(method)
if @service_object.respond_to?(method)
@service_object.send(method, *args)
else
raise NotImplementedError
end
end
def times_called(method)
@call_history.count { |called| called == method }
end
end
class Proxy
def initialize(service_object)
@call_history = [] # Support our supporting methods
@service_object = service_object # Creates reference field.
end
def method_missing(method, *args) # Catch missing methods.
@call_history.push(method) # Record every call.
if @service_object.respond_to?(method) # 🪄 Delegate calls.
@service_object.send(method, *args)
else
raise NotImplementedError
end
end
def times_called(method) # 👏 Supporting methods
@call_history.count { |called| called == method }
end
end
For a deeper dive, check out Proxy in Ruby on ‘Refactoring Guru’. It’s an outstanding resource.
What are your thoughts on this? Let me know!
Get better at programming by learning with me! Join my 100+ subscribers receiving weekly ideas, creations, and curated resources from across the world of programming.