Home Tutorials Forums Articles Blogs Movies Library Employment Press Buy templates

Go Back   ActionScript.org Forums > General > Best Practices

Reply
 
Thread Tools Rating: Thread Rating: 1 votes, 5.00 average. Display Modes
Old 06-10-2008, 05:14 AM   #1
MichaelxxOA
Flash Sucks
 
MichaelxxOA's Avatar
 
Join Date: Mar 2005
Location: Victorville, Ca
Posts: 2,224
Send a message via AIM to MichaelxxOA Send a message via MSN to MichaelxxOA Send a message via Yahoo to MichaelxxOA Send a message via Skype™ to MichaelxxOA
Default class design stuff

Three good class traits

Note that in the following I'm saying class (to emphasize that this is about class design), but I'm really referring to an instance of that class (or an object). anyway ...

- all of the variables in a class are useful for as long as the class lives

- all of the methods in a class can be called independently of one another and in any order

- only the following methods are called:
-- methods that belong to the class
-- methods that belong to objects created within the method
-- methods that belong to objects which are arguments to the method
-- methods that belong to objects stored in the classes variables

Thoughts or opinions? None of these things are my creation, but I find them incredibly helpful (in practice) for quickly identifying weak points in my class (besides the usual stuff ... no duplication, complexity, etc.).

Try applying these three things to the code you are working with now. Chances are if one of them is being violated it should be moved to a new class (either one that exists or a new one altogether).

Of course there are quite a few other things that can be talked about, but these three things are easy to identify and tend to naturally lead me in the direction of a good design.

- M
MichaelxxOA is offline   Reply With Quote
Old 06-10-2008, 08:33 AM   #2
Flash Gordon
rather be programming
 
Flash Gordon's Avatar
 
Join Date: Feb 2005
Location: City of Angels
Posts: 10,000
Default

so how do these apply to build airplanes?? (sorry had to ask bro)
__________________
I'm old enough to know better and young enough to do it anyway. -- maskedman
Flash Gordon is offline   Reply With Quote
Old 06-10-2008, 08:34 AM   #3
Flash Gordon
rather be programming
 
Flash Gordon's Avatar
 
Join Date: Feb 2005
Location: City of Angels
Posts: 10,000
Default

could you give a bad example and good example of each point. I think that might help me a little.
__________________
I'm old enough to know better and young enough to do it anyway. -- maskedman
Flash Gordon is offline   Reply With Quote
Old 06-10-2008, 11:27 PM   #4
MichaelxxOA
Flash Sucks
 
MichaelxxOA's Avatar
 
Join Date: Mar 2005
Location: Victorville, Ca
Posts: 2,224
Send a message via AIM to MichaelxxOA Send a message via MSN to MichaelxxOA Send a message via Yahoo to MichaelxxOA Send a message via Skype™ to MichaelxxOA
Default

Quote:
Originally Posted by Flash Gordon View Post
so how do these apply to build airplanes?? (sorry had to ask bro)
LoL

Quote:
Originally Posted by Flash Gordon View Post
could you give a bad example and good example of each point. I think that might help me a little.
I've learned that the best way to demonstrate these things is with your own code. Do you have a class you've recently written that you feel could use some cleaning up?

I hope things are well mang.
MichaelxxOA is offline   Reply With Quote
Old 06-11-2008, 02:36 AM   #5
yell0wdart
jordanrift.com
 
Join Date: Sep 2007
Location: Phoenix, AZ
Posts: 297
Default

Sounds about right. I've always looked at class design with one thing in mind:

You should be able to describe what your class does in one short sentence.
__________________

bad developer

Jordan Rift
yell0wdart is offline   Reply With Quote
Old 06-11-2008, 03:21 AM   #6
Flash Gordon
rather be programming
 
Flash Gordon's Avatar
 
Join Date: Feb 2005
Location: City of Angels
Posts: 10,000
Default

Quote:
Originally Posted by MichaelxxOA View Post
I've learned that the best way to demonstrate these things is with your own code. Do you have a class you've recently written that you feel could use some cleaning up?
For sure. I'll post all of the code and we can walk through the elements and discuss some OO principles/patterns as well for the solution.

