分享
 
 
 

Flash中oop的设计模式

王朝other·作者佚名  2006-11-24
窄屏简体版  字體: |||超大  

有人问我flash的as应该怎么写,我可以很负责任地告诉他,想怎么写就怎么写,因为as以及flash内部的构成模式决定了它的高度自由化。理论上来说,用按钮的on事件,加上stop(),play(),gotoAndStop(),gotoAndPlay(),就可以实现一个flash里大部分的逻辑关系,而且源代码简单易懂。但是大多数人不会这么做,是因为这种方法实在太让人敬佩。稍有常识的程序员都会知道面对对象与面对过程的区别。Flash的编程虽然只是以脚本的形式出现,并且还很不完善,比如,没有多继承,但已经初步体现了oop的思想。这篇文章现在总结一下flash中面对对象的设计模式问题,以及一些自创的思路。

设计模式是美国一位建筑大师(同时也是信息工程师,画家,机械工程师…的)克里斯蒂安.亚历山大首先提出来的,很快被软件界的技术员们所接受推广,成为软件工程里至高无上的法则之一(有兴趣的人可以找他的《建筑的永恒之道》一书看看,相信会受益非浅)。简单地说就是在面对对象的基础上,包括面对对象,把要设计的整体的各个部分模式化,层次化,细粒度化,高度复用化,可控化,人性化。其中至高无上的原则是建立在需求的基础之上,也就是说,无论做什么,人的需求要放在第一位考虑,从这个角度考虑整个系统是否足够合理。这门学问是非常有趣的,尤其在flash中,可以应用到很多很好玩的实例中去。下面我按照一些通用的设计模式,举例说明,有错误的地方,敬请高手指正:

1.抽象工厂模式(Abstract Factory)

食堂里吃的东西很多,而我只想吃一样,那么食堂这个概念对我来说就是个抽象工厂,每个窗口可以看成它的一个具体实现,我要做的就是,去食堂,找到那个窗口,从窗口里买我要吃的东西。

举例:flash前台与asp后台的交互,访问某个动态页面,从数据库里取出需要的数据,通常的做法是在后台就把数据集解析成xml字符串,再送给swf。每个业务逻辑模块,所取出的数据结构,也就是xml的结构是不一样的,我们要针对各个具体的业务逻辑,对相应的xml字符串解析,转换成可供显示的数组。也要把flash里文本输入的内容转换成 xml字符串,提交给后台也面

AbstractFactory.as

//抽象工厂的接口

Interface AbstractFactory{

//生成xml解析工厂的具体实现

function createXmlParseFactory();

}

XMLParserGetFactory.as

//生成解析读入的xml的对象的工厂

class XMLParserGetFactory implements AbstractFactory.{

var xmlParser;

function XMLParserGetFactory(str:String){

//生成解析器的具体实现,在后面会提到

}

function createXmlParser(){

return xmlParser;

}

}

XMLParserPostFactory.as

//生成解析输出的xml的对象的工厂

class XMLParserPostFactory implements AbstractFactory.{

var xmlParser;

function XMLParserPostFactory(str:String){

//生成解析器的具体实现

}

function createXmlParser(){

return xmlParser;

}

}

这样,我们读入某个xml字符串时,在onLoad里面加入

//生成对留言板的留言列表解析的工厂

var xmlParser=new XMLParserGetFactory(“xmlParseGuestbookList”)

xmlParser= XMLParserGetFactory. createXmlParser()

备注:抽象工厂模式是软件工程里最常用的设计模式之一,实现过程在于,需要某个类的实例时,通过某个工厂创建,而不是直接创建,坦白地说,它加大了开发工作量,但是对程序的层次性变得分明和降低耦合度有极大帮助。

2.生成器模式(builder)

还是那个说法,我要吃东西就去相应的食堂窗口,但我不能吃食堂窗口,窗口里的东西也许不少,我要跟师傅说,要这个,这个,还有这个。

举例:我已经建立了 xml解析器的工厂,现在要返回解析器本身,就让工厂创建,返回给我。

XMLParserGetFactory.as

//生成解析读入的xml的对象的工厂

class XMLParserGetFactory implements AbstractFactory.{

var xmlParser;

function XMLParserGetFactory(str:String){

//如果要求留言板列表解析器,就生成一个

if(str==” xmlParseGuestbookList”){

xmlParser=new xmlParserGuestbookList();

}

}

function createXmlParser(){

//返回所要求的解析器

return xmlParser;

}

}

