Is it ok to reference an abstract class in interface? - actionscript-3

I am trying to write a little Entity-Component based game framework for myself. I just encountered an logic problem with my base class system.
The thing is I have an two things, Entities ( that can contain other entities and component ), and Components ( they are attached to certain entity ).
So I made two interfaces :
interface IEntity
interface IComponent
And I made a abstract classes for each
public class Component implements IComponent
public class Entity extends Sprite implements IEntity, IComponent
The problem is that in IEntity interface I have an function:
function addComponent( e:Entity )
The reason the argument type i Entity, is because then in Component I need to reference to the entity functions that it inherits from Sprite ( I cannot do that with IEntity type ).
But it seems that Flash Develop treats it as an error ( implementation of this function in Entity class ). Am I doing something wrong?
EDIT :
This are the interfaces:
public interface IComponent
{
function get parentGameObject() : IEntity;
function set parentGameObject( v:IEntity ) : void;
function init() : void;
function dispose() : void;
}
public interface IEntity
{
function addComponent( c:IComponent ) : IComponent;
function removeComponent( c:IComponent ) : Boolean;
function getComponent( type:Class ) : IComponent;
function hasComponentOfType( type:Class ) : Boolean;
function addGameObject( child:Entity ) : void;
}
Then my abstract Entity class implements both of this interfaces + extends from DisplayObjectContainer because each Entity needs the functionality of rendering itself and its child Entities.
The problem is that :
public function addGameObject( e:Entity ) : void {
m_components.push( v );
this.addChild( v );
v.gameObject = this;
v.init();
}
seems to be invalid, and the error is : interface method addGameObject in interface IEntity is implemented with incompatibile signature in class Entity.
And the reason I want to use e:Entity and not e:IEntity is because I am using this.addChild( v ), which belongs to DisplayObjectContainer.
Hope that clears my question.

I still can't see why this error is thrown, the implementation of addGameObject looks ok so far (I assume the usage of v is a problem that just exist in the example code?), though the parameter name differs from the interface definition where it's child instead of e, however AFAIK this is valid in AS3, nonetheless try using the name as defined in the interface.
And regarding the actual question, of course the answer depends. Generally you can reference whatever classes you like in an interface, the only problem here should be design patterns.
If you want to continue programming against interfaces, then you could simply create an game object interface that forces to implement the addChild method, something like this:
import flash.display.DisplayObject;
public interface IGameObject extends IComponent, IEntity
{
function addChild(child:DisplayObject):DisplayObject;
}
Change your IEntity interface, your addGameObject and Entity implementation accordingly and you should be good to go:
public interface IEntity
{
...
function addGameObject( child:IGameObject ) : void;
}
public function addGameObject( child:IGameObject ) : void {
...
}
public class Entity extends Sprite implements IGameObject
Though you might want to rename Entity to something like GameObject in order to avoid confusion.

This is how I solved this problem for now:
Three basic interfaces for each GameObject functionallity:
public interface IComponent
{
function get gameObject() : IGameObject;
function set gameObject( v:IGameObject ) : void;
function init() : void;
function dispose() : void;
}
public interface IDisplayObjectContainer
{
function get displayContainer() : DisplayObjectContainer;
}
public interface IEntity
{
function addComponent( c:IComponent ) : IComponent;
function removeComponent( c:IComponent ) : Boolean;
function getComponent( type:Class ) : IComponent;
function hasComponentOfType( type:Class ) : Boolean;
}
And my compound GameObject interface for now is extending all of this functionallity:
public interface IGameObject extends IEntity, IComponent, IDisplayObjectContainer
{
function addGameObject( g:IGameObject ) : void;
}

Related

Attempted access of inaccessible method for interface function?

I can't see what is wrong with this. I have a class MyConnectionManager that has this code:
public class MyConnectionManager {
private var _delegate:NetworkConnectionDelegate;
public function myfunc():void
{
this.delegate.onError(1); // compile error here!
}
public function get delegate():NetworkConnectionDelegate
{
return _delegate;
}
etc
}
where NetworkConnectionDelegate is an interface and has a method onError()
public interface NetworkConnectionDelegate {
function onError(x:int):void;
}
But the compiler (Flash Builder) says that onError is an inaccessible method when compiling MyConnectionManager. Why won't it compile?
Interface describes public structure of class instance.
You need to create you class, and then implement it from defined interface.
Like,
Class:
public class NetworkConnectionDelegate implements IError {
...
// implements to IError interface
public function onError(x : int) : void {
..
}
}
Interface:
public interface IError {
function onError(x : int) : void;
}
belive it or not, the above code is perfectly fine. It was a syntax error in a completely different source file that must have freaked out Flas Builer to cause the compiler error. Once i fixed the totally unrelated error, it compiled just fine. This sort of compile error would never have happened in a decent compiler like VV++ or XCode, but FB seems a liitle flakey. oh well.

How can I subclass a class loaded from a swf

I want to subclass "superClass" and override one of it's functions.
public class superClass {
protected function f1(...) : Boolean {...}
protected function f2(...) : Boolean {...}
...
protected function f100(...) : Boolean {...}
}
public class subClass extends superClass {
// override f1 in the subclass
protected override function f1(...) : Boolean {...}
}
The problem is that the "superClass" is loaded from a swf. I do not have a reference to the class definition in my project. Is there a way to do something like below?
public class subClass {
private var superClassObject: Object;
// construct from an instance of superClass
public function subClass (s : Object) {
superClassObject = s;
}
private function myF1(...) : Boolean {...}
override InvokeFunction (fname: string, args: Array) : Object {
if (fname == "f1") {
return myF1(args);
} else {
return superClassObject.InvokeFunction(fname, args);
}
}
}
I'm not sure how function call is implemented in AS. What should "InvokeFunction" be?
You should use .swc , not .swf. The class you want to extend must be available at compile time, not at runtime. Anyway if using of swf is mandatory for you, you could use different techniques to 'override' functionality.
Besides inheritance there are other OOP concepts (Composition, Aggregation,etc...) and design patterns(Proxy,Adapter,etc...) for changing functionality of class. You could use them.

