软件开发的主要阶段与任务

软件开发阶段&任务
  01 需求调研
    需求调研计划安排
    需求调研记录
    需求设计
      草图设计 Balsamiq Mockups
    提交需求分析报告
    需求评审
      用户,技术,调研人员
  02 详细设计
    依据需求分析报告
    原型设计
      设计工具
        Axure RP pro
        flairbuilder
      UI设计
      标准化
        框架
        元素
        界面
        文字
    详细设计报告
      用例图
      流程图
    详设评审
  03 系统架构设计
    系统技术架构
    事件流程图
  04 技术开发
    前端开发
    后端开发
    测试
      后端测试
      功能测试
      测试报告
  05 交付试行
    培训工作
    安装工作
    开工大会
    阶段评审
    联合评审

软件项目开发过程中应编写的十三类文档

软件项目开发过程中,应该按软件开发要求撰写十三类文档文档编制要求具有针对性、精确性、清晰性、完整性、灵活性、可追溯性!

1、可行性分析报告

说明该软件开发项目的实现在技术上、经济上和社会因素上的可行性,评述为了合理地达到开发目标可供选择的各种可能实施方案,说明并论证所选定实施方案的理由。

2、项目开发计划

软件项目实施方案制订出具体计划,应该包括各部分工作的负责人员、开发的进度、开发经费的预算、所需的硬件及软件资源等。

3、软件需求说明书(软件规格说明书)

对所开发软件的功能、性能、用户界面及运行环境等作出详细的说明。它是在用户与开发人员双方对软件需求取得共同理解并达成协议的条件下编写的,也是实施开发工作的基础。该说明书应给出数据逻辑和数据采集的各项要求,为生成和维护系统数据文件做好准备。

4、概要设计说明书

该说明书是概要实际阶段的工作成果,它应说明功能分配、模块划分、程序的总体结构、输入输出以及接口设计、运行设计、数据结构设计和出错处理设计等,为详细设计提供基础。

5、详细设计说明书

着重描述每一模块是怎样实现的,包括实现算法、逻辑流程等。

6、用户操作手册

本手册详细描述软件的功能、性能和用户界面,使用户对如何使用该软件得到具体的了解,为操作人员提供该软件各种运行情况的有关知识,特别是操作方法的具体细节。

7、测试计划

为做好集成测试和验收测试,需为如何组织测试制订实施计划。计划应包括测试的内容、进度、条件、人员、测试用例的选取原则、测试结果允许的偏差范围等。

8、测试分析报告

测试工作完成以后,应提交测试计划执行情况的说明,对测试结果加以分析,并提出测试的结论意见。

9、开发进度月报

该月报系软件人员按月向管理部门提交的项目进展情况报告,报告应包括进度计划与实际执行情况的比较、阶段成果、遇到的问题和解决的办法以及下个月的打算等。

10、项目开发总结报告

软件项目开发完成以后,应与项目实施计划对照,总结实际执行的情况,如进度、成果、资源利用、成本和投入的人力,此外,还需对开发工作做出评价,总结出经验和教训。

11、软件维护手册

主要包括软件系统说明、程序模块说明、操作环境、支持软件的说明、维护过程的说明,便于软件的维护。

12、软件问题报告

指出软件问题的登记情况,如日期、发现人、状态、问题所属模块等,为软件修改提供准备文档。

13、软件修改报告

软件产品投入运行以后,发现了需对其进行修正、更改等问题,应将存在的问题、修改的考虑以及修改的影响作出详细的描述,提交审批。

软件开发项目控制浅谈





摘要

本文主要谈谈软件开发项目控制的作用和类型,以及项目控制的步骤。
关键词
项目管理、控制

正文

