OOP 问题:扩展类、覆盖函数和类似 jQuery 的语法
我有一个与 Flash、actionscript 3 相关的 OOP 问题。这是一个个人项目,我正在寻找解决此问题的设计模式或解决方法,我的目标是学习新东西。
我创建了一个名为 Chain 的类。我创建这个 util 类是为了使延迟函数调用变得容易。您可以通过以毫秒为单位的延迟添加函数来创建函数链。该链可以执行多次,甚至可以以相反的顺序执行。该类具有返回自身的函数。这使得有可能有一个像这样的 jQuery 风格的语法:
var chain:Chain = new Chain();
chain.wait(100).add(myFunction1,300).wait(300).add(myFunction2,100);
// etc..
对于这个例子,我留下了很多函数只是为了演示这个问题。 Chain 类主要用于添加功能和启动/停止链。
public class Chain
{
function wait(delay:int = 0):Chain
{
// do stuff
return this;
}
public function add(func:Function, delay:Number = 0):Chain
{
list.push( new ChainItem(func, delay) );
return this;
}
}
现在,我有另一个类,称为 ChainTween。我正在尝试将事情分开,以保留 Chain 的一些核心功能,并让 ChainTween 做一些动画技巧。我的想法是创建一个基于 Chain 类的小型补间引擎。目前它扩展了Chain。它使用了 Chain 类中的大量受保护变量,并覆盖了 Chain 的一些核心函数,以在 Chain 的进程中添加补间函数。
public class ChainTween extends Chain
{
function animate(properties:Object = null, duration:Number = 0, easing:Function = null):ChainTween
{
// do stuff
return this;
}
}
现在问题是:我想保留链接语法,但 wait() 返回一个 Chain 实例,而 Chain 没有动画函数。
var chain:ChainTween = new ChainTween();
chain.wait(100).animate({x:200}, 100).wait(250);
我尝试重写 ChainTween 类中的 wait() 和 add() 函数,但这会导致不兼容的重写。
我可以将 chain.wait(100) 转换为 ChainTween,但这非常丑陋,而且当我链接很多它们时没有用。现在我不想将任何 ChainTween 函数添加到 Chain(也没有虚拟函数),并且我想保持所有函数的完成,因此返回 Object 也不是一个选项。我尝试使用接口,但这给出了同样的问题,因为接口的功能应该在实现它的类中实现。
现在我考虑过在 ChainTween 中创建一个 Chain 实例,但这不允许我重写函数,然后我应该将很多属性设为公共而不是受保护,这也不是首选。
这可能吗?有人对此有很好的解决方案吗?
I have an OOP related problem with Flash, actionscript 3. It's a personal project, and I am looking for a design pattern or workaround for this problem, and my goal is to learn new things.
I have created a class called Chain. I created this util-class to make delayed function calling easy. You can make a chain of functions, by adding them with a delay in milliseconds. This chain can be executed multiple times, even in reversed order. This class has functions which returns itself. That makes it possible to have a jQuery styled syntax like this:
var chain:Chain = new Chain();
chain.wait(100).add(myFunction1,300).wait(300).add(myFunction2,100);
// etc..
For the example I have left lots of functions just to demonstrate the problem. The Chain class is mostly pure for adding functions and start/stopping the chain.
public class Chain
{
function wait(delay:int = 0):Chain
{
// do stuff
return this;
}
public function add(func:Function, delay:Number = 0):Chain
{
list.push( new ChainItem(func, delay) );
return this;
}
}
Now, I have a another class called ChainTween. I am trying to split things up to keep the Chain with some core functions and have ChainTween do some animating tricks. I had the idea to create a little tweenengine based on the Chain class. Currently it extends Chain. It uses lots of protected variables from the Chain class and overrides also some core functions for Chain to add the tween functions inside the process of Chain.
public class ChainTween extends Chain
{
function animate(properties:Object = null, duration:Number = 0, easing:Function = null):ChainTween
{
// do stuff
return this;
}
}
Now this is the problem: I want to keep the chaining syntax, but wait() returns a Chain instance and Chain has no animate function.
var chain:ChainTween = new ChainTween();
chain.wait(100).animate({x:200}, 100).wait(250);
I have tried to override the wait() and add() function in the ChainTween class but this causes an incompatible override.
I could cast chain.wait(100) as ChainTween, but this is very ugly and not useful when I am chaining lots of them. Now I don't want to add any of the ChainTween functions to Chain (no dummy functions too), and I want to keep completion to all functions, so returning Object is not an option too. I tried to use an interface, but this gives the same problem, since the functions of an interface should be implemented in the class that implements it.
Now I have thought about creating an instance of Chain inside ChainTween, but this does not allow me to override functions, and then I should make lots of properties public instead of protected, which is not preferred too.
Is this possible and does anyone has a great solution for this?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
如果您希望通过代码补全列出函数,则该函数必须在那里。这排除了任何运行时发现方法。我会向 Chain 添加这样的内容:
在 ChainTween 中被覆盖。不要认为这是一个很大的延伸。
If you want function to be listed by code completion, it must be there. This rules out any runtime discovery methods. I would add to Chain something like this:
to be overridden in ChainTween. Don't think it's such a big stretch.
按照 Chain 类的结构,应该可以(并且在某种程度上合乎逻辑)使用 add 方法来调用 animate 方法...由于不了解 Chain 类的更多信息,很难更准确,但理论上它会似乎有可能...这需要向 add 方法添加一个新参数。
alxx 有一点,似乎有些东西必须以某种方式给出,与 Javascript 不同,AS3 是一种强类型语言,这就是你的限制的原因。如果您需要实现像旋转、淡出这样具体的方法,您可能没有很多可用的解决方案。这些方法将返回 ChainTween、Chain 或 Object,并且您将同时忽略 Object 和 * ...
不知何故,我仍然认为使用 add() (或您的任何其他方法)添加旋转、fadeOut 或 animate 方法可能会为此目的而创建)更符合Chain的设计。
Following the structure of the Chain class, it should be possible ( and somehow logical ) to use the add method to call the animate method... Not knowing more about the Chain class , it's difficult to be more accurate , but in theory it would seem possible... It would require adding a new argument to the add method.
alxx has a point, it would seem that something has to give somehow, unlike Javascript, AS3 is a strongly typed language , this is the very cause of your limitations. If you need to implement methods as specific as rotate, fadeOut , you may not have a whole lot of solutions available. Those methods will either return a ChainTween, a Chain or an Object, and you're dismissing both Object and * ...
Somehow, I still think that adding the rotate , fadeOut or animate method with add() ( or any other method you may create for that purpose ) is more in line with Chain's design.
您可以尝试返回 * 而不是 Chain,但这会删除代码提示。
You could try returning * instead of Chain but this removes code hinting.
如果我是你,我会创建一个仅描述核心功能的
IChain
接口(add
、wait
等)if i were you i'd created an
IChain
interface describing only core functions (add
,wait
etc)我会选择已经建议的界面想法。 Wait 将返回类似“IChainTween”的内容,其中仅包含配置 ChainTween 的方法,以及类似“then”的函数,该函数返回原始 Chain。
I would go for the already suggested interface idea. Wait would return something like 'IChainTween' which only contains methods to configure a ChainTween and also a function like 'then' which returns the original Chain.
这个问题很常见。您使用的设计模式称为Fluent Interface,如果您 Google“Fluent Interface Inheritance”,你会发现很多问题,但答案却很少。
在 C#、Java 和 C++ 中解决此问题的常见方法是使用模板 。但是,我不知道如何在 AS3 中实现相同的功能,我发现这个主题可能对你有帮助。
This problem is quite common. The design pattern you are using is called Fluent Interface and if you Google "Fluent Interface Inheritance", you'll find lots of questions and very few answers.
A common way to solve it in C#, Java and C++ is to use templates. However, I cannot tell how to implement the same in AS3, I found this topic that might help you.