Avg. Rating 3.4

Problem

In an application you usually have users with different roles and have common behavior for a group of users. Instead of having this spread all over the place it is a better idea to structure this kind of logic. One way of doing this is to implement a policy based solution where you have reusable policies which can be used throughout your application.

Solution

This solution uses the built in reflection mechanisms in Action Script 3 to write a generic policy handler which allows developers to easily create policies which can be applied to any user interface component or other classer.

Detailed explanation

The basic scenario is that you have a User object which has one or more Roles which in some cases determines if a policy applies or not. Say for instance that you have a user who has an Administrator role, then he should see the debug console in the application. How would we do this in a neat way in order to not duplicate too much code and not have tons of boiler plate code?

I wanted the policy logic to be in simple classes which needed to be very flexible. In my sample you loose some of the security of type safety as the apply method in the Policy interface takes in an object as a parameter, but I think the benefits of having very flexible arguments makes up for the lack of compile time feedback.

The policy interface
Simple interface which all policy classes must implement. The apply method returns true is the policy applies to the given input criteria.

public interface Policy {
  function apply(criteria:Object) :Boolean;
}

The policy manager

In order to have a simple unified way of using the policies I implemented a manager class which has one static method, applies, which executes the input policy class with the given criteria. This class checks that the input policy is indeed is a class implementing the correct interface.
The reason why you can not pass in a Policy object into the applies method is that I wanted to call this method without having to instantiate the policy classes when calling the manager.

public class PolicyManager {
public static function applies(policy:Class, criteria:Object):Boolean {
  var description:XML = describeType(policy);
  var typeName:String = description.@name.toXMLString();
  var inferfaceName:String
  = description.factory.implementsInterface.@type.toXMLString();
  if (-1 != inferfaceName.indexOf("Policy")) {
  var passedInClass:Class = getDefinitionByName(typeName) as Class;
  var policyInstance:Policy = new passedInClass();
  return policyInstance.apply(criteria);
  }
  throw new Error("Passed in class does not implement the Policy interface");
  }
}

Here is how it would look if you where to use this way of implementing policies. You could also use this in a binding expression in MXML.

if (PolicyManager.applies(PriviledgedUser, user)) {
  //....
}

Here is how the PrivilidgedUser policy might look like:

public class PriviledgedUser implements Policy {
  public function apply(obj:Object):Boolean {
  if (obj is User) {
  return User(obj).role == "Administrator";
  }
  throw new Error("Invalid arugment, must be a User class");
  }
}

This is one way of doing this and you might think that this is really too much code for solving something that could be done with just a simple if-statement. Which would be true of course if you only applied your policies in one place and never had to maintain the code. I think for larger applications doing something similar will be beneficial.
This article is also available in the blog post  Implementing policies using reflection in Action Script 3.

Report abuse

Related recipes