一、项目控制的作用

      项目控制的作用就是为了保证项目按照预期的项目目标进行,必须对项目的运行情况和输出进行持续的跟踪监控,收集各种项目进展信息,对收集的信 息进行分析,与预期的项目目标进行比较。在出现偏差时及时分析偏差原因,制定有效的纠正预防措施,落实纠正预防措施。

      项目的特点是渐进明晰的,特别地软件开发项目更因为其结果的无形性、需求难以明确性、劳动密集性和智力密集性,渐进明晰这一特点更加显 著。在项目的初期,项目经理或项目成员基本上不可能像建设一栋有形的建筑一样,预想出项目实施过程中的所有情况(对于建筑行业来说,不可预见的主要是一些 不可抗力,如天气、人员的流失、供货的及时性)。所以,尽管已经尽可能明确制定了项目目标,并以此为目标制定了尽可能周密的计划,如果没有对照项目计划进 行严密的监控,并及时调整计划,不断使计划明晰化并符合实际,以尽可能地保证项目按照基准计划实施,并使计划的变更尽可能地减少,那么项目就很难达到原先 计划中制定的目标。这些目标要同时兼顾进度、质量、成本。

      所以不仅要制定出好的项目计划,更要进行严密的项目控制。项目控制是项目经理的一项重要职责,也是项目管理部门、项目成员、项目干系人的重要职责。

      项目控制的基础是项目计划,项目计划的基础是项目目标。因此,项目管理的第一步是要明确项目目标。软件开发项目目标应该包括软件系统的范围、 质量、进度、成本、市场或政治目标。范围目标是指软件系统的功能范围;质量目标包括软件系统的性能要求、技术指标、质量要求等等;进度目标包括软件系统的 交付时间,与客户达成共识的其他时间要求,如验收时间、培训时间等等;成本目标对企业内部来说就是项目的预算,对于客户来说就是能够给出合理的价格;市场 或政治目标就是诸如完成市场占有率、提高企业形象、打开知名度、击败某个竞争对手等等。

      第二步是根据目标分析自身的资源状况,资源包括人力资源(管理水平、技术水平、数量、行业知识与经验积累、技术知识与经验积累)、设备、资金、信息、与相关人员的关系或渠道。

      第三步是根据项目目标和资源约束来制定项目计划,项目计划应包括项目目标、项目任务的分解、项目组的组织机构和各角色责任、项目任务的责任分配、项目进度计划、成本计划、质量计划、沟通计划、风险防范计划、项目控制计划。

      第四步就是实施项目计划,在项目计划实施过程中要持续跟踪监控项目进展情况,并与项目计划比较,发现偏差,分析原因,及时采取纠正、预防措施,随时解决项目中需要解决的问题,包括项目团队的沟通和冲突问题。

      项目内外各种因素具有不确定性,同时项目相关环境中存在一定的干扰,因此项目的实施难以完全按照项目计划进行,出现偏差是不可避免的。良好的 项目控制可以保证项目按照计划稳定地完成项目目标,就是说可以及时地发现偏差、有效地缩小偏差、迅速地纠正或预防偏差,使项目始终按照合理的计划推进。

      下面引用著名的破窗理论来说明项目控制的重要性。

      美国心理学家詹巴斗进行过一项有趣的试验:他把两辆一模一样的汽车分别停放在帕罗阿尔托的中产阶级社区和相对杂乱的布朗克斯街区。停在中产阶 级社区的那一辆,停了一个星期也完好无损;而另一辆,他摘掉车牌,打开顶棚,结果不到一天就被人偷走了。后来,他把那辆完好无损的汽车敲碎了一块玻璃,结 果,仅仅过了几个小时车就不见了。以这项试验为基础,美国政治学家威尔逊和犯罪学家凯林提出了一个破窗理论。他们认为:如果有人打坏了一栋建筑上的一 块玻璃,又没有及时修复,别人就可能受到某些暗示性的纵容,去打碎更多的玻璃。久而久之,这些窗户就给人造成一种无序的感觉。结果,在这种麻木不仁的氛围 中,犯罪就会滋生、蔓延。

      “破窗理论在社会治安综合治理中的作用是显而易见的,在项目管理、项目控制中也有着重要的借鉴意义。许多人认为,这样做太简单,芝麻小事, 没有什么意义,而且兴师动众,没有必要。但是一个软件开发项目是否能够保证按照计划的进度质量成本完成的一个重要标志就是项目能否进行防微杜渐的控 制。这是破窗理论在项目管理领域中的一个直观的体现。有时,小题大做的处理是非常有必要的,以防止千里之堤,溃于蚁穴

      当然,话说回来,项目控制并不是对付项目中的小偷小摸或者犯罪嫌疑人。而是为了保证项目目标的达成。目前是讲究以人为本的时代, 项目控制也要讲究人性化管理。除了对项目进展的检查监督外,更有效、更长久的办法应该是提高人的素质,提倡责任控制、自发控制。

二、项目控制类型