So the first to need is what's the problem: I'm trying to simplify the process of collecting data from a form and sending it server side. I need for the validation and object types to be encapsulated so that it may be changed out.

Here's what I got:


IFormCollection.as
ActionScript Code:
package com.*.v1.forms {     import flash.utils.Dictionary;     import com.*.v1.forms.FormValidationTypes;         public interface IFormCollection     {         function get allObjs():Array;         function get errorObjs():Array;         function get data():Dictionary;         function get requests():Dictionary;                 function addObj(obj:*, request:String=null, typeCheck:String="notRequired", errorMes:String=null, defaultTxt:String=null, noMatch:Array=null):void         function validate():Boolean;         function collect():void;         function focusActions():void;         function errorState():void;         function reset():void;     } }

TextFieldCollection.as
ActionScript Code:
package com.*.v1.forms {     import flash.text.TextField;     import flash.utils.Dictionary;     import flash.events.FocusEvent;         import com.*.v1.forms.FormValidationTypes;     import com.*.v1.forms.ValidationExps;         public class TextFieldCollection implements IFormCollection     {         protected var _servRequests:Dictionary = new Dictionary();         protected var _typeChecks:Dictionary = new Dictionary();         protected var _errorMes:Dictionary = new Dictionary();         protected var _defaultTxt:Dictionary = new Dictionary();         protected var _noMatches:Dictionary = new Dictionary();                 protected var _allObjects:Array = new Array();         protected var _errorObjects:Array = new Array();         protected var _collectData:Dictionary = new Dictionary();                 public function get allObjs():Array { return _allObjects; }         public function get errorObjs():Array { return _errorObjects; }         public function get requests():Dictionary { return _servRequests; }         public function get data():Dictionary { return _collectData; }                 public function TextFieldCollection()         {             //         }                         /**          * Function to add an object to the data collection          *          * @param obj For this class only TextFields are excepted          * @param typeCheck is how to validate the object's data. For instance NOT_REQUIRED or as EMAIL.          * @param noMatch This is an array of strings that if the objects data matches will add to an error count          */         public function addObj(obj:*, request:String=null, typeCheck:String=FormValidationTypes.NOT_REQUIRED, errorMes:String=null, defaultTxt:String="", noMatch:Array=null):void         {             if (!obj as TextField) throw new Error("TextFieldCollection::addObject obj argument must be a TextField object");                         _allObjects.push(obj);             _servRequests[obj] = (request != null) ? request : obj.name;             _errorMes[obj] = errorMes;             _defaultTxt[obj] = defaultTxt;             _typeChecks[obj] = typeCheck;                         if (noMatch == null) noMatch = new Array();             noMatch.push(errorMes);             noMatch.push(defaultTxt);             _noMatches[obj] = noMatch;                     }                 /**          * This method will cycle the allObjects array and validate the data          *          * @param return Returns true if data is all valid and false if there are errors          */         public function validate():Boolean         {             _errorObjects = new Array();                         for (var i:int=0; i<_allObjects.length; i++)             {                 var txt:TextField = _allObjects[i];                                 switch (_typeChecks[txt])                 {                     case FormValidationTypes.TEXT:                         checkText(txt);                         break;                     case FormValidationTypes.EMAIL:                         checkEmail(txt);                         break;                     case FormValidationTypes.TELEPHONE:                         checkTelephone(txt);                         break;                 }             }                         return (_errorObjects.length == 0) ? true : false;         }                 /**          * This collects the data from the objects and stores it in a dictionary instance          */         public function collect():void         {             for (var i:int=0; i<_allObjects.length; i++)             {                 var txt:TextField = _allObjects[i];                 _collectData[txt] = txt.text;             }         }                         /**          * This method loops through all of the registered textFields and if they text equals the default text or          * error message text it sets the textfield's text to blank ""          */         public function focusActions():void         {             for (var i:int=0; i<_allObjects.length; i++)             {                 _allObjects[i].addEventListener(FocusEvent.FOCUS_IN, focusIn);                 _allObjects[i].addEventListener(FocusEvent.FOCUS_OUT, focusOut);             }         }                 /**          * This method loops through all of the textfield that has invalid data and sets the error message          */         public function errorState():void         {             for (var i:int=0; i<_errorObjects.length; i++)             {                 _errorObjects[i].text = _errorMes[_errorObjects[i]];             }         }                         /**          * This method sets the TextFields in the collection back to the state before any errors          * or user input          */         public function reset():void         {             for (var i:int=0; i<_allObjects.length; i++)             {                 _allObjects[i].text = _defaultTxt[_allObjects[i]];             }         }                         /**          * This method check and text for to make sure it doesn't have empyt text and that it          * doesn't match one of the avoid strings if any of those conditions are met, it          * adds the textfield to an array of error and returns 1.          *          * @param return Returns 1 if there is an error and 0 if there is no error          */         protected function checkText(txt:TextField):Number         {             if (txt.text == "")             {                 _errorObjects.push(txt);                 return 1;             }                         for each (var value:* in _noMatches[txt])             {                 if (txt.text == value)                 {                     _errorObjects.push(txt);                     return 1;                 }             }                         return 0;         }                 /**          * This method check a textfield for a valid email address          *          * @param return Returns 1 if there is an error and 0 if there is no error          */         protected function checkEmail(txt:TextField):Number         {             var emailReg:RegExp = ValidationExps.EMAIL;                         if ( !emailReg.test(txt.text) )             {                 _errorObjects.push(txt);                 return 1;             }                         for each (var value:* in _noMatches[txt])             {                 if (txt.text == value)                 {                     _errorObjects.push(txt);                     return 1;                 }             }                         return 0;         }                 /**          * This method check a textfield for a valid telephone number address          *          * @param return Returns 1 if there is an error and 0 if there is no error          */         protected function checkTelephone(txt:TextField):Number         {             var emailReg:RegExp = ValidationExps.PHONE_EXT;                         if ( !emailReg.test(txt.text) )             {                 _errorObjects.push(txt);                 return 1;             }                         for each (var value:* in _noMatches[txt])             {                 if (txt.text == value)                 {                     _errorObjects.push(txt);                     return 1;                 }             }                         return 0;         }                         /**          * Protected function to set the focused textfield text to blank ""          */         protected function focusIn(e:FocusEvent):void         {             var txt:TextField = e.currentTarget as TextField;             if( txt.text == _defaultTxt[txt] || txt.text == _errorMes[txt])                 txt.text = "";         }                 /**          * Protected function to set the focused textfield text to default text if text is blank          */         protected function focusOut(e:FocusEvent):void         {             var txt:TextField = e.currentTarget as TextField;             if( txt.text == "" && _defaultTxt[txt] ) txt.text = _defaultTxt[txt]         }     } }
__________________
I'm old enough to know better and young enough to do it anyway. -- maskedman

Last edited by Flash Gordon; 06-11-2008 at 03:23 AM..
Flash Gordon is offline   Reply With Quote
Old 06-11-2008, 03:21 AM   #7
Flash Gordon
rather be programming
 
Flash Gordon's Avatar
 
Join Date: Feb 2005
Location: City of Angels
Posts: 10,000
Default

continued.......

FormHandler.as
ActionScript Code:
/**  * This class is basically a command-fascade pattern for handling forms. This class uses classes with the IFormCollection  * to collect data and validate contents. It then sends the data to a server side script.  *  * <p>The events dispatched from this class include:  * Event.INIT     - whenever the vars sends it to the server  * Event.COMPLETE   - whenever the server returns a response and it is in valid syntax  * ErrorEvent.ERROR - whenever something goes wrong from getting a response from the sever such as invalid syntax  * IOErrorEvent.IO_ERROR - whenever the url is not found.</p>  *  */ package {     import flash.text.TextFormat;     import flash.utils.Dictionary;     import flash.net.URLRequest;     import flash.net.URLVariables;     import flash.net.URLRequestMethod;     import flash.net.URLLoader;     import flash.net.URLLoaderDataFormat;     import flash.events.Event;     import flash.events.ErrorEvent;     import flash.events.IOErrorEvent;     import flash.events.EventDispatcher;     import flash.net.navigateToURL;         import com.*.v1.forms.IFormCollection;         public class FormHandler extends EventDispatcher     {         protected var collections:Array = new Array();         protected var allObjects:Array = new Array();         protected var errorObjects:Array = new Array();                 protected var allData:Dictionary = new Dictionary();         protected var allRequest:Dictionary = new Dictionary();                 protected var urlVars:URLVariables = new URLVariables();         protected var response:String;                         public function FormHandler()         {             //         }                         /**          * This method adds a collection          *          * @param collect A class that implements IFormCollection to be registered          */         public function addCollection(collect:IFormCollection):void         {             allObjects = new Array();             collections.push(collect);             for (var i:int=0; i<collections.length; i++)                 allObjects = allObjects.concat(collections[i].allObjs);                     }                         /**          * This method check all collections to see if they all have valid enteries          *          * @param return Returns true if everything is valid. False if there are errors.          */         public function validate():Boolean         {             var valid:Boolean = true;                         for (var i:int=0; i<collections.length; i++)             {                 var temp:Boolean = collections[i].validate();                 valid &&= temp; // must write this out the long was and it won't loop through if short hand             }                         for (var j:int=0; j<collections.length; j++) errorObjects.concat(collections[j].errorObjs);             return valid;         }                         /**          * This method loops through all the collections and add the data to a dictionary instance.          */         public function collect():void         {             var i:int;             for (i=0; i<collections.length; i++)             {                 collections[i].collect();             }                         for (i=0; i<collections.length; i++)             {                 var objs:Array = collections[i].allObjs;                 for (var j:int=0; j<objs.length; j++)                 {                     allData[ objs[j] ] = collections[i].data[ objs[j] ];                     allRequest[ objs[j] ] = collections[i].requests[ objs[j] ];                     urlVars[ allRequest[objs[j]] ] = allData[ objs[j] ];                 }             }         }                                 /**          * This method loops through all the collections and sets the objs to perform task upon an initial click          * such as clearing the text.          *          * @param tf is the TextFormat to apply to the obj after it has been clicked....MAYBE          */         public function focusActions(tf:TextFormat=null):void         {             for (var i:int=0; i<collections.length; i++)             {                 collections[i].focusActions();             }         }                         /**          * This method loops through all the collections and sets the errorObjs to the error status.          *          * @param tf is the TextFormat to apply to the error message....MAYBE          */         public function setErrors(tf:TextFormat=null):void         {             for (var i:int=0; i<collections.length; i++)             {                 collections[i].errorState();             }         }                         /**          * This method loops through all the collections and sets the objects back to the orignal states          */         public function reset():void         {             for (var i:int=0; i<collections.length; i++)             {                 collections[i].reset();             }         }                         /**          * This method allows additional variables to be sent in addition to the ones collected          * by the collections          *          * @param vars The URLVariables to send in addition to the collections          */         public function addVars(vars:URLVariables):void         {             for (var prop:* in vars)             {                 urlVars[prop] = vars[prop];             }         }                         /**          * This method sends the collected var to a url          *          * @param url Where to send the data          * @param method How to send the data          */         public function sendVars(url:String, method:String=URLRequestMethod.POST):void         {             var loader:URLLoader = new URLLoader();             loader.addEventListener(Event.COMPLETE, onComplete);             loader.addEventListener(ErrorEvent.ERROR, onError);             loader.addEventListener(IOErrorEvent.IO_ERROR, onError);                         var request:URLRequest = new URLRequest(url);             request.method = method;                         loader.dataFormat = URLLoaderDataFormat.VARIABLES;             request.data = urlVars;             loader.load( request );             //navigateToURL(request, "_blank");  // for debugging                         dispatchEvent( new Event(Event.INIT) );         }                 protected function onComplete(e:Event):void         {             try             {                 var loader:URLLoader = URLLoader(e.target);                 var variables:URLVariables = new URLVariables(loader.data);                 response = variables.echo;                                 dispatchEvent( new Event(Event.COMPLETE) );             }             catch(e:Error)             {                 dispatchEvent( new ErrorEvent(ErrorEvent.ERROR) );             }         }                 protected function onError(e:ErrorEvent):void         {             dispatchEvent(e); // this will dispatch an IO_ERROR or plain ERROR             //dispatchEvent( new ErrorEvent(ErrorEvent.ERROR) );         }             } }

Ok so there are many many problems with this. The first of which I've addressed above. The way it currently validates the input make it very difficult to extend it.

Maybe the class is trying to do too much and the client should be more responsible for handling errors in the validation.

What you think Michael? How's that mess for a start?
__________________
I'm old enough to know better and young enough to do it anyway. -- maskedman
Flash Gordon is offline   Reply With Quote
Old 06-11-2008, 03:37 AM   #8
MichaelxxOA
Flash Sucks
 
MichaelxxOA's Avatar
 
Join Date: Mar 2005
Location: Victorville, Ca
Posts: 2,224
Send a message via AIM to MichaelxxOA Send a message via MSN to MichaelxxOA Send a message via Yahoo to MichaelxxOA Send a message via Skype™ to MichaelxxOA
Default

I need for the validation and object types to be encapsulated so that it may be changed out.

-

I know what you mean by validation, but what do you mean by "object types"?
MichaelxxOA is offline   Reply With Quote
Old 06-11-2008, 03:39 AM   #9
Flash Gordon
rather be programming
 
Flash Gordon's Avatar
 
Join Date: Feb 2005
Location: City of Angels
Posts: 10,000
Default

TextField, comboBox, radioButton, TextInput, etc.....

I was trying to treat the all the same: as a type of IFormCollection.
__________________
I'm old enough to know better and young enough to do it anyway. -- maskedman
Flash Gordon is offline   Reply With Quote
Old 06-11-2008, 04:06 AM   #10
MichaelxxOA
Flash Sucks
 
MichaelxxOA's Avatar
 
Join Date: Mar 2005
Location: Victorville, Ca
Posts: 2,224
Send a message via AIM to MichaelxxOA Send a message via MSN to MichaelxxOA Send a message via Yahoo to MichaelxxOA Send a message via Skype™ to MichaelxxOA
Default

What about ...

A Form which contains a collection of FormElements.
A FormElement has a validate method which accepts a Validator object.
A Validator object also has a validate method that returns a boolean.

A FormElement can be something like a CheckBox, TextField, InputText, etc.

A Validator can be something like ... ZipCodeValidator, CreditCardValidator, etc.

You can handle multiple validations by making a CompositeValidator.

This is different from what I am going on about in this thread since I'm introducing a new design, but ... I don't know ... these are my initial thoughts.

Feedback.
MichaelxxOA is offline   Reply With Quote
Reply


Thread Tools
Display Modes Rate This Thread
Rate This Thread:

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump

Similar Threads
Thread Thread Starter Forum Replies Last Post
How to do a CSS Class that contain an instruction for bolding stuff ? Bracer HTML and JavaScript 1 02-20-2008 06:41 PM
Can I target a _root variable from another class? Munkey ActionScript 2.0 6 07-06-2007 04:14 PM
ColorTransform within custom class wmbenedetto ActionScript 2.0 2 05-12-2006 08:59 AM
Database simulated with arrays on a cd-rom lecasn5 Components 61 09-07-2004 12:40 PM
Is it mandatory to know OOP and class stuff to create a component??? CyanBlue Components 23 06-07-2003 02:06 PM


All times are GMT. The time now is 01:36 AM.


Powered by vBulletin® Version 3.8.4
Copyright ©2000 - 2009, Jelsoft Enterprises Ltd.
Ad Management plugin by RedTyger
Copyright 2000-2009 ActionScript.org. All Rights Reserved.
Your use of this site is subject to our Privacy Policy and Terms of Use.
You Rated this Thread: