Do events interrupt interfaces?
Note: in this question I am talking about formal interfaces (for example, the public interface IButton {...}).
I'm an ActionScript developer, but I suspect my question will resonate in many languages that allow for both formal interfaces and events.
I love interfaces. I like the separation between interface and implementation. (I want ActionScript to force each class to implement a formal interface like Objective-C does). All my classes implement an interface (or several) and you will never find that I am writing a public method than the Interface is mentioned.
But ActionScript is also highly event dependent. My problem is this: every part of a class that interacts with external classes or processes is (or should be) part of its interface. (I understand that this is a matter of opinion. If you disagree, this question will probably be meaningless to you.)
There are several ways to eliminate this clear image, but most of them can be avoided:
-
You cannot publish public properties on the frontend. Decision. Don't use public properties in your classes. Use getters and setters instead (and I'm not that crazy with them either, but I use them when I should).
-
If classes are exchanged passing arguments to constructors, these messages bypass the interfaces, since you cannot enumerate a constructor function in an interface. I avoid this problem (almost) by never passing parameters through constructors. I prefer init () methods that can be made explicit in interfaces.
-
Classes can have public methods that are not specified in the interface. I avoid it by not doing it. My classes are implementing interfaces. These interfaces contain headers for ALL public methods.
-
Many classes dispatch events.
This is the last killer.
Let's say I give you a class called Blah and you ask how to use it. I can tell you, "It implements the IBlah interface. Look at this and you will see everything you can do with Blah."
In addition, Blah extends EventDispatcher, which implies that it dispatches events.
"What events is he sending?" You're asking.
"Uh ..."
To know, you need to check JavaDoc or read Blah source code. You shouldn't do that either! You should be able to know how to interact with a class by checking its Interface (s).
I would like the interfaces to look like this:
public interface IBlah
{
function foo() : void;
function bar() : Boolean;
event BlahEvent;
}
But you cannot specify events in the interface.
Is it correct that events interrupt interfaces? For me, it’s like I gave you a car and said the manual here. In the manual, it supposedly explains everything on the dashboard. But then, when you drive a car, strange docks appear and strange sounds are made - events that are not mentioned in the manual.
If I am wrong please explain.
If I'm correct, is there a good way to avoid the problem?
What I think is missing is that events are completely optional. There is no rule dictating when you instantiate a class that should handle all the events it raises. You can (if your implementation requires it), just completely ignore any events caused by raising the object. Also, just the definition and event say nothing about when or if it will actually be raised. Therefore, placing an event on an interface would be useless, because there would be no way to determine when or when the event was raised, when the interface was implemented in the object.
source to share
My comment aside, I think you can declare the function headers in the interface IBlah
for example dispatchMouseDownEvent
(which of course takes the required parameters) and implement them in Blah
to dispatch the mouse event. Now, instead of dispatching a mouse event from a method, call dispatchMouseDownEvent
from that method. Just make sure you are not sending the mouse down event from anywhere in the class.
source to share
EventDispatcher implements IEventDispatcher, and interfaces can extend other interfaces. Therefore, you can simply do this:
public interface IButton extends IEventDispatcher
{
}
IEventDispatcher methods are now available on IButton
Edit: Also, as far as point # 2 is concerned, the class would not have to use the constructor if it was given a factory interface.
Edit: As for point # 1, the fields (without get / set) are data. Interfaces describe behavior without describing an implementation. The presence of a field on an interface flies in front of it, requiring you to implement it as a field.
source to share
Here's one way to do it:
package
{
public interface IMortal
{
function stabMe() : void;
function dispatchDeathEvent() : void
}
}
package
{
import flash.events.EventDispatcher;
import flash.events.Event;
public class Person extends EventDispatcher implements IMortal
{
private var _dispatchesAllowed : Boolean = false;
private var _lifeForce : Number = 10;
public function stabMe() : void
{
if ( --_lifeForce == 0 ) iAmDead();
}
private function iAmDead() : void
{
_dispatchesAllowed = true;
dispatchDeathEvent();
}
public function dispatchDeathEvent() : void
{
if ( _dispatchesAllowed )
dispatchEvent( new Event( Event.COMPLETE ) );
_dispatchesAllowed = false;
}
}
}
I like this because (a) it lists the event in the interface and (b) blocking the event from the outside (_dispatchesAllowed) is optional. This is an implementation detail.
I don't like this because it is a hack. It's weird that a public method can be called but is useless unless it also called an instance of its host class.
source to share