1、按控制内容

      既然项目控制的作用和目的是为了保证项目实施最终能够满足项目目标的要求,而项目目标又包括项目可交付成果及软件产品的范围、质量、交付日 期,因此项目控制至少要包括范围控制、质量控制、进度控制。另外由于交付的成果大多具有确定的价格,而企业为了保证软件产品能够赢得一定的利润,就会设定 预算目标,因此还要进行成本控制。再者,软件需求的不明确性、项目的外在条件和多项目资源共享的情况,都有可能需要对项目计划进行调整,因此需要进行项目 的变更控制。

      范围控制:建筑行业可能不太需要范围控制,因为建造几栋房子其范围是非常。但也很难说,也许由于资金的问题,原来准备建7栋的,现在可能改成 先建4栋,再建3栋。或者原来准备建88层的,现在改成建68层。但是软件系统的范围控制就很重要,有的需求功能分解得很粗很模糊,项目范围是一个大致的 范围,这样就比较难以控制其范围。范围控制的第一步就是把项目的范围确定清晰。确定清楚后项目范围是比较好控制。

      质量控制:质量控制的目的是保证项目成果的质量满足项目质量计划中说明的项目成果的质量要求。项目质量计划的说明可能会引用其他文件来说明项 目成果的质量要求,如招标书、投标书、合同、需求规格说明书、国家标准、行业标准、企业内部制定的各种规范等等。

      进度控制:项目进行过程中,必须不断检查、监控项目的进展情况,以保证每项分解的任务都能按计划完成。持续收集项目进展数据,掌握项目计划的 实施情况,将实际情况与进度计划进行对比,分析其差距和造成这些差距的原因,必要时采取有效地纠正或预防措施,使项目按照项目进度计划中预定的工期目标进 行,防止延误工期。项目进度控制不仅要注意主要任务或关键路径上的任务的工期,也要注意一些本来次要的任务的进展,以防止次要任务拖延,影响主要任务和关 键路径上的任务。

      成本控制:成本控制的基础是在项目计划中对项目制定出合理的成本预算,也叫费用预算。成本控制就是尽可能地保证各项工作在项目计划中预定的预 算内进行。成本控制也可以叫费用控制。软件开发项目的成本最主要的是人力资源的成本,而人力资源的成本体现为各个项目成员薪资水平乘以他所花费工作日的总 合,因此人力资源的成本其重点在于合理地安排使用合适的人力资源。软件开发项目的成本还包括购买必需的软硬件设备的成本;需求调研所花费的交通、协作、通 信成本;购买必要的办公用品、参考资料的费用;给用户培训所需要花费的培训资料编写费、资料印刷费、产地费、设备费;如果需要第三方的鉴定或检测,还需要 一定的鉴定检测费用,包括准备的费用;如果部分组件需要外包,则应当控制软件外包的成本,包括交付给外包承担方的费用,和进行质量、进度控制的管理成本。

      变更控制:对于软件开发项目而言,变更一般是不可避免的。为了将项目变更的影响降低到最小,就需要采用变更控制的方法。变更控制就是要找出影 响项目变更的因素、判断项目变更范围是否有必要、判断项目变更的结果是否已经发生及效果如何等。进行变更控制的主要依据有:项目计划、变更请求和提供了项 目执行状况信息的绩效报告。

      在项目范围相对明确固定的情况下,质量、进度、成本三个目标一般是相互矛盾、互相制约的。赶工、缩短工期、加快进度往往导致成本上升或质量下 降,降低成本会使进度拖延或质量下降;提高质量需要更长的工期、更高的成本。因此应当注意平衡质量、进度、成本三个目标,更好地进行项目控制。

2、按控制执行人员

      项目控制按照控制执行人员来划分可以分为:项目组内控制、企业控制、用户方控制、第三方控制。

      项目组内控制:项目组内以项目经理为主,组织项目成员进行持续自我检查,对照项目计划,及时发现偏差、及时进行调整。

      企业控制:项目组以外,企业领导层以及生产部门、项目管理部门、质量管理部门、财务管理部门对项目进行控制。项目组一般应该定期提交项目状态报告给上述项目干系人,使他们了解项目的真实进展情况。

      用户方控制:用户方对于项目的进度、质量是最关心的,所以有责任感用户方会定期或不定期地需要获得项目进展的信息,作为他们项目控制的依据。 用户控制的措施主要是在发现问题后提出警告。当然,合同签订后软件系统的价格是固定的,所以他们对项目成本的关心程度不会像企业那样高。

      第三方控制:目前有些项目委托项目监理机构进行项目控制。作为第三方的监理机构,对于软件开发项目的成功是有利的,因为理论上监理单位利益独 立于双方之外,可以客观公正地提出相关意见和措施,保证项目的质量、进度及投资。同时,第三方监理拥有很强的咨询能力,可以帮助双方解决一些技术和管理难 题,促进项目进展。对信息工程建设项目实施成功与否做公正客观评价,又可以使软件系统用户和系统开发商双方的市场行为规范起来,客观上促进软件开发商提供 高质量的符合客户业务需求的软件系统,从而提高客户对建设软件系统的信心。

