Where should I place an edited containers class? - actionscript-3

I would like to modify an Accordion class to suit my needs.
Instead of simply extending Accordion, I would like to copy and paste the whole class as a start, with the new class name "MyAccordion", into the src folder; to gain the maximum freedom(I assume).
However, several problems encountered. For the "include "../core/Version.as";" error, I had solved by replacing it with a explicit Version static const string. But for the problems lead by the inheritance, e.g. AccordionHeader, etc, I found that there would be too many files to be edited when going down the stream. I suspect I mis-understand the whole logic of editing the class.
Would anyone give me some help? May be some reference for me to read, or even just some keywords for me to search. Thanks in advance.

Well - for all the reasons your discovering, you actually don't have flexibility when leveraging "boilerplate" code like this. Use Extend and Override to properly modify existing classes:
package com.yourSite.src
{
public class Foo
{
public function Foo
{
}
public function foo():void
{
trace("foo");
}
}
}
package com.yourSite.src
{
public class Bar extends Foo
{
public function Bar
{
}
override public function foo():void
{
trace("bar");
}
}
}
So, write a class that Extends Accordion, and override anything that you want to work differently. Any other functionality you may need can be added as required. OOP 101 :D
Check out the link above for a more cohesive discussion.
Cheers!

Related

How to remove duplicate setup code from tests across classes

