Encapsulation : How ? Its a Dynamic Class.

This is in continuation to the previous post, Encapsulation:Why? , I thought it makes sense if we talk about the same principles to apply in a dynamic class.
First thing first, what is a Dynamic class?! Well, for those who are from AS1 and AS2 days, its in the blood kind of thing. We create an object then add on some properties to it in the runtime. But AS3 seems to take that freedom out. Well, not really, there are still some dynamic classes out there in AS3. Our very basic MovieClip is still a dynamic class. That means, we can still create new properties and methods in it. While the Sprite class is not.
Any new class we make in AS3 is known to be something called as a Sealed class. These classes cannot be modified to have new properties or methods in runtime. Whatever propeties and methods are declared at compile time is only available at runtime. So how to make a dynamic class, its just to declare a class with dynamic keyword as

public dynamic class MyDynamicClass
instead of
public class MyDynamicClass

Well, thats cool and fine. But why I would make one? The question may be answered by the way one designs an application, chances are you never want to make one or may be you just need some. So its all kind of depends how you want to program your application. Now if we make a dynamic class and add some properties, then how to controll its getter and setter as we have discussed earlier about controlling for a sealed class.
There is a very nice utility available at flash.utils package. Its the Proxy class. This does exactly, the same thing as we are searching for. Its a class, which is never being used by its own. Never instantiated. The only way to use it is to subclass it. Go over to the documentation to see a complete overview of the class.
Now lets jump directly to the code and see how it works. Then we will go on details about what it does. I think that way we can relate things while talking.  My proxy class begins like
public dynamic class MyProxyObject extends Proxy
{
}


Then there are 4 methods overridden, just to be with in accordance with the Proxy class’s work flow. These are as follows
override flash_proxy function callProperty(name:*, …rest):*{}
override flash_proxy function getProperty(name:*):*{}
override flash_proxy function setProperty(name:*,value:*):void{}
override flash_proxy function hasProperty(name:*):Boolean{}

Now thats all we have to do. The real code is shared here with both the classes for you to play arround.
The Main class/Document class is making an instance of our dynamic Proxy class and adds some properties and methods to it. Then, it calls to see what those return, this is done by
private function initApp():void
{
var mp:MyProxyObject = new MyProxyObject();
mp.age = -5;
mp.drink(‘ThumsUp’);
trace(‘Main : mp.age :’, mp.age);
trace(‘Main : mp.age :’, mp.age());
//
trace(‘Main : mp.drink :’, mp.drink());
}

Once this code is in place, we must run our application,just to see how it responds. Once we run the application, the traces would be as follows

MyProxyObject : setProperty : name= age : value= -5
MyProxyObject : callProperty : name= drink
MyProxyObject : getProperty : name= age
Main : mp.age : 0
MyProxyObject : callProperty : name= age
Main : mp.age : 2
MyProxyObject : callProperty : name= drink
Main : mp.drink : I am drinking ThumsUp

I think, they say a lot about the workings of our dynamic proxy class. Lets start analysing it.
The first call to the proxy class is to create a property named “age” as
mp.age = -5;
If it would not have a proxy, we could not have tracked what is actually happening in there. But since its a proxy subclass, the above property setting has to go through “setProperty()” method of the proxy class. Now the fun is, if we already know that while setting a property the call will go through “setProperty()” then we know where to check / manipulate the property value to be set. Its basically kind of global setter method of that particular proxy subclass. All the setters will go through it. Thats nice and we got our encapusulation logic put there, which would have gone in a setter for a non dynamic/ sealed class. Well, the question may be if the whole point of making a dynamic class is to add property in runtime, how we know what to check for in the setter ?! Thats a pretty nice question. Just think, if we follow a convention as to put soemthing such as “age_” in the beginning of all the dynamic properties we will be populating for age values of various kinds, then we can quickly check it in the “setProperty()” method that non of the age values should be less than zero. How to use it is upto the developer, but we have a provision here to do setter manipulation on a dynamic class.
Well, if we go and see next, the call is
mp.drink(‘ThumsUp’);
and the trace for this is
MyProxyObject : callProperty : name= drink
Thats pretty neat and I think you already have got the idea. Yes, all the method registrations will go through “callProperty()” method of the Proxy class. So thats all for setting a new property and method in a dynamic class. Lets move on to get some values.
we will be tracing it by
trace(‘Main : mp.age :’, mp.age);
and this gives us
MyProxyObject : getProperty : name= age
Main : mp.age : 0

The first call the straight and you already have guessed it, any call to get a property will go through “getProperty()” method. And then the surprise! why it gave back 0! when we have already set the age as -5! Well, this is exactly what we have talked above, if you go to the proxy subclass and see, the “setProperty()” implemenatation, we are already checking the negative age values and making them zero if its put negative. So the encapsulation of the checking in the setter is already in place. Similar things we can do with getters also, if we want to as its known now that every get method will hit “getProperty()” method of the proxy subclass.
Our next call is
trace(‘Main : mp.age :’, mp.age());
What! you are trying to get the “age” property by a method call?! Well the intention is to show where it ends up calling in the Proxy class. As we have already known any method call will go through “callProperty()” method of the proxy subclass, so is this call. And if you look inside the “callProperty” implementation, we are actually increasing the “age” value by 2 inside it. This is just to give an idea as to we have controll of that. If you try to test the value is actually checnged or not, then better to put another trace with just a property call like
trace(‘Main : mp.age :’, mp.age);
And that will trace out 0 again. So the setter value is not changed, the getter value is not changed but if we acces the same element through a method call like “mp.age()” we get the value incremented by 2. One can do whatever validation and code encapsulation required for the getter and setter and method call. The possibilities are kind of endless.
Lastly, lets try and see whether our actual method is called or not. This will be tested with
trace(‘Main : mp.drink :’, mp.drink());
and the trace it gives is
MyProxyObject : callProperty : name= drink
Main : mp.drink : I am drinking ThumsUp

That shows, it again goes inside the “callProperty()” method and then we can check it, whether its actually the method putting some values in or asking some values out. I have just put the different string there, just to know that we have control !!

That ends the encapsulation on dynamic objects. The proxy class has got some more neat and interesting features to be overriden and checked for. But these are some basic cool things at our fingure tips, if at all we need to controll the getter, setter and the method calls in a dynamic object.

The source files are here.

Hope that helps some understanding of Dynamic class, Proxy class and overall encapsulation thing.
Happy Flashing 🙂

Advertisements

Author: saumya

designer / developer / maker / educator @saumya

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s