3、按控制方式

      控制一词的本意是指抑制或限制、指导或命令、核对或验证。项目控制是保证项目计划实施不偏离目标的有效手段,控制方式的选择伴随着控制者与控制对象渐进而长期的适应过程,它是一种综合而复杂的管理行为。

      远程控制:随着网络和通信技术的发展,企业经营市场的全球化,企业员工的工作可能远离企业管理部门,也可能在家里上班,传统的检查监控的控制方式无法适用。因此,制度控制将成为控制企业生产经营活动的一种重要方式。

      检查控制:企业通过检查监督等方式对项目组进行持续的监控,及时发现问题,解决问题,纠正偏差。人们不会做你期望他做的事情,只会做你准备检查的事情。这句话不完全对,但有一定的道理,主要看针对什么样的人。

      责任控制:项目任务分解合理,每个项目成员分工责任明确,每个成员按照自己的责任目标,按时保质地完成自己的任务。软件开发是智力型的手工劳动,传统机械的控制、管理方法很难起到真正的效果。

      自发控制:自发控制方式是把责任控制代之以更严格的、要求更高的、更有效的内部控制。它激励项目团队自觉行动,并不是别人要他做什么或怎么 做,而是客观的计划任务和变化的环境要求他采取相应的行动,不仅完成责任分配的份内工作,还在完成本职工作的基础上主动完成自己认为需要完成的工作。

4、按控制时机

      项目控制的时机可以可以在活动开始之前、之中和之后进行,分为预防控制、过程控制和纠正控制

      预防控制:防范于未燃是最好的一种项目控制方式,它可以预先做好准备避免和防止预期问题的发生。预防控制就是从项目的策划阶段开始,每个阶段 对后面项目实施的过程,根据经验预测和估计可能产生的偏差,并采取相应的防范措施,尽可能地消除偏差。例如,对于软件开发需要的技术,要及早安排培训学 习,做好技术预研,对于可能会流失的关键项目骨干,应当及早准备好替代人员。预防控制需要项目经理丰富的经验、敏锐的嗅觉和判断力、及时准确的信息。对于 确定的问题,进行项目假设和约束分析,假设是通过努力可以直接解决的问题,而这些问题是一定要解决才能保证项目按计划完成;约束一般是难以解决的问题,但 可以通过其他途径回避或弥补、取舍,如牺牲进度、质量等等;如果问题的出现具有不确定性,则应该在风险分析中列出,分析其出现的可能性(概率)、造成的影 响、采取的措施。

      过程控制:在项目的实施过程中进行持续的随时的监督和指导的控制。通过观察和定期汇报的形式都可以有效地进行过程控制,可以通过每周进度图表 清楚地显示计划的任务、已经完成的任务、与计划目标的偏差程度(准时、提早、延迟),一旦发现偏差,就应当考虑及时采取纠正或者预防措施。

      纠正控制:纠正控制是在项目的某个阶段或某个任务或整个项目基本结束或项目出现偏差后进行纠正的控制,这时候损失已经发生了,因此具有亡羊补牢的性质,纠正控制可能是迫不得已的唯一选择。

三、项目控制的步骤

      从以上项目控制的作用和类型分析来看,项目控制的基础和依据是项目目标和项目计划,所以项目控制的步骤就是:根据项目目标制定项目控制计划 (包括进度控制计划、质量控制计划、成本控制计划)、设定阶段成果验收准则、汇报和收集项目实施进展信息、判断偏差、分析偏差产生的原因和趋势、采取适当 的纠正预防措施,对纠正预防措施的有效性进行评估。

1、根据项目目标制定控制计划

      项目控制的对象不仅要针对总体任务,更要针对尽可能详细的分解后的任务,这样的控制才会取得应有的效果。因此项目控制的目标包括总体目标、分 任务目标、阶段目标。项目控制的基础是否扎实依赖于项目任务的分解是否清晰合理、是否尽可能的详细、阶段目标设置是否合理等等。有的任务的分解往往可以有 多种方案,应当找到既利于工作任务分配,有利于划分阶段目标的分解方案。

