Handling client-side domain object state in a presentation model

505 Views Asked by At

I'm currently building the client side of a Flex/PHP project using the Presentation Model pattern.

What I'm trying to achieve:
I currently have a view displaying non-editable information about a domain object called Node. Depending on if the Node is editable and the user has the right privileges, an additional view becomes available where it's possible to make changes to this object. Any changes made are only committed to the server once the user decides to "Save Changes". If changes are made to a NodeA and the user navigates away to a different NodeB without saving them, NodeA is reverted to its original state.

Design:
I have a PM for the info view holding a reference to the current Node. The PM for the edit view is extended from this info PM, adding methods to make changes to the wrapped Node object. Both PMs has the same Node reference injected into them and all fields in the info/edit views are bound to the Node via their PMs.

The problem:
When the user makes changes to NodeA but doesn't commit them, I can't seem to think of an elegant solution to revert back to the original state. Basically, what I've thought of so far is to hold separate value copies on the edit PM, either clone-creating a new Node reference or through an identical set of Node properties. Of these two the former seems like the better idea because the Node already houses domain logic, but I wonder whether creating clones of unique domain objects is a bad practice, even if it's used in a limited scope.

2

There are 2 best solutions below

3
On

Each view should have it's own instance of your Presentation Model class. Just maintain it in memory if the user has not saved it when moving to another view. Cloning accomplishes basically the same thing through a more convoluted process.

1
On

I handle similar cases by storing the original data in an XML property of the Value Object ("VO"), and reset all of the other property values when the VO is needed.

So, when it is first needed to be viewed, I go get the XML:

<Node>
    <prop1>value</prop1>
    <prop2>value</prop2>
    <prop3>value</prop3>
    <prop4>value</prop4>
</Node>

When I retrieve the XML, in my result handler, the first thing I do is create an instance of my VO, and set the XML property, and then call a public function in a separate class to set the VO's properties:

private function getNodeResultHandler(event:ResultEvent):void
{
    var myNode:Node = new Node();

    myNode.xmlData = new XML(event.result);

    nodeUtils.setNodeProperties(myNode);
}

public class nodeUtils
{
    public function setNodeProperties(node:Node):void
    {
        var nodeXmlData:XML = node.xmlData;

        myNode.prop1 = nodeXmlData.prop1;

        myNode.prop2 = nodeXmlData.prop2;

        myNode.prop3 = nodeXmlData.prop3;

        myNode.prop4 = nodeXmlData.prop4;
    }
}

Then, any time you switch your view to edit mode, you call that same function to reset the properties to the values stored in the XML.

The only other thing you need to do is reset that XML any time the user commits changes to the VO. I usually handle this by passing back the VO's data in the same format on a Save and Get, and then saving the XML just as above.

I usually do this in a Cairngorm MVC application, so I have event/command chains to handle all of this, but you can put this functionality in any number of classes, or in the VO class itself, whichever is easiest for you to maintain.