AbstractXmlParser.as

//抽象xml解析器

Interface AbstractXmlParser{

function ParseXml();

}

xmlParserGuestBookList.as

//留言板列表解析器

Class xmlParserGuestBookList implements AbstractXmlParser{

//把xml字符串里的内容解析到一堆数组里

function ParseXml(xml:XML,arrayID:Array,arrayTitle:Array){

//具体循环操作

}

}

使用的时候:

var xmlParser=new XMLParserGetFactory(“xmlParseGuestbookList”)

xmlParser= XMLParserGetFactory. createXmlParser(xml,arrayID,arrayTitle);

3.工厂方法模式(Factory Method)

我到了食堂窗口,如果师傅跟那儿抽烟,我还是吃不着东西。我说:师傅,打饭!师傅才会完成打饭这一动作。这是工厂方法模式,抽象工厂的实现通常用工厂方法模式来完成。

举例:还是上一条,我本来想用一句话带一个参数就实现具体xml解析器的实现,无奈构造函数没有返回值,所以必须用

xmlParser= XMLParserGetFactory. createXmlParser(xml,arrayID,arrayTitle);

实现。

备注:抽象工厂模式,生成器模式和工厂方法模式需要灵活应用。

4.单件模式(singleton)

我前面一个人买了一条巨大的鸡腿,我说我也要一条,师傅说,就这一条

举例:单件模式的应用是相当广泛的,它确保每个实例在全局范围内只被创建一次,我们flash里的mc大多数是单件。内核里的核心组件也只是单件,比如我的消息映射列表(见后)。

按照单件模式的严格定义,应该让类负责保存它的唯一实例。但是我在Flash里还想不到怎么实现这一点,或者实现它的意义所在,但另外一点我们可以做到,就是在全局范围内只提供该对象的唯一访问点。这可以由层次关系做到,把对该对象的访问具体实现全部封装在下层,只给上层提供唯一的访问点(原因是,上层不知道这个单件的具体信息,比如路径)。

看我内核文件的一部分:

Core.as

//内核

class Core {

var strucGlobalParam:ConfigVariables;

//站点信息

var xmlConfig:XML;

//站点信息的xml化对象

var ArrayStructureInitial:Array;

//用来提供给loadObject对象的数组

var ArrayForBtn:Array;

//用来初始化导航条组件的数组

var objInitial:loadObject;

//读取影片的对象

var objMessageMap:MessageMap;

//消息映射组件

……

}

这是我的内核类也就是全站最核心类的数据结构。里面的数据只有通过下层的BasicMovie,OriginalFunctionObject等类(见后)直接访问。

备注,核心思想是,确保只有一个。

5.原型模式(protoType)

到小炒窗口,看前面的哥们炒的青椒炒肉不错的样子。“师傅,我也要这样的。”

举例:这对flash的用户来说再熟悉不过了,我们经常用duplicateMovieClip()和

attachMovie()这两个函数。按照一个原型复制相应的实例,各自执行自己的动作。在我的blog列表,导航条的生成。。几乎用得到多项数据的地方就要用原型模式。

6.责任链模式

7.中介者模式

8.观察者模式

食堂里厨房最远的窗口没熬白菜了,要告诉厨房,快送过来。

责任链模式:一个窗口一个窗口地传话,一直传到食堂,食堂一看不妙,赶快做好送过去。

中介者模式:专门派一个人负责传话,任何窗口没菜了,就要这个人赶快去厨房催。

观察者模式:厨房那边派一个盯着,看哪个窗口没菜了就开始大声嚷嚷。

举例:之所以要把这三个设计模式放在一块儿,是因为我在我的站里面结合这三者建立了一个好玩的东西,可以说是我的网站的核心所在。它解决了我的flash里面各个mc的通信问题。

比如,影片A放完了,要通知影片B开始播放,直接的做法是在A的最后一帧,写从A到B的相对路径或B的绝对路径,让B play()。这样做A和B的耦合性是相当高的,也就是说,相互依赖程度太高。运用设计模式的解决方案如下:

MessageMap.as

//消息映射类

