How do you work on the need to bind a related object to a base class?
This question is intended to apply to interfaces in general, but I will be using AS3 / Flex for my language. It should be [mostly] obvious how to apply it in different languages.
If I create a base class and extend the interface, there is an explicit contract: for each method in the interface, the base class must implement the specified method.
It's simple enough. But I don't understand why you have the option to translate the linked instance back to the original base class. Of course, I've had to do this several times (the example below is very close to the situation I'm struggling with), but that doesn't mean I understand it: ^)
Here's an example of the interface:
public interface IFooable extends IUIComponent {
function runFoo():void;
}
Let's say I create a base class that extends VBox and implements an interface:
public class Foo extends VBox implements IFooable {
public Foo() {
super();
//stuff here to create Foo..blah blah
}
public function runFoo():void {
// do something to run foo
}
}
Now the reason I used the interface is because I want to ensure that "runFoo" is always implemented. This is common functionality that all my classes should do, no matter how they implement it. This way my parent class (application) will create Foo through its interface:
public function init():void {
var foo:IFooable = new Foo();
foo.percentHeight = 100; //works because of IUIComponent
}
But if I want to add Foo to the application container, now I have to return it to the base class (or another base class):
public function init():void {
var foo:IFooable = new Foo();
foo.percentHeight = 100;
addChild(foo as DisplayObject); //_have_ to cast, because addChild takes a 'DisplayObject' class type
//could also do this:
//addChild(foo as VBox);
}
Was the intention to hide the implementation of Foo? There is still the assumption that Foo is a DisplayObject. Unfortunately, the ability to add a custom object to a container seems impossible without casting.
Am I missing something? Is this really just a phenomenon in Flex / AS3? If you have a container in the core API of the language, and it allows you to add child objects of a specific class type, how do you abstractly do the implementation?
For the record, this question seems to be asking if such an operation is possible, but it doesn't really mean why it might be bad design (and how to fix it).
Second thought:
Abstract classes :
As Matthew pointed out, abstract classes help solve some of these problems: I could create a base abstract class that inherits from DisplayObject (or, in my case, VBox, since it is a child of DisplayObject) and has a base class that implements the interface ... Thus, then any class that extends an abstract class will have to inject methods into it.
Great idea - but AS3 doesn't have abstract classes (to my knowledge, anyway).
So, I could create a base class that implements the interface and extends the VBox and inherits from it, and I could insert the code into those methods that need to be extended; such code would throw an error if the base class is an executor. Unfortunately, this is a runtime check as opposed to a forced compilation.
This is still a solution.
Context
Some context might help:
I have an application that can have any number of subcontainers. Each of these subcontainers will have their own configuration options, options, etc. However, the application itself has a global ApplicationControlBar that will contain the starting point menu to access these configuration options. So when I add a subcomponent to the main application (via "addChild") it will also "register" its own configuration settings in the ApplicationControlBar menu. This preserves configuration knowledge with the containers themselves, but allows for more uniform access to them.
This way, when I create each container, I want to create them through their interface so that I can ensure that they can register with the ApplicationControlBar. But when I add them to my application, they should be the base class.
a source to share
Okay, I disagree at all because you said "Is this really just a phenomenon in Flex / AS3?"
In your init method, you obviously always call addChild with foo. This means that foo must always be a DisplayObject instance. You also want it to be an IFooable instance (although not clear here). Since DisplayObject is a class, you must use a DisplayObject subclass (such as FooableDisplayObject) that implements IFooable. In Java it will be below. I am not familiar with AS, but I think this does not show any general flaws in interfaces.
interface IFooable
{
public void runFoo();
}
class DisplayObject
{
}
abstract class FooableDisplayObject extends DisplayObject implements IFooable
{
}
class Foo extends FooableDisplayObject
{
public void runFoo()
{
}
}
public void init()
{
FooableDisplayObject foo = new Foo();
foo.percentHeight = 100;
addChild(foo);
}
a source to share
@James Ward, This is definitely what I want, it was in language, perhaps the IDisplayObject interface. This would solve many of the problems in programming OOP mapping in AS3.
Regarding the original question, which I have used in the past and have seen on www.as3dp.com, the getDisplay (): DisplayObject method must be included in the interface, which is usually returned "this" by its developer. It's less perfect, but it works.
@Matthew Flaschen. While we don't have the AS3-native Abstarct classes, it's common practice to call the class Abstract ie: AbstarctMyObject and then just treat it as abstarct objects in Java and other languages. Our desire for true abstarct classes is something that the Flash player team is well aware of, and we'll see that in the next version of the ActionScript language.
a source to share
I think this is where the Flex / Flash API is wrong. I think I addChild
should be using an interface not for a class. However, since this is not the case, you must give it up. Another option would be a monkey patch UIComponent
, so it would require an interface, or might add another method, for example addIChild(IUIComponent)
. But it's messy. Therefore, I recommend that you write down the error .
a source to share
The situation here is that, for best practice, it should just be the other way around ... you shouldn't cast your interface into a displayobject, but to have your instance already a displayable, and then apply it to your interface to apply specific methods.
Let's say I have a base page and other subclasses of Home page, contact page, and so on. Now you don't apply material to the base class as abstract, but you create interfaces for your subclasses.
Suppose subpages implement, for example, an interface for working with init, addtostage, loader, etc., and another with logic, and eventually the base req will be managed as displayobjects.
To develop a project, you just need to use the custom stuff interface and extend the subclass from where it mostly belongs. The page now has a "base" value to be displayed (design wise. Base'-class is a displayobject), but may require some specialization for which an interface is created to cover this.
public class Page extends Sprite{...}
public interface IPageLoader{ function loadPage():void{}; function initPage():void{}; }
public class Homepage extends Page implements IPageLoader
{ function loadPage():void{/*do stuff*/}; function initPage():void{/*do stuff*/}; }
var currentpage:Page;
var currentpageLoader:IPageLoader;
currentpage = new Homepage;
currentpageLoader = currentpage as IPageLoader;
currentpageLoader.loadPage();
currentpageLoader.initPage();
addChild(currentpage);
Tween(currentpage, x, CENTER);
a source to share