2
、设定阶段成果验收准则

      阶段成果验收准则应当包括在进度控制计划、质量控制计划、成本控制计划中。阶段成果验收准则就是判断阶段成果是否符合要求的标准,其最原始依 据是合同。由合同带出的依据包括需要遵守的相关技术标准规范、需求规格说明书、设计说明书、测试计划等等。

3、汇报和收集项目进展信息

      项目实施进展信息包括制度规定的定期汇报信息和项目管理人员不定期地收集的相关信息。定期汇报信息包括定期的会议和定期的项目阶段状态报告。 定期的汇报信息应但包括:项目当前状态、报告区间内完成的工作、计划区间内准备完成的工作、已经解决的问题、需要解决的问题(包括遗留未解决的问题、新出 现的问题、需要客户、企业领导层、兄弟部门等协调解决的问题)。项目管理部门根据项目组的汇报进行汇总统计。

4、判断偏差

      根据项目组汇报的项目当前状态(不能仅仅写一个延期或准时或提前、应当说明哪项任务延期、哪项任务准时、哪项任务提前)判断项目是否出现偏 差,这些偏差是在合理的范围、可接受的范围、还是应当尽快纠正的范围。通过把项目阶段状态汇报信息、汇总统计信息与项目计划、相关标准规范进行对比,及早 发现项目实施结果和计划预期结果之间的差距。为了更好地判断项目计划实施过程中的偏差,应该项目计划中按阶段设置必要的里程碑。不过,里程碑应当 设置的合理有效,而一旦里程碑设置好后,就要认真地进行对里程碑的结果进行检验,同时也不能仅仅依靠检查某些里程碑的结果,而不去跟踪监控产生这个结果的 过程。

5、分析偏差产生的原因和趋势

      所谓偏差主要是在进度和成本上的的,质量上的偏差对软件来说比较难以判断。项目实施过程中产生的偏差就是实际进展和项目计划之间的差距,可以 分为正偏差、负偏差和零偏差。零偏差意味着没有偏差;正偏差说明项目进度比进度计划有所超前,或当前花费成本少于计划中当前预算约定的成本;负偏差说明项 目进度比进度计划有所延迟,或当前花费成本多于计划中当前预算约定的成本。

      正偏差不完全是好事,负偏差也不完全是坏事。这些偏差的原因是什么,应当进一步向项目组了解情况,具体分析产生偏差的原因。

      可能的原因有:原来制定的项目计划不合理,过于保守的计划造成了正偏差,过于乐观的计划造成了负偏差;技术革新、管理革新提高了效率造成了正 偏差,资源不足、低效率、故障、人员离职造成了负偏差;成本的增加(负偏差),如增加奖金、提高工资、提高加班补贴造成了进度正偏差或零偏差;抽走技术人 员(正偏差)造成进度的负偏差;需求分析不够清楚、设计方案有问题造成进度和成本的负偏差;外部因素有:客户配合不力、外包供应商未能按期、按质的要求交 付、战争或自然灾害等不可抗力等等。

       除了要分析出偏差的原因,还要根据原因分析除可能的趋势。原来的正偏差或零偏差是否会发展成负偏差,原来的负偏差是否有希望扭转成正偏差,还是会在不采取措施的情况下越来越严重,对后面的项目活动有多大程度的影响。

6、采取适当的纠正预防措施

      偏差的判断和分析让我们了解了偏差的根源,可以有的放矢地制定适当的纠正或预防措施。如果是计划不合理,就进行计划变更;如果是设计不合理, 就进行设计变更;如果是人力资源不足,就适当增加人力资源;如果需要加班,就采取适当的措施安排加班。只有分析出造成偏差的根源和责任人,才能制定出对症 下药的和可以落实到具体人员的纠正预防措施。
7
、跟踪评估措施的有效性

      项目出现偏差后,制定的纠正预防措施和项目计划一样应该是具有可跟踪性的,就是说必须落实到具体的人负责,同时纠正的结果和效果是可以检验 的。纠正预防措施制定出来后,应当保证落到实处,因此必须进行跟踪检查,对纠正预防措施的有效性进行评估。

 

AS3应用程序模块化开发与ApplicationDomain

转发:http://eidiot.net/2007/06/03/applicationdomain/