I have four java classes, each containing a test. They must remain like this; I can't put the four tests in one file.
Each file has a small setup portion at the top:
private SQSRequestCreator sqsRequestCreator;
private AssociateErgoTriggerStateDAO associateErgoTriggerStateDao;
#Inject
ClassName(SQSRequestCreator sqsRequestCreator, AssociateErgoTriggerStateDAO associateErgoTriggerStateDAO) {
this.sqsRequestCreator = sqsRequestCreator;
this.associateErgoTriggerStateDao = associateErgoTriggerStateDAO;
}
Each test uses the variables created above. This works! But, I would like to refactor this as to not have this code duplicated across 4 classes. I would like to have just one occurrence, and have the classes refer to it. I am not 100% sure this is possible, since the method in question is a constructor.
I tried making an abstract class like so:
public abstract class TestSetup {
public SQSRequestCreator sqsRequestCreator;
public AssociateErgoTriggerStateDAO associateErgoTriggerStateDao;
#Inject
TestSetup(SQSRequestCreator sqsRequestCreator, AssociateErgoTriggerStateDAO associateErgoTriggerStateDAO) {
this.sqsRequestCreator = sqsRequestCreator;
this.associateErgoTriggerStateDao = associateErgoTriggerStateDAO;
}
But this only works because the instance variables are public. They should be private. If anyone could suggest a way to refactor this code, I would be very grateful.
Thanks!

custom imports/non-local classes in as3

I was attempting to use this and this to figure out how to set up some math classes (the sin/cos functions I use for anything top down.) but I have it set to import package.class (the names of course.) but It said that "defintion package:Class not found". This confuses me and I am going to assume I have to do something with folders. However I'm not sure what folders to put it in/what to do to enter things specifically in a folder.
//import sthreets.CustomFuncs;
private function Movement()
{
if(LEFT==true)
{
rotation=rotation-6;
}
if(RIGHT==true)
{
rotation=rotation+6;
}
if(UP==true)
{
//x=x+CustomFuncs.TopDownMove("x", rotation, 0);
//y=y+CustomFuncs.TopDownMove("y", rotation, 0);
}
if(DOWN==true)
{
//x=x-CustomFuncs.TopDownMove("x", rotation, 0);
//y=y-CustomFuncs.TopDownMove("y", rotation, 0);
}
}
Commented out stuff was giving me errors, here's the CustomFuncs code.
package sthreets
{
public class CustomFuncs
{
public function CustomFuncs()
{
}
public function TopDownMove(xy:String, rot:Number, offSet:Number):Number
{
if(xy=="x")
{
return cos(DegreesToRadions(rot)+offSet)
}
if(xy=="y")
{
return sin(DegreesToRadions(rot)+offSet)
}
}
public function DegreesToRadions(rot:Number):Number
{
return rot*Math.PI/180;
}
}
}
Package names are determined by the location from src. src/my/package/name is my.package.name. The package you import at the top of any class must match the actual package, otherwise the compiler will not find the class.
So... say you have this structure in your folders:
src
->my
->package
->name
->ClassName
The class would be set up as so:
package my.package.name {
public class ClassName {
public function ClassName(){
//construct
}
}
}
And you would import it using:
import my.package.name.ClassName;
or
import my.package.name.*; //only use the wildcard if every class in that package is being used, otherwise you will include code you may or may not need to in your project
Hopefully that helps explain packages and imports a bit.
I also noticed that you are using the functions in your CustomFuncs class as if they were static (as you would with Math.cos() or similar). Your class is not set up to work this way. To do that, you need to use this static access modifier.
package sthreets
{
public class CustomFuncs
{
public static function TopDownMove(xy:String, rot:Number, offSet:Number):Number
{
if(xy=="x")
{
return cos(DegreesToRadions(rot)+offSet)
}
if(xy=="y")
{
return sin(DegreesToRadions(rot)+offSet)
}
}
public static function DegreesToRadions(rot:Number):Number
{
return rot*Math.PI/180;
}
}
}
The static access modifier means that the object (in this case, the functions) only exist once in any instance of the app, whereas a standard access modifier (public, private, protected, internal, mx_internal, final) create one object for every single instance of the class. Using the static access modifier allows you to access objects through ClassName.objectName because the objects belong to the class, not to the parent object. To get to those objects, you never have to instantiate (you will notice in the above code that I removed your constructor because it is unnecessary in this case).
Note: The following isn't necessarily directed at you, but I am including it for any future readers who might visit this question
This blog post gives a fairly good rundown of the standard access modifiers. The comparisons it makes in relation to beer are incredibly good and incredibly easy for someone with limited knowledge about the modifiers to understand.
I also suggest reading this Wikipedia article on "Static Variable" to help you understand what a static object is and where and how to use it.
AS3 strictly follows OOP (object oriented programming) and ECMAScript policies and its syntax is based heavily on Java. For these reasons, nearly every principle used by other OOP or ECMA languages applies to AS3 as well. This means that you can improve your AS3 skills by reading up on these principles, even if they are not specifically for AS3 (AS3 OOP tutorials are fairly limited in both quantity and quality so it can be difficult for someone who is learning AS3 as their first OOP language to learn these principles).

How can I create a subclass that takes in different parameters for the same function name?

So I have made this simple interface:
package{
public interface GraphADT{
function addNode(newNode:Node):Boolean;
}
}
I have also created a simple class Graph:
package{
public class Graph implements GraphADT{
protected var nodes:LinkedList;
public function Graph(){
nodes = new LinkedList();
}
public function addNode (newNode:Node):Boolean{
return nodes.add(newNode);
}
}
last but not least I have created another simple class AdjacancyListGraph:
package{
public class AdjacancyListGraph extends Graph{
public function AdjacancyListGraph(){
super();
}
override public function addNode(newNode:AwareNode):Boolean{
return nodes.add(newNode);
}
}
Having this setup here is giving me errors, namely:
1144: Interface method addNode in namespace GraphADT is implemented with an incompatible signature in class AdjacancyListGraph.
Upon closer inspection it was apparent that AS3 doesn't like the different parameter types from the different Graph classes newNode:Node from Graph , and newNode:AwareNode from AdjacancyListGraph
However I don't understand why that would be a problem since AwareNode is a subClass of Node.
Is there any way I can make my code work, while keeping the integrity of the code?
Simple answer:
If you don't really, really need your 'addNode()' function to accept only an AwareNode, you can just change the parameter type to Node. Since AwareNode extends Node, you can pass in an AwareNode without problems. You could check for type correctness within the function body :
subclass... {
override public function addNode (node:Node ) : Boolean {
if (node is AwareNode) return nodes.add(node);
return false;
}
}
Longer answer:
I agree with #32bitkid that your are getting an error, because the parameter type defined for addNode() in your interface differs from the type in your subclass.
However, the main problem at hand is that ActionScript generally does not allow function overloading (having more than one method of the same name, but with different parameters or return values), because each function is treated like a generic class member - the same way a variable is. You might call a function like this:
myClass.addNode (node);
but you might also call it like this:
myClass["addNode"](node);
Each member is stored by name - and you can always use that name to access it. Unfortunately, this means that you are only allowed to use each function name once within a class, regardless of how many parameters of which type it takes - nothing comes without a price: You gain flexibility in one regard, you lose some comfort in another.
Hence, you are only allowed to override methods with the exact same signature - it's a way to make you stick to what you decided upon when you wrote the base class. While you could obviously argue that this is a bad idea, and that it makes more sense to use overloading or allow different signatures in subclasses, there are some advantages to the way that AS handles functions, which will eventually help you solve your problem: You can use a type-checking function, or even pass one on as a parameter!
Consider this:
class... {
protected function check (node:Node) : Boolean {
return node is Node;
}
public function addNode (node:Node) : Boolean {
if (check(node)) return nodes.add(node);
return false;
}
}
In this example, you could override check (node:Node):
subclass... {
override protected function check (node:Node) : Boolean {
return node is AwareNode;
}
}
and achieve the exact same effect you desired, without breaking the interface contract - except, in your example, the compiler would throw an error if you passed in the wrong type, while in this one, the mistake would only be visible at runtime (a false return value).
You can also make this even more dynamic:
class... {
public function addNode (node:Node, check : Function ) : Boolean {
if (check(node)) return nodes.add(node);
return false;
}
}
Note that this addNode function accepts a Function as a parameter, and that we call that function instead of a class method:
var f:Function = function (node:Node) : Boolean {
return node is AwareNode;
}
addNode (node, f);
This would allow you to become very flexible with your implementation - you can even do plausibility checks in the anonymous function, such as verifying the node's content. And you wouldn't even have to extend your class, unless you were going to add other functionality than just type correctness.
Having an interface will also allow you to create implementations that don't inherit from the original base class - you can write a whole different class hierarchy, it only has to implement the interface, and all your previous code will remain valid.
I guess the question is really this: What are you trying to accomplish?
As to why you are getting an error, consider this:
public class AnotherNode extends Node { }
and then:
var alGraph:AdjacancyListGraph = new AdjacancyListGraph();
alGraph.addNode(new AnotherNode());
// Wont work. AnotherNode isn't compatable with the signature
// for addNode(node:AwareNode)
// but what about the contract?
var igraphADT:GraphADT = GraphADT(alGraph);
igraphADT.addNode(new AnotherNode()); // WTF?
According to the interface this should be fine. But your implemenation says otherwise, your implemenation says that it will only accept a AwareNode. There is an obvious mismatch. If you are going to have an interface, a contract that your object should follow, then you might as well follow it. Otherwise, whats the point of the interface in the first place.
I submit that architecture messed up somewhere if you are trying to do this. Even if the language were to support it, I would say that its a "Bad Idea™"
There's an easier way, then suggested above, but less safe:
public class Parent {
public function get foo():Function { return this._foo; }
protected var _foo:Function = function(node:Node):void { ... }}
public class Child extends Parent {
public function Child() {
super();
this._foo = function(node:AnotherNode):void { ... }}}
Of course _foo needs not be declared in place, the syntax used is for shortness and demonstration purposes only.
You will loose the ability of the compiler to check types, but the runtime type matching will still apply.
Yet another way to go about it - don't declare methods in the classes they specialize on, rather make them static, then you will not inherit them automatically:
public class Parent {
public static function foo(parent:Parent, node:Node):Function { ... }}
public class Child extends Parent {
public static function foo(parent:Child, node:Node):Function { ... }}
Note that in second case protected fields are accessible inside the static method, so you can achieve certain encapsulation. Besides, if you have a lot of Parent or Child instances, you will save on individual instance memory footprint (as static methods therefore static there exists only one copy of them, but instance methods would be copied for each instance). The disadvantage is that you won't be able to use interfaces (can be actually an improvement... depends on your personal preferences).

AS3 - Retype/Cast an inherited variable permanently in a subclass?

Possibly bad practice but I'm not well versed in software design anyway (I'm sure this question would have been asked before but I can't seem to find the right terminology)...Anyhow, it's just another curiosity of mine I'd like to have answered.
So I have worked in a way where I type a base class variable to type Object or Sprite or something similar so that in my subclasses, I can instantiate my custom classes into them and store it. And when I access it, I just cast that variable to ensure I can access the methods.
Take this example, so that you know what I'm talking about:
public class BaseClass
{
protected var the_holder_var:Object;
public function BaseClass()
{
//Whatever abstract implementation here...
}
}
Now, my subclasses of that base class usually use an interface but for simplicity sake, I'll just write it without it.
public class AnExtendedClass extends BaseClass
{
public function AnExtendedClass()
{
//Instantiate my own class into the base class variable
this.the_holder_var = new ACustomClassOfMine();
//Then I can use the 'hackish' getter function below to
//access the var's functions.
this.holder_var.somefunction()
}
private function get holder_var():ACustomClassOfMine
{
return this.the_holder_var as ACustomClassOfMine;
}
}
This works and I'm sure it will make some ppl cringe (I sometimes cringe at it too).
So now, my question, is there a way to recast/retype that base var in my extended subclass?
kinda like this:
public class ExtendedClass extends BaseClass
{
//Not possible I know, but as a reference to see what I'm asking about
//Just want to change the type....
override protected var the_holder_var:ACustomClassOfMine;
public function ExtendedClass()
{
//Then I can forget about having that hackish getter method.
this.the_holder_var = new ACustomClassOfMine();
this.the_holder_var.somefunction();
}
}
I was thinking of typing most of my base class vars that I use as holders as type * and retyping them as I extend the class. (I could use it here too but yeah...)
Thoughts? Comments? Ideas?
I actually think your code (apart from the hypothetical addition at the end) is pretty alright. The practise of adding accessors to solve the type issue you're dealing with is a solid one. I would advise to rename the accessor to show it is a cast, maybe get holderVarAsCustom():ACustomClassOfMine (I'm also not a big fan of the underscores, that's another language's convention), but that's personal preference. What I'd do to solve your last problem is just create a matching setter function:
private function set holderVarAsCustom(value:ACustomClassOfMine):void {
this.the_holder_var = value;
}
This way you can access the correctly typed holder var for both read and write operations with complete type safety:
holderVarAsCustom = new ACustomClassOfMine();
holderVarAsCustom.someFunction();
I would definately advise against dropping the type safety by including arrays and what not, that just makes it unstable.
I must admit that i'm a little confused as to why you want to do this, but here goes. Could you not utilise the fact that Array's can hold different data types. So something like this:
public class BaseClass
{
protected var customStorage:Array;
public function BaseClass()
{
//Whatever abstract implementation here...
}
}
You could then access it with an associative method and a property:
public class AnExtendedClass extends BaseClass
{
private static const myName:String = "myName";
public function AnExtendedClass()
{
//Instantiate my own class into the base class variable
customStorage[myName] = new ACustomClassOfMine();
objectIWant.somefunction()
}
private function get objectIWant():ACustomClassOfMine
{
return ACustomClassOfMine(customStorage[myName]);
}
}
Is that any better?
I would not try to tinker this behaviour, since you can't change the declared type of a variable once declared, no matter how hard you try.
What I do in such cases, I either cast the variable if I use it sparingly or the object it references may change, or I add another variable with the type I want and let the other variable point to the new one. Like this:
public class A {
protected var object:Object;
public function A() {
//Whatever abstract implementation here...
}
}
and
public class B extends A {
protected var other:MyClass;
public function B() {
super();
this.other = new MyClass();
this.object = this.other;
}
}
Having it this way, class A uses the object via the this.object reference, and class B can use the this.other or both. But both references point to the same object. The only issues with this are:
having two references for in the same class to the same object is ugly (so are untyped variables and casts)
if the object one of them may point can change during runtime, you must be really carefull to synchronize these changes

Friend methods/classes for AS3 packageless classes

Hi I'm wondering if I can have a packageless () AS3 class call a private method on the main class in the file. For example:
package demo
{
public class MyDemoClass
{
var helper:FriendlyHelperClass = new FriendlyHelperClass(this)
}
private function methodToCall():void
{
...
}
}
public class FriendlyHelperClass
{
public function FriendlyHelperClass(demo:MyDemoClass)
{
demo.methodToCall()
}
}
The call to methodToCall() from FriendlyHelperClass will fail as it is a private member of the MyDemoClass. Is there any way to call the methodToCall() method from the FriendlyHelperClass without extending MyDemoClass.
Basically I'm looking for inner class functionality that Java has or some sort of C++ style friend class.
Short answer : no.
You can never access a private member from outside a class in ActionScript. What you could do is use a namespace instead of a private scope. This would allow to give access to some members to selected classes. This is the closest of a friend class that you will get in AS3.
I'm afraid that is not possible, but if you make the class dynamic, then you can edit it while the program is running, and possibly add some useful functions to it, to access the private functions. I haven't tried it though.
Dynamic classes
Without testing the code, and knowing what your full problem. you can try passing the functions you need into the embedded class as a callback. e.g.,
helper.methodToCallCallback = this.methodToCall;
then inside FriendlyHelperClass:
this.methodToCallCallback();