我在这里有一个非常简单的场景并且它有效,但我的直觉告诉我,我犯了一个错误,并希望通过一些更好的思想来运行它。
这里我有一个父类,它实例化一个MenuClass并处理页面之间的转换。
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
}
这里是创建前进和后退按钮的MenuClass。单击每个将分别告诉上面的ParentClass 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与其父级绑定得太紧,因此不太可重复使用。另一方面,我觉得,为了保持一切自包含,ParentClass不负责进入MenuClass实例并在那里添加事件监听器。这似乎应该有某种OOP经验法则来管理这种关系。
所以我的问题是:我的MenuClass是否与其父级太紧密了?如果是这样,你有什么建议可以放松这种耦合吗?
感谢。
答案 0 :(得分:5)
如果您有任何机会想要提供多种导航方式(除了菜单之外),那么使用事件驱动方法是有道理的。它可以让你几乎完全将Parent与菜单分离。
这是我在Flash中实际测试过的一些代码。 ;)
父对象创建菜单对象并从中侦听FORWARD和BACKWARD事件:
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");
}
}
}
然后,当点击某些内容时,MenuClass会调度这些事件:
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方法,例如键盘快捷键或上下文菜单等,只需调度相同的FORWARD和BACKWARD事件,并让Parent也听取它们。您也可以创建一个新的Event子类,并在需要时将FORWARD和BACKWARD常量放在那里。
答案 1 :(得分:1)
另一方面,我觉得,为了保持一切自包含,ParentClass不负责进入MenuClass实例并在那里添加事件监听器。
为什么不呢?如果ParentClass需要监听MenuClass上的事件,那么它应该自己添加这些事件监听器。通过直接调用addEventListener,或者调用MenuClass上的另一个方法来设置具有正确函数的事件处理程序来调用。
答案 2 :(得分:0)
恕我直言,如果您的应用程序是小型/中型应用程序,您可以这样做,对于更大的项目,您正确地将父类和子类分离。 有几种基于品味的方法,一种是创建使用“FlowControl”类。
public class FlowControl
{
private var _parentSprite : ParentClass;
private var _instance : FlowControl;
public static FlowControl GetInstance(ParentSprite : ParentClass)
{
if (_instance == null)
_instance = new FlowControl(ParentSprite);
return _instance;
}
private FlowControl(ParentSprite : ParentClass)
{
_parentSprite = ParentSprite;
}
public static void NextPage()
{
ParentSprite.transitionForward();
}
}
我没有闪光灯来测试它,但你明白了。
更好的解决方案是实现一个接口,因此您可以在接口而不是类上获得紧密耦合。
答案 3 :(得分:0)
这不是“坏”的形式,但根据具体情况,可能还有其他方式来接近它。
特别是如果您有多个孩子只有一个父母。
我是静态方法和管理器类的忠实粉丝,但是有一大群人同样反对这种情况或者更糟糕,而不是与孩子 - >父方法调用相反。
值得注意的是,“parent”是一个取决于addChild()和显示列表的属性。
我可能错了,但我的理解是,如果您在代码中创建一个对象,并且它的生命周期中从未添加到显示列表中,那么parent将为null。所以这就提出了问题。
另一个怪癖是,如果你将一个子项添加到显示列表,然后删除它,父项仍然设置为它被添加到的最后一个对象,所以它可能能够对技术上的对象采取行动不再是孩子了。
这就是为什么我通常将这个逻辑说成如下
if(Type(this.parent).contains(this))
{
//do stuff
}
只有当对象出现在显示列表中时,包含才会返回true。
这种类型的逻辑可能相关的一些情况是,如果您在某些对象可能可见而其他对象不可见的对象数组上循环。在最坏的情况下,它会节省一些CPU周期。