Design Patterns: elegant solutions for complex problems.

Trust, as we have seen, is a complex thing to model. To quantify it we need to look at a variety of parameters e.g. User behaviours, user provenance and user context. Each of these parameters will modify the trust value. However not all will be used in every setting. We will need different flavours of trust calculation and ways of keeping track of which was used to construct each trust calculation. Designing code to implement a complex model of trustworthiness is going to be a challenge, particularly if we want maintainable code built along proper Object Oriented design principles.

For instance:

Code (classes) should be open for extension, but closed for modification.

We may need to create new metrics for modifying specific trust values, especially as the application will be in Beta for a period of research. We may also need to change components of existing metrics and apply different steps in our calculations depending on the context of the calculation. However once we have working code, running in our application we don’t want to change it if we can avoid doing so as we can create all kinds of headaches and reduces the robustness of our application. Much better to have the ability and flexibility to add in those changes, extending what works, rather than tinkering with it.

Enter the decorator design pattern…decoratorUML

This is a UML class diagram that shows how a users provenance based trust is calculated.

Provenance based trust is derived from the characteristics of a user’s third party social media activity. Each verified account will apply a modifier to the value which then forms part of the users overall trust calculations. The calculation itself is a type defined by an abstract class – TrustRating. The concrete class Prov extends this and forms our basic rating which will initially have a very low value. An instance of this is stored in the user object as a field of type TrustRating and to obtain a value the method getRatingValue() is called.

Once a user has been verified with eBay a ‘decorator’ is used which takes the Prov object as a value in its constructor and stores it as a member variable. The Decorator, an abstract class, RatingFactor, also extends TrustRating so its instance is still a TrustRating object which can still be stored as a member of the user object. It also still has a getRatingValue() method. The trick is that the decorator has a slightly different implementation of this method. The instance is of the concrete class extending RatingFactor: EbayVerify()

The original Prov version has something like:

public int getRatingValue(){
return 3;
}

Whereas the EbayVerify object has:

public int getRatingValue(){
return trustRating.getRatingValue() + 34;
}

…so when the object is decorated – (in the diagram below there is also a Facebook decorator) we call getRatingValue on FacebookVerify, which calls getRatingValue() on ebayVerify, which calls getRatingValue() on Prov. Prov’s implementation returns ‘3’ which is added to ebayVerify()’s value in ebayVerify’s implementation of the method. This is then returned to getRatingValue() in FacebookVerify which adds its value which is returned as the calculation. Phew!methodchain

To modify the rating further we can add more decorators and use a chain of these method calls to perform the calculations.

This is a simplified version of the pattern which can have a lot more code in the decorators and can use more than one method chain to produce some complex calculations and modifications to the way values are calculated. For example we can also use another method chain to build a list of description codes which generate a detailed report explaining how the rating was produced. It may seem very drawn out but it makes life a lot easier because we can change the way the code works by adding new classes, extending it, rather than modifying existing working code.

Tinkering with what works is how you make bugs. Extending what works is how you make progress!

Leave a Reply