Archive for the 'Object Oriented Design' Category

Accessing private class members in AS3

Tuesday, March 11th, 2008

Reflective programming is a very common, powerful, yet expensive software development practice. In most modern programming languages reflection can not be utilized to modify private members of an object, which is to be expected. However in certain circumstances, such as when developing very high level frameworks and automation APIs it may be beneficial at times to be have the ability to access private members of an object from outside of the public API of the class.

For instance, consider the following class definition:

// User class does not define setter functions for
// the private members _username and _password
package com.ericfeminella.example
{
    public class User
    {
        private var _username:String;
        private var _password:String;
       
        public function User(username:String, password:String)
        {
            this._username = username;
            this._password = password;
        }      
        public function get username() : String
        {
            return this._username;
        }
       
        public function get password() : String
        {
            return this._username;
        }
    }
}

The above class defines two private members: _username and _password. The public API of this class exposes these properties via the read-only accessors get username and get password. Per design assignments to these properties can only be made via the instance constructor.

So how can these values be modified once the object has been instantiated? More importantly, should this be allowed as the properties have not been publicly exposed? Theoretically they can not, philosophically they shouldn’t. All of this is debatable; however as a dynamic programming language ActionScript can easily accomplish accessing and modifying private members of an object which have not been exposed.

To do so is simple: define a method which provides an interface into the private members of the class instance, as in the following example:

// static method which provides a mechanism allowing
// private properties to be modified
public static function modifyMember(instance:User,
                                    property:String,
                                    value:*) : void
{
    try {
     instance[property] = value;
    }
    catch(error:ReferenceError)
    {
        throw new ArgumentError(property+not defined by+User);
    }
}

The above example is pretty straightforward. It is simply a static method which requires 3 arguments. The first being the instance of the class, the second is the property in which to assign a new value, and the third is the value to assign to the property. This static method can be defined in any class and will work fine - you only need to change the type of the instance argument and error message to match the type of the class in which the method is defined. All methods in a class definition have access to any member of the class therefore assignments can be made to an instance of the class via a static method. This is possible in most object oriented languages such as C# and Java, however ActionScript takes this approach into the dynamic realm thus making it much more robust as the actual properties which are to be modified can be specified at runtime.

This approach can just as easily be accomplished on the instance level as well via an instance method, as in the following:

// instance method which provides a mechanism allowing
// private properties to be modified
public function modifyMember(property:String, value:*) : void
{
    try {
       this[property] = value;
    }
    catch(error:ReferenceError)
    {
       throw new ArgumentError(property + not defined by+this);
    }
}

A client implementation for each would be as follows:

var vo:User = new User("foo", "bar");

trace( vo.username ); // foo
trace( vo.password ); // bar

// static implementation
User.modifyMember( vo, "_username ", "efeminella" );
trace( vo.username ); // efeminella

// instance implementation
vo.modifyMember( "_username ", "admin" );
trace( vo.username ); // admin
 

This approach is best suited for assigning values to simple types, or for pointing reference types to other object instances. This does not allow nested properties of a member to be accessed or modified (although it could easily be refactored to do so). Most importantly, (as you may be thinking) this breaks encapsulation and violates information hiding; therefore I do not recommend utilizing this approach for general use, however it is a convenient and efficient way to modify objects when developing complex APIs which use reflection and also for implementing Unit Tests directly against private members.

Initially I was introduced to the static implementation of this technique by a .Net developer on my team, and admittedly I was somewhat skeptical at first, however given the dynamic nature of ActionScript I realized this could open up some interesting possibilities under unique circumstances, similar to how mixins open up many possibilities - when used with discretion in a good design they both provide powerful advantages over other languages.

Food for thought. Enjoy.

Principle of Least Knowledge

Saturday, February 2nd, 2008

One very important (yet often overlooked) design guideline which I advocate is the Principle of least knowledge.

The Principle of Least knowledge, also known as The law of Demeter, or more precisely, the Law of Demeter for Functions/Methods (LoD-F) is a design principle which provides guidelines for designing a system with minimal dependencies. It is typically summarized as “Only talk to your immediate friends.”

What this means is a client should only have knowledge of an objects members, and not have access to properties and methods of other objects via the members. To put it in simple terms you should only have access to the members of the object, and nothing beyond that. Think if it like this: if you use more than 1 dot you are violating the principle.