Check if Class Implements a Specific Interface

in ActionScript 3.0, there are a few ways to check a class's extension. for example, if i want to know of a custom class extends Sprite i could use the is operator:
trace(MyClass is Sprite);
or i could use flash.utils.getQualifiedSuperclassName:
trace(getQualifiedSuperclassName(MyClass));
i would like to accept a class as an argument and check to see if the passed class implements an certain interface. is there an equally simple or common way to check if my custom class adheres to an interface? perhaps something like:
trace(MyClass implements IMyInterface);
Use something like this function:
public function isImplementing( MyClass:Class, MyInterface:Class ):Boolean
{
var description:XML = describeType( MyClass );
var interfaceName:String = getQualifiedClassName( MyInterface );
return Boolean( description.factory.implementsInterface.( #type == interfaceName ).length() != 0 );
}
This function returns true if the class is implementing the interface.
why not just trace(MyClass is IMyInterface);?

t4mvc : Cannot inherit a controller class which has no default constructor?

I am using T4MVC with MVC2.
I have the following building blocks:
A simple entity interface which defines that every POCO entity must have a long Id property:
public interface IEntity
{
public long Id;
}
A simple POCO class which implements the IEntity interface and has some string properties:
public class CD : IEntity
{
public long Id { get; set; }
public long Name { get; set; }
}
A base controller:
public abstract class EntityController<T> : Controller where T : class, global::IEntity
{
public EntityController(IEntityManager<T> manager);
}
I use this base controller in my CDController (where CDManager implements the IEntityManager interface, which is a UnitOfWork pattern to add CRUD functionality):
public partial class CDController : EntityController<CD>
{
public CDController() : base(new CDManager()) { }
}
When I run my t4 template, this code is generated:
namespace MyApp.Web.Controllers {
public partial class CDController {
[GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
protected CDController(Dummy d) { }
But this gives me an error during compilation:
MyApp.EntityController<CD> does not contain a constructor that takes 0 arguments
How can I solve this?
I wanted by controller base class to be abstract and it's constructor protected and parametrized. Got around this issue by adding a blank constructor to ControllerBase that throws a NotImplementedException.
Doesn't quite feel right but it gets the job done. Only issue is when combined with dependency injection the wrong constructor will be called - since it throws an exception the app will bum out.
Code:
public abstract class ControllerBase : Controller
{
protected object AlwaysSupply { get; private set; }
public ControllerBase()
{
throw new NotImplementedException();
}
public ControllerBase(object alwaysSupply)
{
AlwaysSupply = alwaysSupply;
}
}
This will cause T4MVC to generate compilable code. The fault seems to be it always tries to generate a blank (no parameters) constructor for controller classes.
Hope this helps someone.
I see the problem, and it comes down to T4MVC not quite doing the right thing when dealing with generic classes. Normally it would generate a default ctor for it in a partial class, but the fact that it's generic is throwing it off.
You should be able to work around simply by adding a default ctor yourself, e.g.
public abstract partial class EntityController<T> : Controller where T : class, IEntity {
public EntityController() { }
// etc...
}
I've noticed something very odd:
I've added the empty constructor to the base class, but without the throw new NotImplementedException(); and it works fine.
But here's the odd thing, when calling the controller if I have an url like
/{controller}?params (default action being set to Index in the RouteConfig) the parameterless private controller on the base class is called.
But when I have an url like /{controller}/{action}?params then the constructor with parameters is called.

Run code before class instanciation in ActionScript 3

I need to run code in a class declaration before its instanciation. This would be especially useful to automatically register classes in a factory. See:
// Main.as
public class Main extends Sprite
{
public function Main() : void
{
var o : Object = Factory.make(42);
}
}
// Factory.as
public class Factory
{
private static var _factory : Array = new Array();
public static function registerClass(id : uint, c : Class) : void
{
_factory[id] = function () : Object { return new c(); };
}
public static function make(id : uint) : Object
{
return _factory[id]();
}
}
// Foo.as
public class Foo
{
// Run this code before instanciating Foo!
Factory.registerClass(CLASS_ID, Foo);
public static const CLASS_ID : uint = 42;
}
AFAIK, the JIT machine for the ActionScript language won't let me do that since no reference to Foo is made in the Main method. The Foo class being generated, I can't (and don't want to) register the classes in Main: I'd like to register all the exported classes in a specific package (or library). Ideally, this would be done through package introspection, which doesn't exist in ActionScript 3.
Do you know any fix (or other solution) to my design issue?
I'm not 100% sure sure if this is what you're after, but have you tried using a Static Initializer?
public class Foo
{
// Static Initializer
{
Factory.registerClass(CLASS_ID, Foo);
}
public static const CLASS_ID : uint = 42;
}
http://life.neophi.com/danielr/2006/12/static_initializers_in_as3.html
You can use compiler options to include class byte code in the resulting SWF or SWC. But you have to compile with MXMLC (or COMPC for SWCs).