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
ChangeSet
at will, and for everything to still work as expected as they conform to theChange
interface.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.