Formal semantics of an Object-oriented programming language include encapsulated state. Is there a use-case for encapsulating a potential change, previous to the state change? Although the following examples are in PHP, please also think language-agnostic in your answer.
Background
I have a Client object whose responsibility is to send requests and retrieve responses from a server, and this is used to change state of an object that resides on another server by calling an API. There are a few Url's, one with the endpoint create and another with the endpoint update. The problem is, update can be used to update multiple different elements within the given object, each requiring different parameters.
'Layer' Objects
Imagine the object owns the following objects:
- ImageLayer
- BackgroundLayer
- TextLayer
- AudioLayer
- (N)Layer
In order to change the ImageLayer, the API requires:
- An ID
- The url of the new image
In order to change the TextLayer, the API requires:
- An ID
- What you are changing about it (is it the font, the size, the text content?)
- The new value
Now before you think this can simply be abstracted out to an id and a replacement value, consider the AudioLayer:
- An ID
- A bitrate
- The url of the new audio file
- Some other values
My Considerations
I originally considered adding Client::updateImageLayer(), Client::updateTextLayer(), but then realised that the Client object could become exponentially bigger given (N)Layer in the future.
Then I considered adding Client::updateLayer(Layer $layer, array $values) but I didn't think this was good enough.
Finally, here's another option I have been thinking about: a Change object.
Change Object
What if I created a Change object that encapsulated the change to any specific layer, and then this could be passed to the Client, already validated, and ready to be sent off in the request to the API?
interface Change
{
public function isValid();
public function getChanges();
}
class ImageLayerChange implements Change
{
protected $url;
protected $id;
public function __construct($id, $url)
{
$this->url = $url;
$this->id = $id;
}
public function isValid()
{
// Use a validator object to check url is valid etc
}
public function getChanges()
{
return array($this->id, $this->url);
}
}
Using the above, the Client object can loop around a set of Change objects, I could even make a ChangeSet, make sure they're all valid by calling isValid(), and call getChanges() to send the specific array direct to the API as it's all validated.
Questions
I have never heard of modelling change before. What do you think about the above option? Am I overcomplicating things? I liked the idea of being able to add / remove changes from a
ChangeSetat will, and for everything to still work as expected as they conform to theChangeinterface.Perhaps I'm not going about this the best way? Is there anything bad about my solution.
Are there any patterns I am using, or should be considering, when using either my solution or the one you propose? I am interested in good code.