class MessageMap extends Object {

var Message:String;

var MessageWatcher:Function;

var Target;

var MessageList:Array;

var Num_Msg:Number;

function MessageMap() {

Num_Msg = 0;

MessageList = new Array();

Message = "HANG_UP";

MessageWatcher = function (prop, oldVar, newVar, Param) {

for (var i = 0; i<Num_Msg+1; i++) {

if (newVar == MessageList[i][0]) {

MessageList[i][1].apply(MessageList[i][3], MessageList[i][2]);

if (!MessageList[i][4]) {

MessageList.splice(i, 1);

Num_Msg--;

i-=1;

}

}

}

};

this.watch("Message", MessageWatcher, "test");

}

function SendMessage(Msg:String, mc:MovieClip) {

Message = Msg;

}

function UpdateMessageMap(Msg:String, objFunction:Function, ArrayParam:Array, objRefer,IsMultiUsed:Boolean) {

MessageList[Num_Msg] = new Array();

MessageList[Num_Msg][0] = new String();

MessageList[Num_Msg][0] = Msg;

MessageList[Num_Msg][1] = new Function();

MessageList[Num_Msg][1] = objFunction;

MessageList[Num_Msg][2] = new Array();

MessageList[Num_Msg][2] = ArrayParam;

MessageList[Num_Msg][3] = objRefer;

MessageList[Num_Msg][4] = IsMultiUsed;

Num_Msg++;

}

function DeleteMessageMap(objRefer) {

for (var i = 0; i<Num_Msg; i++) {

if (MessageList[i][2] == objRefer) {

MessageList.splice(i, 1);

Num_Msg--;

}

}

}

}

class SubTemplateMovie extends BaseMovie {

var MovieRemoveFunction:Function;

function SubTemplateMovie() {

this.stop();

MovieStartFunction = function () {

Lock();

this.play();

};

MovieEndFunction = function () {

Lock();

this.play();

};

MovieRemoveFunction = function () {

this.stop();

SendMsg("SUB_TEMPLATE_REMOVED", this);

_parent.unloadMovie();

};

MovieMainFunction = function () {

stop();

SendMsg("SUB_TEMPLATE_OPEN", this);

};

UpdateMessage("LOADING_BAR_OVER", MovieStartFunction, null, this, false);

UpdateMessage("BACK_TO_INDEX", MovieEndFunction, null, this, false);

}

}

大概机制就是,影片提前提交一个数据结构,声明,如果有影片提交这条消息,就执行这条函数。原理在于,发送消息,实际上是把消息映射的一个变量赋值,由于消息映射继承自object类,可以用watch方法对该变量进行监视,一旦改变,在已经提交上来的消息映射列表里检查,如果有,执行对应函数。实际上这也造成了一定程度的耦合性,但是我们已经成功地把耦合性控制在了下级类,上级子类完全不用理会这一套消息机制的实现过程。

这个机制可以让我们对oop的真正目的有更深的看法。举例说明,影片A播放完了,就声明自己播放完了,至于我播完了你要干什么,不是我的事,我不控制你。所谓的降低耦合度是个相对概念,别忘了在计算机最底层,耦合度还是一样,cpu总是不断的直接或间接寻址,但我们需要做的是,改变系统的拓扑结构,把耦合度控制在某一个范围之内。

整个消息映射类相当于一个中介者,内部生成一个观察器,一旦触发消息,以责任链的方式执行。

9.桥接模式(Bridge)

菜太淡,不合有些人的胃口,所以要求食堂的师傅,专门开一个窗口,专门在做好的菜里多加些辣椒。

我在自己的站里运用了桥接模式:所有的影片都继承自我定义的BasicMovie 类(BasicMovie继承自MovieClip类),但是在四个下级栏目的影片里,需要定义相同的方法和事件来响应消息,BasicMovie没有这些函数,不符合要求,这时候,在四个影片里都写一遍是愚蠢的,我又写了一个SubTemplateMovie类继承自BaseMovie,里面加进一些通用的方法,然后四个下级模板影片都继承它,这样大大简化了后期开发。

BasicMovie.as

//基类影片

/所有影片的原始类,一切影片的父类都继承此类而来

class BaseMovie extends MovieClip {

var isLocked:Boolean;

//初始类开始影片函数

var MovieStartFunction:Function;

//初始类影片主功能函数

var MovieMainFunction:Function;

//初始类结束影片函数

var MovieEndFunction:Function;

var GlobalParam

//初始类构造函数

function BaseMovie() {

}

//

//发送消息

function SendMsg(Msg:String, Mc:MovieClip) {

_root.objCore.objMessageMap.SendMessage(Msg, Mc);

[1] [2] [3] 下一页

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有