当程序越来越大,我们需要把它拆分成多个swf,在需要的时候动态加载。拆分时应该尽量把不同的类编译进唯一的swf,避免因swf文件增多而使整个程序的文件尺寸增大。按此原则可以拆分出以下两种swf,借助 ApplicationDomain 共享其代码和资源。

  • 模块(Module)
    按照程序逻辑,可以拆分出多个“功能模块”,如“注册”、“管理”等等;按照游戏或社区类程序的关卡或场景,可以拆分出不同的“场景模块”。这些模块不是主程序运行必须的,只在需要的时候加载。
  • 运行时共享库(RSL)
    主场景或者多个模块通用的资源,比如位图、声音、设计好的页面元素等,可作为“库”在主程序运行前加载。可以整套更换的皮肤(skin)只需先加载一套。

  ApplicationDomain 是存放AS3定义(包括类、方法、接口等)的容器。使用Loader类加载swf时可以通过指定 ApplicationDomain 参数将swf加载到不同的域(Domain):

var loader : Loader = new Loader();
var context : LoaderContext = new LoaderContext();
/* 加载到子域(模块) */
context.applicationDomain = new ApplicationDomain(ApplicationDomain.currentDomain);
/* 加载到同域(共享库) */
context.applicationDomain = ApplicationDomain.currentDomain;
/* 加载到新域(独立运行的程序或模块) */
context.applicationDomain = new ApplicationDomain();
loader.load(new URLRequest("loaded.swf"), context);

  ApplicationDomain使用类似于显示列表(DisplayList)的树形结构。 相对于舞台(Stage) ,可以认为 ApplicationDomain 最根部的是系统域(system domain),包含 Flash Player 核心类定义。主程序所在的域(以下简称主域)就是它唯一的子域,类似于Stage下的文档类(Document Class)。
一个fla文档类里代码:

this.stage.addChild(mySprite);
this.addChild(myMC);
this.addChild(myShape);

  运行后的显示列表:
01.gif
ApplicationDomain 的类似结构:
02.gif

  • 加载到子域(模块)
    类似于“继承”,子域可以直接获得父域所有的类定义,反之父域得不到子域的。和继承关系不同的是,如果子域中有和父域同名的类,子域定义会被忽略而使用父域的定义。
  • 加载到同域(运行时共享库)
    类似集合里的合并关系。被加载swf里的所有类定义被合并到当前域中可以直接使用。和加载到子域相同,和当前域同名的定义也会被忽略。
  • 加载到新域(独立运行的程序或模块)
    swf载入指定域之前,先要检查该域及其父域中是否存在同名类,重复定义一概忽略。如果加载别人写的程序,或者使用旧版本的主程序加载新版本的模块,为避免类名冲突就要加载到新域独立运行以使用自己的类。

  模块加载到同域不是一样可以吗?为何要加载到子域呢?好处就在于,卸载一个加载到子域的模块时,只要确保清除所有到该模块的引用,模块的所有类定义将被垃圾回收(Garbage Collection)。
有两种方式可以访问 ApplicationDomain :

  • ApplicationDomain.currentDomain
    currentDomain是ApplicationDomain的静态变量,表示当前代码所 在的域。该变量很奇特,在主程序里指向主域,在加载到子域的模块里则指向该模块所在的子域。虽然 ApplicationDomain 有个 parentDomain 属性,但子域已经自动获得了父域的类定义,所以通过 ApplicationDomain.currentDomain 就可以获取父域定义了——包括主程序和加载到主域的共享库。(注:系统域不可直接访问,主域和所有新域即系统域子域的parentDomain属性为 null)
  • LoaderInfo类的applicationDomain属性
    此方式可以访问任何方式加载的swf的 ApplicationDomain。对于主程序来说,加载到同域的库定义已经存在于 ApplicationDomain.currentDomain ,而模块的类主程序一般用不到。所以这种方式个人不推荐使用。

  ApplicationDomain 的 hasDefinition() 方法判断某定义是否存在,getDefinition() 方法获取指定的定义。下面以一个 例子 来介绍 ApplicationDomain 的具体用法和应用程序的拆分。
本例 有四个swf,shell.swf是主程序,lib.swf是共享库,login.swf和result.swf分别是“登录”和“结果”模块,所有的视 图元件都在共享库中。实际开发时可能有很多库,比如“位图库”、“音效库”、“模型通用库”等。“通用库”里存放多个模块共用的资源,比如此例中的背景元 素。而各个模块独有的资源还是放在各自的swf中。
主程序首先将共享库加载到同域,完成后将“登录模块”加载到子域。主程序可以像操作普通的视觉对象(DisplayObject)一样操作加载的模 块:监听事件、调用方法。因为编译器不会识别未定义的类,为使用强类型,建议为主类和模型定义相应的接口,使用少量的重复代码协助编程。