Consider the following: We have three classes: ClassA, ClassB and ClassC. ClassA has an instance member of type ClassB. ClassB has an instance member of type ClassC. This can be designed in such a way which allows direct access all the way down the dependency chain to ClassC or beyond, as in the following example:

// ClassA defines a member of type ClassB and provides
// access to the instance
public class ClassA
{
    private var b:ClassB;
   
    public function getB() : ClassB
    {
         return b;
    }
}

// ClassB defines a member of type ClassC and provides
// access to the instance
public class ClassB
{
    private var c:ClassC = new ClassC();
   
    public function getC() : ClassC
    {
         return c;
    }
}

// ClassC could expose additional members and on and
// on creating more and more direct dependencies
public class ClassC
{
    public someType:SomeType;
    …
}

// client implementation
var a:ClassA = new ClassA();
var sometype:SomeType = a.getB().getC().someType;
 

The above example is quite common, however it violates The Principle of Least Knowledge as it creates multiple dependencies, thus reducing maintainability as should the internal structure of ClassA need to change so would all instances of ClassA.

Now keep in mind that in all software development there are trade-offs to some degree. Sometimes performance trumps maintainability or vice-versa, other times readability trumps both. A perfect example of where you would not want to use The Principle of Least Knowledge is in a Cairngorm ModelLocator implementation. The Cairngorm ModelLocator violates the Principle of least knowledge for good reason - it simply would not be practical to write wrapper methods for every object on the ModelLocator. This is the main drawback of the Principle of least Knowledge; the need to create wrapper methods for each object, which are more formally known as Demeter Transmogrifiers.

The goal of good software design is to minimize dependencies, and by carefully following the guidelines provided by The Principle of Least Knowledge this becomes much easier to accomplish.

API Design: Method parameter objects

Saturday, January 12th, 2008

When defining a constructor or method with more than three parameters it is considered a best practice to create a parameters object for holding the values which are required. This especially holds true when some of the parameters are optional (as they will contain default values) and also when two or more consecutive parameters are of the same type (as developers may accidentally transpose these parameters - which will not result in compile time or runtime errors, making debugging a nightmare!)

The most appropriate solution for such cases is to break up the method into separate methods, however when this is not feasible creating a parameters object will improve both code readability and provide a cleaner design which leaves less room for unexpected errors.

Consider the following method:

public function someMethod(a:String,
                           b:Object,
                           c:int = 1,
                           x:int = 2,
                           y:int = 3,
                           z:Boolean = true):SomeType
{

The parameters defined in this method are typical of what you will often see, however it is much cleaner and reliable to create a parameters object for holding these parameters. In addition, a parameters object allows for a much easier client implementation as default values need not be reassigned for all parameters which proceed a parameter which you need to specify a value other than the default value. For instance, if a method accepts 5 parameters and the first two parameters are required but the last three are optional, if you you need to specify a value for the last parameter you will need to re-assign the default values for the proceeding parameters, when in fact you really only need to specify three parameters.

The following example demonstrates creating a parameter object which can be passed to “someMethod”:

package
{
    public final class SomeMethodParams
    {
      public var a:String;
      public var b:Object;
      public var c:int = 1;
      public var x:int = 2;
      public var y:int = 3;
      public var z:Boolean = true;
       
      //only specify required parameters in constructor
      //optional parameters are simply public properties
      //which have default values assigned
      public function SomeMethodParams(a:String, b:Object)
      {
          this.a = a;
          this.b = b;
      }  
   }
}

When invoking “someMethod” clients can now simply instantiate an instance of the parameter object, set values only for what is needed and pass it in as follows:

var params:SomeMethodParams= new SomeMethodParams("a",{}) ;
params.z = false;

instance.someMethod( params );

So if you would like to improved code readability and provide proactive exception precautions, consider utilizing parameter objects for methods which require more than three parameters.

IResponder and Cairngorm

Friday, November 23rd, 2007

My original post on Cairngorm and IResponder had accidentally been deleted while updating my moderations queue, and many of you have contacted me stating that the post is no longer available so I will re-iterate what I mentioned in that post.

For some time now I have been entertaining the notion of abstracting IResponder implementations from Command classes into separate, discreet classes which are intended to handle asynchronous service invocation responses. There has been some talk in the Cairngorm community recently regarding Cairngorm Commands and IResponder implementations so I thought I would share my thoughts on the subject.

Typically most Cairngorm Events are handled by an associated Command. The Command handles the Event by updating a model on the ModelLocator, and / or instantiating a Business Delegate to manage invoking a middle-tier service.

At this point one could argue that the Command has finished doing it’s job - handling the Event. Let’s clarify by taking a look at a formal definition of the Command Pattern:

“The Command pattern is a design pattern in which objects are used to represent actions. A command object encapsulates an action and its parameters.”

From this we can deduce (in the context of a Cairngorm Event) that the Event is the “action” and the Command is the object which encapsulates the handling of the Event (action). The actual handling of the Service response could be considered a separate concern which is outside of the direct concern of the Event and Command, thus requiring an additional object to handle the service response.

However for many developers it is (by design) typical to simply have the Command implement IResponder and also handle the response from the service in addition to the actual Event. This makes sense from a convenience perspective, but not necessarily from a design perspective.

What I have been experimenting with is pretty simple and straightforward. It involves having a completely separate object implement IResponder and handle the service response directly.

Consider the following example in which a specific use-case requires an account log in. The following classes would be required: LoginEvent, LoginCommand, LoginResponder and LoginDelegate. Utilizing a separate class as the responder is very simple and straightforward and would be implemented as follows:

package events
{
  import com.adobe.cairngorm.events.CairngormEvent;
  import vo.LoginVO;

  public class LoginEvent extends CairngormEvent
  {    
    public static const LOGIN_EVENT:String="LoginEvent";
    public var vo:LoginVO;

    public function LoginEvent(vo:LoginVO)
    {
       super ( LOGIN_EVENT );
       this.vo = vo;
    }
  }
}

So far nothing different here, the above Event is just like any other CairngormEvent. Now let’s take a look at the Command implementation.

package commands
{
  import com.adobe.cairngorm.commands.ICommand;
  import com.adobe.cairngorm.events.CairngormEvent;
  import events.LoginEvent;

  public class LoginCommand implements ICommand
  {
    public function execute(event:CairngormEvent)
    {
      var evt:LoginEvent = event as LoginEvent;
      var re:IResponder = new LoginResponder();

      var delegate:LoginDelegate = new LoginDelegate(re);
      delegate.login(evt.vo.username, evt.vo.password);
    }
  }
}

Based on the above example, the only method which must be implemented is execute(), as defined by ICommand. The body of the execute() implementation instantiates an instance of LoginResponder and LoginDelegate, the LoginResponder instance is passed to the LoginDelegate as the IResponder instance.

As can be seen in the following example, the Business Delegate implementation is the same as any other typical Cairngorm Delegate:

package business
{
  import com.adobe.cairngorm.business.ServiceLocator;
  import mx.rpc.AsyncToken;
  import mx.rpc.IResponder;
  import mx.rpc.http.HTTPService;
  import vo.LoginVO;

  public class LoginDelegate
  {
    private var responder:IResponder;
    private var service:HTTPService;

    public function LoginDelegate(responder:IResponder)
    {
      this.responder = responder;
     
      var sl:ServiceLocator = ServiceLocator.getInstance();
      service = sl.getHTTPService( Services.LOGIN_SERVICE );
    }
   
    public function Login(vo:LoginVO) : void
    {
       var call:AsyncToken=service.send(vo.username,vo.password);
       call.addResponder( responder );
    }
  }
}

The IResponder implementation would be as follows:

package responders
{
  import mx.rpc.IResponder;

  public class LoginResponder implements IResponder
  {
    public function result(data:Object)
    {
      // result implementation…
    }

    public function fault(info:Object)
    {
      // fault implementation…
    }
  }
}

That’s pretty much it. Clean, simple, and yes, more code, however this design supports clean separation of concerns and promotes encapsulation and code reusability.

At the end of the day it really comes down to personal preference. For me, I always prefer to have more classes which encapsulate very specific tasks and responsibilities. As long as you have a clear and concise, but most of all, consistent design you usually can’t go wrong.