tl;dr: This post describes an easy way to implement a proxy pattern in Godot with read-only reflection.
I occasionally find myself needing to use a proxy design pattern with GDScript. GDScript doesn't make this straight-forward to accomplish, so here's a simple approach that may be helpful for you!
What is a proxy pattern?
A proxy pattern is when you create a placeholder object and use this in-place of an underlying instance of the real object. A proxy class looks like the following:
This has many uses. Most of these uses boil-down to letting you extend the behavior of an object, while still maintaining the original object instance.
How to implement a proxy pattern?
Unfortunately, GDScript makes this difficult to do without a lot of brittle code duplication.
The naïve approach is to duplicate all methods and properties from the backer object on the proxy object, and then add logic to keep the two instances in-sync whenever one of them changes. This usually requires a ton of duplicated code, and can be a big headache to maintain when making updates to the logic of either class.
A better solution is to use some form of reflection to automatically define the proxy's state and behavior based on the backer. However, this would require being able to dynamically assign method definitions, which is not supported in GDScript.
A read-only proxy pattern
Fortunately, we can use GDScript to easily setup read-only state for our proxy. In this approach, we use reflection to duplicate all of the state from the backer object onto the proxy object. We then expect that the state of the backer object won't change.
This does still work if the backer's state will need to change at some point. We just need to add custom logic to handle updates in that case.
GDScript supports reflection through get_property_list(). This only tells us about the member variables of a class (not any of the methods), but this is sufficient for our use-case. However, there is a problem with get_property_list(); it includes all the properties on the direct class as well as any ancestor classes. We can run into problems if we try to re-assign some of the properties from ancestor classes, so we really need some way of querying only the direct properties of the current class.
Limiting Godot's get_property_list() to only properties on the direct child class
Fortunately, there is a way we can restrict our property query to only values on our direct class. We just need to query the properties from a parent class, and subtract these from the get_property_list() result. Here is an implementation for that:
Putting it all together
Here is an example which uses reflection to easily define a read-only proxy class:
🎉 Cheers!
Comments
Post a Comment