private function showModule(p_module : IModule) : void
{
   
if (this.m_moduleList[0] == "login.swf")
   
{
       
p_module.show(this);
       
p_module.addEventListener("login", this.onLogin);
   
} else
   
{
       
p_module.show(this, this.m_userName);
   
}
}

  模块“继承”了主程序和共享库的所有类和资源,可以通过 ApplicationDomain.currentDomain.getDefinition() 来获取相应的类。注意获取不存在的类会抛出一个 ReferenceError。

protected function getClass(p_name : String) : Class
{
   
try
   
{
       
return ApplicationDomain.currentDomain.getDefinition(p_name) as Class;
   
} catch (p_e : ReferenceError)
   
{
       
trace("定义 " + p_name + " 不存在");
       
return null;
   
}
   
return null;
}

  登录模块获取库中的界面元素,并在点击按钮后抛出事件。Event类不允许带参数,必须使用继承Event的自定义事件抛出参数。主程序可以把 模块的自定义事件也编译进去(这样就增大了整个程序的文件尺寸),或者让监听模块事件的函数接受一个Objcet参数,以获取其动态属性。

private function onLogin(p_e : Object) : void
{
   
this.m_userName = p_e.userName;
   
var login : IModule = p_e.currentTarget;
   
login.removeEventListener("login", this.onLogin);
   
login.dispose();
   
this.loadSwf();
}

  主程序收到事件之后卸载注册模块,加载“结果模块”到子域,并将登录模块传出的”userName”参数传给结果模块。

public function show(p_parent : DisplayObjectContainer, … rest) : void
{
   
var libClass : Class = this.getClass("net.eidiot.appDomainDemo.Libaray");
   
if (libClass != null) this.initUi(libClass, rest);
}
override protected function initUi(p_libClass : Class, p_rest : Array = null) : void
{
   
this.addUi(this.getClass(p_libClass.BG_NAME), "结果");
   
var resultFunc : Function = p_libClass.getResult;
   
var userName : String = p_rest[0];
   
this.addChild(resultFunc(userName));
}

  注意initUi()方法分别使用了共享库中Libaray类的静态属性BG_NAME和静态方法getResult()。但是直接调用此静态方法会报错,可以先用 resultFunc 变量取出此方法。详细内容请参考 源代码

 

FLEX- MDI窗口开发实例(2)

修改了一些bugs,下一步打算做个像ActiveDesktop的应用。

其他代码和FLEX- MDI窗口开发实例一样。
in MDITest1.mxml

1 xml version=”1.0″ encoding=”utf-8″?>
2 <ChildWindow xmlns=”ext.containers.windows.mdi.*” xmlns:mx=”http://www.adobe.com/2006/mxml”
3 width=”340″ height=”214″ xmlns:flexlib=”flexlib.containers.*”
4 title=”child window” layout=”absolute”
5 minButtonVisible=”{cbMin.selected}”
6 maxButtonVisible=”{cbMax.selected}”
7 closeButtonVisible=”{cbClose.selected}”
8 >
9
10 <mx:CheckBox id=”cbMin” x=”45″ y=”49″ label=”Min Button” selected=”true” />
11 <mx:CheckBox id=”cbMax” x=”181″ y=”49″ label=”Max Button” selected=”true” />
12 <mx:CheckBox id=”cbClose” x=”124″ y=”106″ label=”Close Button” selected=”true”/>
13
14
15 ChildWindow>
16

细心一些朋友会发现5-6行是以前没有的属性,用来控制按键是否显示。
另增强了自定制加入按钮的方法,这样就可以派生window或childWindow重载

1 protected function addToolButtons(buttonArray:Array):void
2 {
3 //create buttons and add to buttonArray
4 }

程序会按照先后顺序来排列按钮。

FLEX- MDI窗口开发实例

参考了杜增强的dpanel和flex Doc Team的关于Creating Resizable and Draggable flex Components

 

连接:

dpanel
Creating Resizable and Draggable Flex Components
 

demo

下载
 

示例:


 

代码:

 

application.mxml

 

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical"
     xmlns:mdi
="ext.containers.windows.mdi.*" width="100%" height="100%"
creationComplete
="initCollections();">
    
<mx:Script>
        
