AS3/Flash:子组件调用其父组件上的方法是一种糟糕的形式吗?
我这里有一个非常简单的场景,它是有效的,但是我的直觉告诉我我犯了一个错误,我想让一些更好的人来运行它 这里我有一个父类,它实例化一个菜单类并处理页面之间的转换AS3/Flash:子组件调用其父组件上的方法是一种糟糕的形式吗?,flash,actionscript-3,oop,Flash,Actionscript 3,Oop,我这里有一个非常简单的场景,它是有效的,但是我的直觉告诉我我犯了一个错误,我想让一些更好的人来运行它 这里我有一个父类,它实例化一个菜单类并处理页面之间的转换 public class ParentClass extends Sprite { public function ParentClass() { setupOptionMenu(); } private function setupOptionMenu() : void {
public class ParentClass extends Sprite
{
public function ParentClass()
{
setupOptionMenu();
}
private function setupOptionMenu() : void
{
var myMenu:MenuClass = new MenuClass;
myMenu.setUpButtons();
this.addChild( myMenu );
}
+ public function transitionForward() : void
+ public function transitionBackward() : void
}
这是创建前进和后退按钮的菜单类。单击每个将分别告诉上述父类transitionForward()或transitionBackward()
public class MenuClass extends Sprite
{
public function MenuClass()
{
setupButtons();
}
public function setUpButtons() : void
{
var backButton:Button = new Button();
backButton.addEventListener( MouseEvent.CLICK, backClick );
addChild( backButton );
var forwardButton:Button = new Button();
forwardButton.addEventListener( MouseEvent.CLICK, forwardClick );
addChild( forwardButton );
}
private function backClick( e:Event ) : void
{
ParentClass( this.parent ).transitionForward();
}
private function forwardClick( e:Event ) : void
{
ParentClass( this.parent ).transitionBackward();
}
}
一方面,我觉得MenuClass与其父类绑定得太紧密,因此不太容易重用。另一方面,我觉得为了保持所有内容都是自包含的,父类没有责任访问MenuClass实例并在那里添加事件侦听器。这似乎应该有某种面向对象的经验法则来管理这种关系
所以我的问题是:我的MenuClass是否与它的父类绑定得太紧了?如果是这样的话,你有什么建议可以放松这种耦合吗
谢谢
另一方面,我觉得为了保持所有内容都是自包含的,父类没有责任访问MenuClass实例并在那里添加事件侦听器
为什么不呢?如果父类需要侦听MenuClass上的事件,那么它应该添加这些事件侦听器本身。通过直接调用addEventListener,或者在设置事件处理程序的菜单类上调用另一个方法来调用正确的函数
另一方面,我觉得为了保持所有内容都是自包含的,父类没有责任访问MenuClass实例并在那里添加事件侦听器
为什么不呢?如果父类需要侦听MenuClass上的事件,那么它应该添加这些事件侦听器本身。通过直接调用addEventListener,或者调用MenuClass上的另一个方法来设置事件处理程序和要调用的正确函数。如果您的应用程序是小型/中型应用程序,您可以如何做到这一点,对于更大的项目,您正确地解耦了父类和子类。 有几种基于味道的方法,一种是创建一个“FlowControl”类 我没有flash来测试,但你知道了
更好的解决方案是实现一个接口,这样就可以在接口而不是类上实现紧密耦合。如果您的应用程序是中小型应用程序,那么如何做到这一点,对于更大的项目,您正确地解耦了父类和子类。 有几种基于味道的方法,一种是创建一个“FlowControl”类 我没有flash来测试,但你知道了 更好的解决方案是实现一个接口,这样就可以在接口而不是类上实现紧密耦合。这不是一种“坏”形式,但根据上下文的不同,可能有其他方法来实现它 特别是如果你有多个孩子和一个单亲 我非常喜欢静态方法和管理器类,但是有一大群人同样反对这种方法,甚至更反对child->parent方法调用 需要注意的是,“parent”是一个依赖于addChild()和显示列表的属性 我可能错了,但我的理解是,如果在代码中创建对象,并且在其生命周期中从未将其添加到显示列表中,则父对象将为null。因此,这就提出了一些问题 另一个怪癖是,如果将子对象添加到显示列表中,然后将其删除,父对象仍然设置为其添加到的最后一个对象,因此它可能能够对技术上不再是其子对象的对象采取操作 这就是为什么我通常将这种逻辑表述如下
if(Type(this.parent).contains(this))
{
//do stuff
}
如果对象当前在显示列表中,Contains将仅返回true
这种类型的逻辑可能相关的一些情况是,如果您在对象数组上循环,其中一些对象可能可见,而另一些对象不可见。最坏的情况下,它会为您节省一些CPU周期。这不是一种“坏”形式,但根据上下文的不同,可能会有其他方法
特别是如果你有多个孩子和一个单亲
我非常喜欢静态方法和管理器类,但是有一大群人同样反对这种方法,甚至更反对child->parent方法调用
需要注意的是,“parent”是一个依赖于addChild()和显示列表的属性
我可能错了,但我的理解是,如果在代码中创建对象,并且在其生命周期中从未将其添加到显示列表中,则父对象将为null。因此,这就提出了一些问题
另一个怪癖是,如果将子对象添加到显示列表中,然后将其删除,父对象仍然设置为其添加到的最后一个对象,因此它可能能够对技术上不再是其子对象的对象采取操作
这就是为什么我通常将这种逻辑表述如下
if(Type(this.parent).contains(this))
{
//do stuff
}
如果对象当前在显示列表中,Contains将仅返回true
这种类型的逻辑可能相关的一些情况是,如果您在对象数组上循环,其中一些对象可能可见,而另一些对象不可见。最坏的情况下,它会为您节省一些CPU周期。如果您希望提供多种导航方式(除了菜单),那么使用事件驱动方法是有意义的。它可以让您几乎完全从菜单中分离父菜单 下面是我在Flash中实际测试的一些代码 父对象创建菜单对象并从中侦听向前和向后事件:
package
{
import flash.display.Sprite;
import flash.events.Event;
public class ParentClass extends Sprite
{
public function ParentClass()
{
setupOptionMenu();
}
private function setupOptionMenu() : void
{
var myMenu:MenuClass = new MenuClass;
myMenu.setUpButtons();
this.addChild( myMenu );
myMenu.addEventListener(MenuClass.FORWARD, transitionForward);
myMenu.addEventListener(MenuClass.BACKWARD, transitionBackward);
}
public function transitionForward(e:Event) : void
{
trace("forward");
}
public function transitionBackward(e:Event) : void
{
trace("backward");
}
}
}
然后,菜单类在单击某些内容时发送这些事件:
package
{
import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.display.SimpleButton;
public class MenuClass extends Sprite
{
public static const FORWARD:String = "forward";
public static const BACKWARD:String = "backward";
public function MenuClass()
{
setUpButtons();
}
public function setUpButtons() : void
{
var rect:Sprite = new Sprite();
rect.graphics.beginFill(0x666666);
rect.graphics.drawRect(0,0,50,20);
var backButton:SimpleButton = new SimpleButton(rect, rect, rect, rect);
backButton.x = 10;
backButton.y = 10;
backButton.addEventListener( MouseEvent.CLICK, backClick );
addChild( backButton );
var forwardButton:SimpleButton = new SimpleButton(rect, rect, rect, rect);
forwardButton.x = 70;
forwardButton.y = 10;
forwardButton.addEventListener( MouseEvent.CLICK, forwardClick );
addChild( forwardButton );
}
private function backClick( e:MouseEvent ) : void
{
dispatchEvent(new Event(BACKWARD));
}
private function forwardClick( e:MouseEvent ) : void
{
dispatchEvent(new Event(FORWARD));
}
}
}
要提供备用UI方法,如键盘快捷键或上下文菜单等,只需发送相同的转发和BAC