Flash中oop的设计模式.docx
- 文档编号:6517038
- 上传时间:2023-01-07
- 格式:DOCX
- 页数:14
- 大小:26.91KB
Flash中oop的设计模式.docx
《Flash中oop的设计模式.docx》由会员分享,可在线阅读,更多相关《Flash中oop的设计模式.docx(14页珍藏版)》请在冰豆网上搜索。
Flash中oop的设计模式
Flash中oop的设计模式
有人问我flash的as应该怎么写,我可以很负责任地告诉他,想怎么写就怎么写,因为as以及flash内部的构成模式决定了它的高度自由化。
理论上来说,用按钮的on事件,加上stop(),play(),gotoAndStop(),gotoAndPlay(),就可以实现一个flash里大部分的逻辑关系,而且源代码简单易懂。
但是大多数人不会这么做,是因为这种方法实在太让人敬佩。
稍有常识的程序员都会知道面对对象与面对过程的区别。
Flash的编程虽然只是以脚本的形式出现,并且还很不完善,比如,没有多继承,但已经初步体现了oop的思想。
这篇文章现在总结一下flash中面对对象的设计模式问题,以及一些自创的思路。
设计模式是美国一位建筑大师(同时也是信息工程师,画家,机械工程师…的)克里斯蒂安.亚历山大首先提出来的,很快被软件界的技术员们所接受推广,成为软件工程里至高无上的法则之一(有兴趣的人可以找他的《建筑的永恒之道》一书看看,相信会受益非浅)。
简单地说就是在面对对象的基础上,包括面对对象,把要设计的整体的各个部分模式化,层次化,细粒度化,高度复用化,可控化,人性化。
其中至高无上的原则是建立在需求的基础之上,也就是说,无论做什么,人的需求要放在第一位考虑,从这个角度考虑整个系统是否足够合理。
这门学问是非常有趣的,尤其在flash中,可以应用到很多很好玩的实例中去。
下面我按照一些通用的设计模式,举例说明,有错误的地方,敬请高手指正:
1.抽象工厂模式(AbstractFactory)
食堂里吃的东西很多,而我只想吃一样,那么食堂这个概念对我来说就是个抽象工厂,每个窗口可以看成它的一个具体实现,我要做的就是,去食堂,找到那个窗口,从窗口里买我要吃的东西。
举例:
flash前台与asp后台的交互,访问某个动态页面,从数据库里取出需要的数据,通常的做法是在后台就把数据集解析成xml字符串,再送给swf。
每个业务逻辑模块,所取出的数据结构,也就是xml的结构是不一样的,我们要针对各个具体的业务逻辑,对相应的xml字符串解析,转换成可供显示的数组。
也要把flash里文本输入的内容转换成xml字符串,提交给后台也面
AbstractFactory.as
//抽象工厂的接口
InterfaceAbstractFactory{
//生成xml解析工厂的具体实现
functioncreateXmlParseFactory();
}
XMLParserGetFactory.as
//生成解析读入的xml的对象的工厂
classXMLParserGetFactoryimplementsAbstractFactory.{
varxmlParser;
functionXMLParserGetFactory(str:
String){
//生成解析器的具体实现,在后面会提到
}
functioncreateXmlParser(){
returnxmlParser;
}
}
XMLParserPostFactory.as
//生成解析输出的xml的对象的工厂
classXMLParserPostFactoryimplementsAbstractFactory.{
varxmlParser;
functionXMLParserPostFactory(str:
String){
//生成解析器的具体实现
}
functioncreateXmlParser(){
returnxmlParser;
}
}
这样,我们读入某个xml字符串时,在onLoad里面加入
//生成对留言板的留言列表解析的工厂
varxmlParser=newXMLParserGetFactory(“xmlParseGuestbookList”)
xmlParser=XMLParserGetFactory.createXmlParser()
备注:
抽象工厂模式是软件工程里最常用的设计模式之一,实现过程在于,需要某个类的实例时,通过某个工厂创建,而不是直接创建,坦白地说,它加大了开发工作量,但是对程序的层次性变得分明和降低耦合度有极大帮助。
2.生成器模式(builder)
还是那个说法,我要吃东西就去相应的食堂窗口,但我不能吃食堂窗口,窗口里的东西也许不少,我要跟师傅说,要这个,这个,还有这个。
举例:
我已经建立了xml解析器的工厂,现在要返回解析器本身,就让工厂创建,返回给我。
XMLParserGetFactory.as
//生成解析读入的xml的对象的工厂
classXMLParserGetFactoryimplementsAbstractFactory.{
varxmlParser;
functionXMLParserGetFactory(str:
String){
//如果要求留言板列表解析器,就生成一个
if(str==”xmlParseGuestbookList”){
xmlParser=newxmlParserGuestbookList();
}
}
functioncreateXmlParser(){
//返回所要求的解析器
returnxmlParser;
}
}
AbstractXmlParser.as
//抽象xml解析器
InterfaceAbstractXmlParser{
functionParseXml();
}
xmlParserGuestBookList.as
//留言板列表解析器
ClassxmlParserGuestBookListimplementsAbstractXmlParser{
//把xml字符串里的内容解析到一堆数组里
functionParseXml(xml:
XML,arrayID:
Array,arrayTitle:
Array){
//具体循环操作
}
}
使用的时候:
varxmlParser=newXMLParserGetFactory(“xmlParseGuestbookList”)
xmlParser=XMLParserGetFactory.createXmlParser(xml,arrayID,arrayTitle);
3.工厂方法模式(FactoryMethod)
我到了食堂窗口,如果师傅跟那儿抽烟,我还是吃不着东西。
我说:
师傅,打饭!
师傅才会完成打饭这一动作。
这是工厂方法模式,抽象工厂的实现通常用工厂方法模式来完成。
举例:
还是上一条,我本来想用一句话带一个参数就实现具体xml解析器的实现,无奈构造函数没有返回值,所以必须用
xmlParser=XMLParserGetFactory.createXmlParser(xml,arrayID,arrayTitle);
实现。
备注:
抽象工厂模式,生成器模式和工厂方法模式需要灵活应用。
4.单件模式(singleton)
我前面一个人买了一条巨大的鸡腿,我说我也要一条,师傅说,就这一条
举例:
单件模式的应用是相当广泛的,它确保每个实例在全局范围内只被创建一次,我们flash里的mc大多数是单件。
内核里的核心组件也只是单件,比如我的消息映射列表(见后)。
按照单件模式的严格定义,应该让类负责保存它的唯一实例。
但是我在Flash里还想不到怎么实现这一点,或者实现它的意义所在,但另外一点我们可以做到,就是在全局范围内只提供该对象的唯一访问点。
这可以由层次关系做到,把对该对象的访问具体实现全部封装在下层,只给上层提供唯一的访问点(原因是,上层不知道这个单件的具体信息,比如路径)。
看我内核文件的一部分:
Core.as
//内核
classCore{
varstrucGlobalParam:
ConfigVariables;
//站点信息
varxmlConfig:
XML;
//站点信息的xml化对象
varArrayStructureInitial:
Array;
//用来提供给loadObject对象的数组
varArrayForBtn:
Array;
//用来初始化导航条组件的数组
varobjInitial:
loadObject;
//读取影片的对象
varobjMessageMap:
MessageMap;
//消息映射组件
……
}
这是我的内核类也就是全站最核心类的数据结构。
里面的数据只有通过下层的BasicMovie,OriginalFunctionObject等类(见后)直接访问。
备注,核心思想是,确保只有一个。
5.原型模式(protoType)
到小炒窗口,看前面的哥们炒的青椒炒肉不错的样子。
“师傅,我也要这样的。
”
举例:
这对flash的用户来说再熟悉不过了,我们经常用duplicateMovieClip()和
attachMovie()这两个函数。
按照一个原型复制相应的实例,各自执行自己的动作。
在我的blog列表,导航条的生成。
。
几乎用得到多项数据的地方就要用原型模式。
6.责任链模式
7.中介者模式
8.观察者模式
食堂里厨房最远的窗口没熬白菜了,要告诉厨房,快送过来。
责任链模式:
一个窗口一个窗口地传话,一直传到食堂,食堂一看不妙,赶快做好送过去。
中介者模式:
专门派一个人负责传话,任何窗口没菜了,就要这个人赶快去厨房催。
观察者模式:
厨房那边派一个盯着,看哪个窗口没菜了就开始大声嚷嚷。
举例:
之所以要把这三个设计模式放在一块儿,是因为我在我的站里面结合这三者建立了一个好玩的东西,可以说是我的网站的核心所在。
它解决了我的flash里面各个mc的通信问题。
比如,影片A放完了,要通知影片B开始播放,直接的做法是在A的最后一帧,写从A到B的相对路径或B的绝对路径,让Bplay()。
这样做A和B的耦合性是相当高的,也就是说,相互依赖程度太高。
运用设计模式的解决方案如下:
MessageMap.as
//消息映射类
classMessageMapextendsObject{
varMessage:
String;
varMessageWatcher:
Function;
varTarget;
varMessageList:
Array;
varNum_Msg:
Number;
functionMessageMap(){
Num_Msg=0;
MessageList=newArray();
Message="HANG_UP";
MessageWatcher=function(prop,oldVar,newVar,Param){
for(vari=0;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"); } functionSendMessage(Msg: String,mc: MovieClip){ Message=Msg; } functionUpdateMessageMap(Msg: String,objFunction: Function,ArrayParam: Array,objRefer,IsMultiUsed: Boolean){ MessageList[Num_Msg]=newArray(); MessageList[Num_Msg][0]=newString(); MessageList[Num_Msg][0]=Msg; MessageList[Num_Msg][1]=newFunction(); MessageList[Num_Msg][1]=objFunction; MessageList[Num_Msg][2]=newArray(); MessageList[Num_Msg][2]=ArrayParam; MessageList[Num_Msg][3]=objRefer; MessageList[Num_Msg][4]=IsMultiUsed; Num_Msg++; } functionDeleteMessageMap(objRefer){ for(vari=0;i if(MessageList[i][2]==objRefer){ MessageList.splice(i,1); Num_Msg--; } } } } classSubTemplateMovieextendsBaseMovie{ varMovieRemoveFunction: Function; functionSubTemplateMovie(){ 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 //基类影片 /所有影片的原始类,一切影片的父类都继承此类而来 classBaseMovieextendsMovieClip{ varisLocked: Boolean; //初始类开始影片函数 varMovieStartFunction: Function; //初始类影片主功能函数 varMovieMainFunction: Function; //初始类结束影片函数 varMovieEndFunction: Function; varGlobalParam //初始类构造函数 functionBaseMovie(){ } // //发送消息 functionSendMsg(Msg: String,Mc: MovieClip){ _root.objCore.objMessageMap.SendMessage(Msg,Mc); } //添加消息映射 functionUpdateMessage(Msg: String,MsgMapFunction: Function,ArrayParam,obj,IsMultiUsed){ _root.objCore.objMessageMap.UpdateMessageMap(Msg,MsgMapFunction,ArrayParam,obj,IsMultiUsed); } //删除消息映射 functionDeleteMessage(obj){ _root.objCore.objMessageMap.DeleteMessageMap(obj); } functionGetGlobalParam(){ GlobalParam=_root.objCore.strucGlobalParam; } } SubTemplateMovie.as //下级模板影片类 classSubTemplateMovieextendsBaseMovie{ varMovieRemoveFunction: Function; functionSubTemplateMovie(){ 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); } } 注(关于消息映射机制看责任链模式) 10.适配器模式(Adapter) 我要一碗汤,但是只有纸饭盒,还没勺,所以食堂的师傅给了我一次性的汤碗和勺,这叫适配器。 适配器解决的是某一个类的对外接口不合用的问题,可能是参数或者返回值类型不符等问题造成的,这时候我们需要在工作对象和这个类之间加一层间接的层次。 这个模式我在底层的数据交换层用过。 我说过,flash和之间交换数据全以xml为载体。 返回xml在底层只有三层,数据库操作,数据操作,数据显示,由数据操作层返回给数据显示层一个xml字符串就可以了。 然后我就遇到一个小问题,在另一方面,我需要提交数据到数据库,也是提交一个xml字符串,但是我需要数据库里对应的表的数据集的xml表现形式的xsd验证! (一口气说完,差点没憋死)。 就是说我至少需要取出这个表里的一条记录,问题在于,我封装的类从来只返回xml,没有返回xsd的。 解决办法就是适配器,新建一个项目,加了一层专用于获得xml验证格式,这样就完成了不同接口之间的转换。 备注: 适配器和桥接很象,都是在已有类不符合要求的时候,加入一层间接的元素以达到目的。 不同的是适配器是解决不兼容接口之间的转换,桥接一般不涉及这个问题,只是完成一个一对多的转换。 11.外观模式(Facade) 每天都要去食堂,每个人去不同的窗口吃不同的菜,很累,今天全寝室推举猴子去打饭: 你吃这个,三两饭,我吃那个,五两饭,所有人都只跟猴子一个人交涉,食堂所有的师傅也只见猴子一个人。 举例: 这个模式在程序的上下层的通信之间可以应用得十分广泛。 Asp的每个模块要去不同的数据,访问数据库的不同表,就要跟不同的下层数据访问组件打交道。 就是说,每个mc模块必须知道,我要去哪个具体的数据访问组件取数据。 每个模块要维持自己的一个,至少是字符串。 如果运用外观模式。 我们可以让所有的需要数据交互的mc访问同一个aspx页面,比如getStrXml.aspx。 只要传送一个标示符,就可以通知这个唯一的取数据的叶面,访问哪个下层组件获取数据。 下层组件不知道哪个mc要求数据,mc也不知道数据的具体来源,这样,上下层之间互相都显得不透明。 这就降低了耦合度。 12.代理模式(Proxy) 可能我们不是每个人每天都想吃饭,所以我们要求猴子每天中午必须在寝室,如果我们要吃,他就去,如果我们都不吃,他爱干嘛干嘛。 举例: 这恐怕是每个人在flash里都会无意中用到的模式。 比如,一个网站,它的下级栏目不用在整个网站初始化的时候一开始就读进来,但是我们要确保,在浏览者想看并且点击导航条上的某个按钮时,能够正确地读进相应的影片文件,前提是,我们必须在内部保留一个索引,可以称作代理。 通常是一个空mc 13.策略模式(strategy) 我每天先在食堂找座位,再打饭,再打菜,再买杯酸奶。 这已经模式化。 要是食堂有服务员,我也会要他这么做。 举例,策略模式是把一系列的算法封装起来,形成一个类。 这个模式几乎是随时随地都可以整合到别的模式里去的,我的那一堆xml解析器实际上就是策略模式的应用,这个模式还应用到我网站的下层,因为flash提交给aspx页面的数据也是xml字符串,下层模块也需要相应的解析算法。 同样的,我把对xml的解析封装进了一个类。 //Cs文件里的解析函数 ClassDataModel.BlogMsgs{ … PublicDataSetparseXML(stringstrXml){ DataSetds=newDataSet
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- Flash oop 设计 模式