<![CDATA[
            import mx.events.MenuEvent;
            import mx.collections.XMLListCollection;
            import mx.controls.Alert;
            import mx.managers.PopUpManager;
            import mx.managers.SystemManager;
            import mx.containers.Panel;
            import ext.containers.windows.mdi.ChildWindow;
            import mx.events.flexEvent;
            private var menuBarXML:XMLList =
            <>
                <menuitem label = "windows">
                    <menuitem label ="create window" data="createWindow"/>
                    <menuitem label ="close window" data="closeWindow"/>
                    <menuitem label ="max window" data ="maxWindow"/>
                    <menuitem label ="min window" data = "minWindow"/>
                    <menuitem label ="min all windows" data ="minAllWindows"/> 
                    <menuitem label ="Tile window" data ="tileWindow"/>
                    <menuitem label ="Cascade window" data ="cascadeWindow"/>
                </menuitem>
                <menuitem label ="modal window">
                    <menuitem label ="create modal window" data ="showModal"/>
                </menuitem>
            </>;        
            [Bindable]
            private var menuBarCollection:XMLListCollection;
            
            private function initCollections():void
            {
                menuBarCollection = new XMLListCollection(menuBarXML);
            }
            private function menuHandler(e:MenuEvent):void{
                //Alert.show(e.item.@data);
                switch(String(e.item.@data)){
                    case "createWindow":
                        new MDITest1().addToMainArea();
                        break;
                    case "showModal":
                        (new ModalWindow()).showModal();
                        break;
                    case "closeWindow":
                        ma.windowClose();
                        break;
                    case "maxWindow":
                        ma.maxActiveWindow();
                        break;
                    case "minWindow":
                        ma.minActiveWindow();
                        break;
                    case "minAllWindows":
                        ma.windowMinimizeAll();
                        break;
                    case "tileWindow":
                        ma.windowTileHorizontal();
                        break;
                    case "cascadeWindow":
                        ma.windowCascade();
                        break;
                }
            }
        
]]>
    
</mx:Script>
    
<mx:MenuBar x="0" y="0" labelField="@label" itemClick="menuHandler(event);"
dataProvider
="{menuBarCollection}" width="100%" />
    
<mdi:MainArea id="ma" width="100%" height="100%"/>
</mx:Application>

 

MDITest1.mxml

 

1 <?xml version="1.0" encoding="utf-8"?>
2 <ChildWindow xmlns="ext.containers.windows.mdi.*" xmlns:mx="http://www.adobe.com/2006/mxml"
width
="400" height="300" xmlns:flexlib="flexlib.containers.*" title="child window">
3     <flexlib:Docker>
4         <flexlib:DockableToolBar width="215">
5         <mx:Button width="30" label="B" fontWeight="bold" fontFamily="Arial"/>
6         <mx:Button width="32" label="I" fontStyle="italic"/>
7         </flexlib:DockableToolBar>
8     </flexlib:Docker>
9 </ChildWindow>

 

ModalWindow.mxml

 

 1 <?xml version="1.0" encoding="utf-8"?>
 2 <Window xmlns="ext.containers.windows.*" 
 3     xmlns:mx="http://www.adobe.com/2006/mxml" width="412" height="322" 
 4     layout="absolute" xmlns:flexlib="flexlib.containers.*" 
 5     title="This is a modal window" >
 6     <mx:Script>
 7         <![CDATA[
 8             import mx.controls.Alert;
 9         ]]>
10     </mx:Script>
11     <mx:Button label="close" x="331" y="246" click="modalResult = Alert.CANCEL;"/>
12     <flexlib:SuperTabNavigator x="10" y="10" width="376" height="221" tabEnabled="true">
13         <mx:Canvas label="one" width="100%" height="100%">
14             <mx:DataGrid x="5" y="0" width="100%" height="100%">
15                 <mx:columns>
16                     <mx:DataGridColumn headerText="Column 1" dataField="col1"/>
17                     <mx:DataGridColumn headerText="Column 2" dataField="col2"/>
18                     <mx:DataGridColumn headerText="Column 3" dataField="col3"/>
19                 </mx:columns>
20             </mx:DataGrid>
21         </mx:Canvas>
22         <mx:Canvas label="two" width="100%" height="100%">
23         </mx:Canvas>
24         <mx:Canvas label="three" width="100%" height="100%">
25         </mx:Canvas>
26         <mx:Canvas label="four" width="100%" height="100%">
27         </mx:Canvas>
28     </flexlib:SuperTabNavigator>
29     <mx:Button label="ok" x="288" y="246" click="modalResult = Alert.OK"/>
30 </Window>
31 

ModalWindow.mxml中第11行中 click事件中只要对modalResult写值就自动关闭窗口,模仿delphi中的模态窗口。