版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
Android初级培训教程27/271.11框架和设计模式介绍(10课时机上10课时)目录第一-二课时 2教学目标 21.11.1-2.1什么是框架 21.11.1-2.2为什么要采用框架? 21.11.1-2.3开源框架的出现 21.11.1-2.4框架的发展过程 51.11.1-2.5Java的主流框架 5第三-四课时 6教学目标 61.11.3-4.1MVC简介 61.11.3-4.2MVC设计思想 71.11.3-4.3MVC的应用图 81.11.3-4.4MVC设计模式的实现 101.11.3-4.5MVC的优点 101.11.3-4.6MVC的不足 11第五-六课时 11教学目标 111.11.5-6.1什么是设计模式 111.11.5-6.2设计模式的表述格式 111.11.5-6.3设计模式的分类 12第七-八课时 15教学目标 151.11.7-8.1工厂方法模式的概述 151.11.7-8.2为何要使用工厂模式? 151.11.7-8.3例子 171.11.7-8.4适用性 21第九-十课时 22教学目标 221.11.9-10.1观察者模式概述 221.11.9-10.2参与类别 221.11.9-10.3观察者模式实例代码 231.11.9-10.4用途 261.11.9-10.5示例 26第一-二课时教学目标框架介绍与运用。1.11.1-2.1什么是框架框架(Framework)是整个或部分系统的可重用设计,表现为一组抽象构件及构件实例间交互的方法;另一种定义认为,框架是可被应用开发者定制的应用骨架。前者是从应用方面而后者是从目的方面给出的定义。1.11.1-2.2为什么要采用框架?框架是由一些类组成,正式这些类为应用程序提供了一个可重用的设计或者我们经常提到的应用程序种的一层。应用程序代码访问类库从而执行任务,而框架是调用应用程序代码,从而管理程序的流程。这就是经常说道的好莱坞原则:“不要试图联系我们,我们到时候自会通知你。”开发者写的程序在运行时由框架调用。设计一个在各种未知背景下都可以使用的框架是很有挑战性的。框架很适合在复杂的J2EE开发中使用,它可以为开发者提供一个简单易用的模型。采用一个经过良好设计的开源框架有很多好处:好的框架下,开发者只需要写一些必须的代码;他们不需要直接接触底层的API。经过良好设计的框架可以为程序提供清晰的结构并且提高程序的内聚性。清晰的结构使得其他人可以更容易加入项目。一个容易使用的框架,可以通过一些例子和文档为用户提供最佳实践。采用成功框架的代码比自己的代码容易测试框架只有提供了一些值得使用的功能才会变得流行。J2EE工程只有真正需要框架的时候才会用它,而自己的框架并不是这样,后者是处于统治地位的。J2EE本身也提供了一些框架。比如,EnterpriseJava-Beans(EJB)container或者Servletengine,二者都运用了“采用了好莱坞原则”这个思想,并采用运行时调用来管理对象。像Struts这些开源web应用框架正式建立在这两个框架的基础上的,像Struts这样建立在J2EE上的框架,他们为开发者提供了更为简单的模型和其他的一些好处。1.11.1-2.3开源框架的出现很多大型的J2EE项目都用自己的内部框架来隐藏平台的复杂性,直到最近人们才逐渐发现一些在很多项目中都存在的共有的难题,这些难题都可以由一个较为统一的解决方案来解决。而有的框架正好可以充当这些问题的解决方案。现在有种很明显的趋势:与从前的内部框架相比,这些框架将成为这些难题“标准化”的解决方案。J2EE平台的日益成熟是这些框架流行的一个原因。开发者知道有些地方是J2EE的标准API无能为力的,以他们的经验来看,要弥补这个缺陷是很困难的。于此同时,一些优秀的开源框架可供使用,它们提供了极为丰富的技术文档,在它们背后还有一个专业的团队做支持,并且一切都是免费的。Struts,在web应用程序产生时就有的开源框架。在1999-2000年,开发者们意识到JSP“Model1”的缺陷,JSP中充斥着请求处理代码和静态数据模板,这意味着你不得不把业务逻辑和复杂的HTML以及其他的标签混到一起。那个时候还没有标准的框架和J2EE的标准支持,要解决这个问题开发者就得自己实现前端控制器,这样可以把业务逻辑分离到java类中,从而可以减轻对JSP的维护难度。前端控制器模式经常运用在MVC架构中,MVC模式在OO语言的GUI开发中经常使用(这个名字总是让人误解,WEBMVC中的视图是从模型中“拉”数据;而在经典MVC中,模型把事件“推向”视图)。最初的前端控制器实现质量参差不齐。2001~2002年间,Apache开源组织发布的Struts改变了这个状况,虽然它并非一个完美的框架,但已经足够使其成为该领域事实上的标准。Struts向人们展示了开源框架的一些优点,比如,新手可以很容易地熟悉它的结构。Struts几乎用在每一个J2EE项目中,这使得它成为J2EE架构的一个重要组成部分。甚至很多保守的组织也将其作为软件底层的一部分,并同意接受Apache的开源协议条款。图1.11-1struts框架设计图框架在持久化中应用。J2EE提供了两个持久化的手段:JDBC,它是J2SE中访问关系数据库系统的标准API;另一个是实体Beans,它是EJB中专门模型化持久化实体的组件。JDBC以一种错误的编程模型来强制开发者用Java代码来处理关系思想。而实体beans,先不说Sun和其他主要的J2EE供应商的吹嘘,给人很笨重的感觉:起初这门技术的应用范围很窄,持久化对象间的关系都不能处理。它使得应用程序难于测试,并且使用了一个很糟糕的查询语言。直到2003年,即使EJB2.0做了很多改进,开发者们却很少用它。早期的尝试持久化问题的解决方案是由关系-对象映射(ORM)来解决的,它可以透明地持久化普通java对象(POJO)。虽然这种方案并不是专属java的。但相对与其他的社区而言比如.NET,ORM在java社区更加流行。在后来Hibernate的出现。ORM领域在2002年发生了大变化,原因有两个。首先,实体Beans在实践中失败,开发者们将其从J2EE中忽视掉了。它向开发者们说明了一个规范是如何将开发拉入泥潭的。另外的一个原因是Hibernate的发布,它是第一个功能健全的解决关系对象影射解决方案。虽然在功能上,它功能并不多样。但在那些最常用的功能上,Hibernate实现的更加健壮,并且有一个非常专业的团队提供全职的开发。Hibernate并不是全新的,它的ORM思想在这个领域很普遍,但它提供的编程模型比其他任何竞争者都容易使用、都来的直接,它为ORM的使用提供了更加易用、廉价的途径。图1.11-2Hibernate结构图1.11.1-2.4框架的发展过程=1\*GB3①1980年代初期Smalltalk-80的MVCFramework=2\*GB3②1980年代中期Macintoshdianna的MacAppFramework=3\*GB3③1990年代初期VisualC++的MFCFramework④1990年代中期IBM的SanFranciscoFramework⑤2000年Microsoft的.NetFramework⑥2007年Google的Android框架1.11.1-2.5Java的主流框架=1\*GB3①SpringSpring是一个解决了许多在J2EE开发中常见的问题的强大框架。Spring提供了管理业务对象的一致方法并且鼓励了注入对接口编程而不是对类编程的良好习惯。Spring的架构基础是基于使用JavaBean属性的InversionofControl容器。然而,这仅仅是完整图景中的一部分:Spring在使用IoC容器作为构建完关注所有架构层的完整解决方案方面是独一无二的。Spring提供了唯一的数据访问抽象,包括简单和有效率的JDBC框架,极大的改进了效率并且减少了可能的错误。Spring的数据访问架构还集成了Hibernate和其他O/Rmapping解决方案。Spring还提供了唯一的事务管理抽象,它能够在各种底层事务管理技术,例如JTA或者JDBC事务提供一个一致的编程模型。Spring提供了一个用标准Java语言编写的AOP框架,它给POJOs提供了声明式的事务管理和其他企业事务--如果你需要--还能实现你自己的aspects。这个框架足够强大,使得应用程序能够抛开EJB的复杂性,同时享受着和传统EJB相关的关键服务。Spring还提供了可以和IoC容器集成的强大而灵活的MVCWeb框架。②STRUCTSStruts是一个基于SunJ2EE平台的MVC框架,主要是采用Servlet和JSP技术来实现的。由于Struts能充分满足应用开发的需求,简单易用,敏捷迅速,在过去的一年中颇受关注。Struts把Servlet、JSP、自定义标签和信息资源(messageresources)整合到一个统一的框架中,开发人员利用其进行开发时不用再自己编码实现全套MVC模式,极大的节省了时间,所以说Struts是一个非常不错的应用框架。③HibernateHibernate是一个开放源代码的对象关系映射框架,它对JDBC进行了非常轻量级的对象封装,使得Java程序员可以随心所欲的使用对象编程思维来操纵数据库。Hibernate可以应用在任何使用JDBC的场合,既可以在Java的客户端程序实用,也可以在Servlet/JSP的Web应用中使用,最具革命意义的是,Hibernate可以在应用EJB的J2EE架构中取代CMP,完成数据持久化的重任。,Hibernate可以在应用EJB的J2EE架构中取代CMP,完成数据持久化的重任。第三-四课时教学目标MVC设计模式介绍。1.11.3-4.1MVC简介MVC架构是"Model-View-Controller"的缩写,中文翻译为"模型-视图-控制器"。MVC应用程序总是由这三个部分组成。Event(事件)导致Controller改变Model或View,或者同时改变两者。只要Controller改变了Models的数据或者属性,所有依赖的View都会自动更新。类似的,只要Controller改变了View,View会从潜在的Model中获取数据来刷新自己。模型-视图-控制器(MVC)是XeroxPARC在八十年代为编程语言Smalltalk-80发明的一种软件设计模式,至今已被广泛使用。最近几年被推荐为Sun公司J2EE平台的设计模式,并且受到越来越多的使用ColdFusion和PHP的开发者的欢迎。图1.11-3MVC示意图1.11.3-4.2MVC设计思想图1.11-4 MVC组件类型的关系和功能视图视图(View)代表用户交互界面,对于Web应用来说,可以概括为HTML界面,但有可能为XHTML、XML和MVC模式Applet。随着应用的复杂性和规模性,界面的处理也变得具有挑战性。一个应用可能有很多不同的视图,MVC设计模式对于视图的处理仅限于视图上数据的采集和处理,以及用户的请求,而不包括在视图上的业务流程的处理。业务流程的处理交予模型(Model)处理。比如一个订单的视图只接受来自模型的数据并显示给用户,以及将用户界面的输入数据和请求传递给控制和模型。模型模型(Model):就是业务流程/状态的处理以及业务规则的制定。业务流程的处理过程对其它层来说是黑箱操作,模型接受视图请求的数据,并返回最终的处理结果。业务模型的设计可以说是MVC最主要的核心。目前流行的EJB模型就是一个典型的应用例子,它从应用技术实现的角度对模型做了进一步的划分,以便充分利用现有的组件,但它不能作为应用设计模型的框架。它仅仅告诉你按这种模型设计就可以利用某些技术组件,从而减少了技术上的困难。对一个开发者来说,就可以专注于业务模型的设计。MVC设计模式告诉我们,把应用的模型按一定的规则抽取出来,抽取的层次很重要,这也是判断开发人员是否优秀的设计依据。抽象与具体不能隔得太远,也不能太近。MVC并没有提供模型的设计方法,而只告诉你应该组织管理这些模型,以便于模型的重构和提高重用性。我们可以用对象编程来做比喻,MVC定义了一个顶级类,告诉它的子类你只能做这些,但没法限制你能做这些。这点对编程的开发人员非常重要。业务模型还有一个很重要的模型那就是数据模型。数据模型主要指实体对象的数据保存(持续化)。比如将一张订单保存到数据库,从数据库获取订单。我们可以将这个模型单独列出,所有有关数据库的操作只限制在该模型中。控制控制(Controller)可以理解为从用户接收请求,将模型与视图匹配在一起,共同完成用户的请求。划分控制层的作用也很明显,它清楚地告诉你,它就是一个分发器,选择什么样的模型,选择什么样的视图,可以完成什么样的用户请求。控制层并不做任何的数据处理。例如,用户点击一个连接,控制层接受请求后,并不处理业务信息,它只把用户的信息传递给模型,告诉模型做什么,选择符合要求的视图返回给用户。因此,一个模型可能对应多个视图,一个视图可能对应多个模型。模型、视图与控制器的分离,使得一个模型可以具有多个显示视图。如果用户通过某个视图的控制器改变了模型的数据,所有其它依赖于这些数据的视图都应反映到这些变化。因此,无论何时发生了何种数据变化,控制器都会将变化通知所有的视图,导致显示的更新。这实际上是一种模型的变化-传播机制。模型、视图、控制器三者之间的关系和各自的主要功能,如图1所示。1.11.3-4.3MVC的应用图MVC在Web程序中的应用图1.11-5MVC在Web程序中的应用框架图MVC通常用法图1.11-6MVC通常用法示例图1.11.3-4.4MVC设计模式的实现ASPNETaspnet提供了一个很好的实现这种经典设计模式的类似环境。开发者通过在ASPX页面中开发用户接口来实现视图。控制器的功能在逻辑功能代码(.cs)中实现。模型通常对应应用系统的业务部分。在ASPNET中实现这种设计而提供的一个多层系统,较经典的ASP结构实现的系统来说有明显的优点。将用户显示(视图)从动作(控制器)中分离出来,提高了代码的重用性。将数据(模型)从对其操作的动作(控制器)分离出来可以让你设计一个与后台存储数据无关的系统。就MVC结构的本质而言,它是一种解决耦合系统问题的方法。MFC微软所推出的MFCDocument/View架构是早期对于MVC实现,MFC将程序分成CView以及CDocument两大类,其中的Document对应MVC中的Model,View相当于MVC中的View+Controller,再加上CWinApp类,合成三大项。但是基本上MFC是一个失败的MVC作品。由于MFC之下的Document/View定义过于模糊,未将Controller(MessageMap)部份取出,因此Controller可以置入View或Document,但不管置入哪一方面,都会与View或Document绑死,没有弹性。JavaJava平台企业版(J2EE)和其他的各种框架不一样,J2EE为模型对象(ModelObjects)定义了一个规范。视图(View)在J2EE应用程序中,视图(View)可能由JavaServerPage(JSP)承担。生成视图的代码则可能是一个servlet的一部分,特别是在客户端服务端交互的时候。控制器(Controller)J2EE应用中,控制器可能是一个servlet,现在一般用Struts实现。模型(Model)模型则是由一个实体Bean来实现。1.11.3-4.5MVC的优点大部分用过程语言比如ASP、PHP开发出来的Web应用,初始的开发模板就是混合层的数据编程。例如,直接向数据库发送请求并用HTML显示,开发速度往往比较快,但由于数据页面的分离不是很直接,因而很难体现出业务模型的样子或者模型的重用性。产品设计弹性力度很小,很难满足用户的变化性需求。MVC要求对应用分层,虽然要花费额外的工作,但产品的结构清晰,产品的应用通过模型可以得到更好地体现。首先,最重要的是应该有多个视图对应一个模型的能力。在目前用户需求的快速变化下,可能有多种方式访问应用的要求。例如,订单模型可能有本系统的订单,也有网上订单,或者其他系统的订单,但对于订单的处理都是一样,也就是说订单的处理是一致的。按MVC设计模式,一个订单模型以及多个视图即可解决问题。这样减少了代码的复制,即减少了代码的维护量,一旦模型发生改变,也易于维护。其次,由于模型返回的数据不带任何显示格式,因而这些模型也可直接应用于接口的使用。再次,由于一个应用被分离为三层,因此有时改变其中的一层就能满足应用的改变。一个应用的业务流程或者业务规则的改变只需改动MVC的模型层。控制层的概念也很有效,由于它把不同的模型和不同的视图组合在一起完成不同的请求,因此,控制层可以说是包含了用户请求权限的概念。最后,它还有利于软件工程化管理。由于不同的层各司其职,每一层不同的应用具有某些相同的特征,有利于通过工程化、工具化产生管理程序代码。1.11.3-4.6MVC的不足MVC的不足体现在以下几个方面:(1)增加了系统结构和实现的复杂性。对于简单的界面,严格遵循MVC,使模型、视图与控制器分离,会增加结构的复杂性,并可能产生过多的更新操作,降低运行效率。(2)视图与控制器间的过于紧密的连接。视图与控制器是相互分离,但确实联系紧密的部件,视图没有控制器的存在,其应用是很有限的,反之亦然,这样就妨碍了他们的独立重用。(3)视图对模型数据的低效率访问。依据模型操作接口的不同,视图可能需要多次调用才能获得足够的显示数据。对未变化数据的不必要的频繁访问,也将损害操作性能。(4)目前,一般高级的界面工具或构造器不支持MVC架构。改造这些工具以适应MVC需要和建立分离的部件的代价是很高的,从而造成使用MVC的困难。第五-六课时教学目标设计模式的介绍。1.11.5-6.1什么是设计模式设计模式这个术语是由ErichGamma等人在1990年代从建筑设计领域引入到计算机科学的。它是对软件设计中普遍存在(反复出现)的各种问题,所提出的解决方案。设计模式并不直接用来完成代码的编写,而是描述在各种不同情况下,要怎么解决问题的一种方案。面向对象设计模式通常以类或对象来描述其中的关系和相互作用,但不涉及用来完成应用程序的特定类或对象。设计模式能使不稳定依赖于相对稳定、具体依赖于相对抽象,避免会引起麻烦的紧耦合,以增强软件设计面对并适应变化的能力。并非所有的软件模式都是设计模式,设计模式特指软件“设计”层次上的问题。还有其它非设计模式的模式,如架构模式。同时,算法不能算是一种设计模式,因为算法主要是用来解决计算上的问题,而非设计上的问题。随着软件开发社区对设计模式的兴趣日益增长,已经出版了一些相关的专著,定期召开相应的研讨会,而且WardCunningham为此发明了WikiWiki用来交流设计模式的经验并发表了《设计模式》一书。1.11.5-6.2设计模式的表述格式表述一个软件设计模式的格式根据作者的不同,划分和名称等都会有所不同。常用的GoF描述模式的格式大致分为以下这些部分:模式名:每一个模式都有自己的名字,模式的名字使得我们可以讨论我们的设计。问题:在面向对象的系统设计过程中反复出现的特定场合,它导致我们采用某个模式。解决方案:上述问题的解决方案,其内容给出了设计的各个组成部分,它们之间的关系、职责划分和协作方式。别名:一个模式可以有超过一个以上的名称。这些名称应该要在这一节注明。动机:该模式应该利用在哪种情况下是本节提供的方案(包括问题与来龙去脉)的责任。适用性:模式适用于哪些情况、模式的背景等等。结构:这部分常用类图与交互图阐述此模式。参与者:这部分提供一份本模式用到的类与对象清单,与它们在设计下扮演的角色。合作:描述在此模式下,类与对象间的交互。影响:采用该模式对软件系统其他部分的影响,比如对系统的扩充性、可移植性的影响。影响也包括负面的影响。这部分应描述使用本模式后的结果、副作用、与权衡(trade-off)实现:这部分应描述实现该模式、该模式的部分方案、实现该模式的可能技术、或者建议实现模式的方法。示例:简略描绘出如何以编程语言来使用模式。已知应用:业界已知的实现示例。相关模式:这部分包括其他相关模式,以及与其他类似模式的不同。1.11.5-6.3设计模式的分类《设计模式》一书原先把设计模式分为创建型模式、结构型模式、行为型模式,把它们通过授权、聚合、诊断的概念来描述。创建型模式单例模式保证一个类只有一个实例,并提供一个访问它的全局访问点抽象工厂提供一个创建一系列相关或相互依赖对象的接口,而无须指定它们的具体类。工厂方法定义一个用于创建对象的接口,让子类决定实例化哪一个类,FactoryMethod使一个类的实例化延迟到了子类。建造模式将一个复杂对象的构建与他的表示相分离,使得同样的构建过程可以创建不同的表示。原型模式用原型实例指定创建对象的种类,并且通过拷贝这些原型来创建新的对象。迭代器模式提供一个方法顺序访问一个聚合对象的各个元素,而又不需要暴露该对象的内部表示。观察者模式定义对象间一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知自动更新。模板方法定义一个操作中的算法的骨架,而将一些步骤延迟到子类中,TemplateMethod使得子类可以不改变一个算法的结构即可以重定义该算法得某些特定步骤。命令模式将一个请求封装为一个对象,从而使你可以用不同的请求对客户进行参数化,对请求排队和记录请求日志,以及支持可撤销的操作。状态模式允许对象在其内部状态改变时改变他的行为。对象看起来似乎改变了他的类。策略模式定义一系列的算法,把他们一个个封装起来,并使他们可以互相替换,本模式使得算法可以独立于使用它们的客户。职责链模式使多个对象都有机会处理请求,从而避免请求的送发者和接收者之间的耦合关系中介者模式用一个中介对象封装一些列的对象交互。访问者模式表示一个作用于某对象结构中的各元素的操作,它使你可以在不改变各元素类的前提下定义作用于这个元素的新操作。解释器模式给定一个语言,定义他的文法的一个表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子。备忘录模式在不破坏对象的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。结构型模式适配器模式将某个类的接口转换成客户端期望的另一个接口表示。适配器模式可以消除由于接口不匹配所造成的类兼容性问题。桥接模式将一个抽象与实现解耦,以便两者可以独立的变化。组合模式把多个对象组成树状结构来表示局部与整体,这样用户可以一样的对待单个对象和对象的组合。修饰模式向某个对象动态地添加更多的功能。修饰模式是除类继承外另一种扩展功能的方法。外观模式为子系统中的一组接口提供一个一致的界面,外观模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。享元通过共享以便有效的支持大量小颗粒对象。代理为其他对象提供一个代理以控制对这个对象的访问。行为型模式黑板广义的观察者在系统范围内交流信息,允许多位读者和写者。责任链为解除请求的发送者和接收者之间耦合,而使多个对象都有机会处理这个请求。将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它。命令将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持可取消的操作。解释器给定一个语言,定义它的文法的一种表示,并定义一个解释器,该解释器使用该表示来解释语言中的句子。迭代器提供一种方法顺序访问一个聚合对象中各个元素,而又不需暴露该对象的内部表示。中介者包装了一系列对象相互作用的方式,使得这些对象不必相互明显作用,从而使它们可以松散偶合。当某些对象之间的作用发生改变时,不会立即影响其他的一些对象之间的作用,保证这些作用可以彼此独立的变化。备忘录备忘录对象是一个用来存储另外一个对象内部状态的截图的对象。备忘录模式的用意是在不破坏封装的条件下,将一个对象的状态捉住,并外部化,存储起来,从而可以在将来合适的时候把这个对象还原到存储起来的状态。空对象通过提供默认对象来避免空引用。观察者模式在对象间定义一个一对多的联系性,由此当一个对象改变了状态,所有其他相关的对象会被通知并且自动刷新。规格以布尔形式表示的可重绑定的商业逻辑。状态让一个对象在其内部状态改变的时候,其行为也随之改变。状态模式需要对每一个系统可能取得的状态创立一个状态类的子类。当系统的状态变化时,系统便改变所选的子类。策略定义一个算法的系列,将其各个分装,并且使他们有交互性。策略模式使得算法在用户使用的时候能独立的改变。模板方法模板方法模式准备一个抽象类,将部分逻辑以具体方法及具体构造子类的形式实现,然后声明一些抽象方法来迫使子类实现剩余的逻辑。不同的子类可以以不同的方式实现这些抽象方法,从而对剩余的逻辑有不同的实现。先构建一个顶级逻辑框架,而将逻辑的细节留给具体的子类去实现。访问者封装一些施加于某种数据结构元素之上的操作。一旦这些操作需要修改,接受这个操作的数据结构可以保持不变。访问者模式适用于数据结构相对未定的系统,它把数据结构和作用于结构上的操作之间的耦合解脱开,使得操作集合可以相对自由的演化。第七-八课时教学目标工厂模式介绍。1.11.7-8.1工厂方法模式的概述在软件系统中,经常面临着“某个对象”的创建工作,由于需求的变化,这个对象的具体实现经常面临着剧烈的变化,但是它却拥有比较稳定的接口。如何应对这种变化?提供一种封装机制来隔离出“这个易变对象”的变化,从而保持系统中“其它依赖该对象的对象”不随着需求的改变而改变?这就是要说的FactoryMethod模式了。在工厂方法模式中,核心的工厂类不再负责所有产品的创建,而是将具体创建工作交给子类去做。这个核心类仅仅负责给出具体工厂必须实现的接口,而不接触哪一个产品类被实例化这种细节。这使得工厂方法模式可以允许系统在不修改工厂角色的情况下引进新产品。在FactoryMethod模式中,工厂类与产品类往往具有平行的等级结构,它们之间一一对应。1.11.7-8.2为何要使用工厂模式?工厂模式是我们最常用的模式了,著名的Jive论坛,就大量使用了工厂模式,工厂模式在Java程序系统可以说是随处可见。为什么工厂模式是如此常用?因为工厂模式就相当于创建实例对象的new,我们经常要根据类Class生成实例对象,如Aa=newA()工厂模式也是用来创建实例对象的,所以以后new时就要多个心眼,是否可以考虑使用工厂模式,虽然这样做,可能多做一些工作,但会给你系统带来更大的可扩展性和尽量少的修改量。我们以类Sample为例,如果我们要创建Sample的实例对象:Samplesample=newSample();可是,实际情况是,通常我们都要在创建sample实例时做点初始化的工作,比如赋值查询数据库等。首先,我们想到的是,可以使用Sample的构造函数,这样生成实例就写成:Samplesample=newSample(参数);但是,如果创建sample实例时所做的初始化工作不是象赋值这样简单的事,可能是很长一段代码,如果也写入构造函数中,那你的代码很难看了(就需要Refactor重整)。为什么说代码很难看,初学者可能没有这种感觉,我们分析如下,初始化工作如果是很长一段代码,说明要做的工作很多,将很多工作装入一个方法中,相当于将很多鸡蛋放在一个篮子里,是很危险的,这也是有背于Java面向对象的原则,面向对象的封装(Encapsulation)和分派(Delegation)告诉我们,尽量将长的代码分派“切割”成每段,将每段再“封装”起来(减少段和段之间偶合联系性),这样,就会将风险分散,以后如果需要修改,只要更改每段,不会再发生牵一动百的事情。在本例中,首先,我们需要将创建实例的工作与使用实例的工作分开,也就是说,让创建实例所需要的大量初始化工作从Sample的构造函数中分离出去。这时我们就需要Factory工厂模式来生成对象了,不能再用上面简单newSample(参数)。还有,如果Sample有个继承如MySample,按照面向接口编程,我们需要将Sample抽象成一个接口.现在Sample是接口,有两个子类MySample和HisSample.我们要实例化他们时,如下: Samplemysample=newMySample(); Samplehissample=newHisSample();随着项目的深入,Sample可能还会"生出很多儿子出来",那么我们要对这些儿子一个个实例化,更糟糕的是,可能还要对以前的代码进行修改:加入后来生出儿子的实例.这在传统程序中是无法避免的.但如果你一开始就有意识使用了工厂模式,这些麻烦就没有了.工厂方法
你会建立一个专门生产Sample实例的工厂: publicclassFactory { publicstaticSamplecreator(intwhich) { //getClass产生Sample一般可使用动态类装载装入类。 if(which==1) { returnnewSampleA(); } elseif(which==2) { returnnewSampleB(); } } }那么在你的程序中,如果要实例化Sample时.就使用SamplesampleA=Factory.creator(1);这样,在整个就不涉及到Sample的具体子类,达到封装效果,也就减少错误修改的机会,这个原理可以用很通俗的话来比喻:就是具体事情做得越多,越容易犯错误.这每个做过具体工作的人都深有体会,相反,官做得越高,说出的话越抽象越笼统,犯错误可能性就越少.使用工厂方法要注意几个角色,首先你要定义产品接口,如上面的Sample,产品接口下有Sample接口的实现类,如SampleA,其次要有一个factory类,用来生成产品Sample,如下图,最右边是生产的对象Sample:图1.11-7工厂模式示例图1.11.7-8.3例子现在我们考虑一个日志记录的例子(这里我们只是为了说明FactoryMethod模式,实际项目中的日志记录不会这么去做,也要比这复杂一些)。假定我们要设计日志记录的类,支持记录的方法有FileLog和EventLog两种方式。在这里我们先不谈设计模式,那么这个日志记录的类就很好实现了: //日志记录类 publicclassLog { publicvoidWriteEvent() { Console.WriteLine("EventLogSuccess!"); } publicvoidWriteFile() { Console.WriteLine("FileLogSuccess!"); } publicvoidWrite(stringLogType) { switch(LogType.ToLower()) { case"event": WriteEvent(); break; case"file": WriteFile(); break; default: break; } } }这样的程序结构显然不能符合我们的要求,如果我们增加一种新的日志记录的方式DatabaseLog,那就要修改Log类,随着记录方式的变化,switch语句在不断的变化,这样就引起了整个应用程序的不稳定,进一步分析上面的代码,发现对于EventLog和FileLog是两种完全不同的记录方式,它们之间不应该存在必然的联系,而应该把它们分别作为单独的对象来对待。 //EventLog类 publicclassEventLog { publicvoidWrite() { Console.WriteLine("EventLogWriteSuccess!"); } } //FileLog类 publicclassFileLog { publicvoidWrite() { Console.WriteLine("FileLogWriteSuccess!"); }进一步抽象,为它们抽象出一个共同的父类,结构图如下:图1.11-8父类和子类关系图实现代码: //Log类 publicabstractclassLog { publicabstractvoidWrite(); }此时EventLog和FileLog类的代码应该如下: //EventLog类 publicclassEventLog:Log { publicoverridevoidWrite() { Console.WriteLine("EventLogWriteSuccess!"); } } //FileLog类 publicclassFileLog:Log { publicoverridevoidWrite() { Console.WriteLine("FileLogWriteSuccess!"); } }此时我们再看增加新的记录日志方式DatabaseLog的时候,需要做哪些事情?只需要增加一个继承父类Log的子类来实现,而无需再去修改EventLog和FileLog类,这样的设计满足了类之间的层次关系,又很好的符合了面向对象设计中的单一职责原则,每一个类都只负责一件具体的事情。到这里似乎我们的设计很完美了,事实上我们还没有看客户程序如何去调用。在应用程序中,我们要使用某一种日志记录方式,也许会用到如下这样的语句: EventLogeventlog=newEventLog(); eventlog.Write();当日志记录的方式从EventLog变化为FileLog,我们就得修改所有程序代码中出现上面语句的部分,这样的工作量是可想而知的。此时就需要解耦具体的日志记录方式和应用程序。这就要引入FactoryMethod模式了,每一个日志记录的对象就是工厂所生成的产品,既然有两种记录方式,那就需要两个不同的工厂去生产了,代码如下: //EventFactory类 publicclassEventFactory { publicEventLogCreate() { returnnewEventLog(); } } //FileFactory类 publicclassFileFactory { publicFileLogCreate() { returnnewFileLog(); } }这两个工厂和具体的产品之间是平行的结构,并一一对应,并在它们的基础上抽象出一个公用的接口,结构图如下:图1.11-9继承关系结构图实现代码如下: //LogFactory类 publicabstractclassLogFactory { publicabstractLogCreate(); }此时两个具体工厂的代码应该如下: //EventFactory类 publicclassEventFactory:LogFactory { publicoverrideEventLogCreate() { returnnewEventLog(); } } //FileFactory类 publicclassFileFactory:LogFactory { publicoverrideFileLogCreate() { returnnewFileLog(); } }这样通过工厂方法模式我们把上面那对象创建工作封装在了工厂中,此时我们似乎完成了整个FactoryMethod的过程。这样达到了我们应用程序和具体日志记录对象之间解耦的目的了吗?看一下此时客户端程序代码: //App类 publicclassApp { publicstaticvoidMain(string[]args) { LogFactoryfactory=newEventFactory(); Loglog=factory.Create(); log.Write(); } }在客户程序中,我们有效地避免了具体产品对象和应用程序之间的耦合,可是我们也看到,增加了具体工厂对象和应用程序之间的耦合。那这样究竟带来什么好处呢?我们知道,在应用程序中,Log对象的创建是频繁的,在这里我们可以把LogFactoryfactory=newEventFactory();这句话放在一个类模块中,任何需要用到Log对象的地方仍然不变。要是换一种日志记录方式,只要修改一处为:LogFactoryfactory=newFileFactory();其余的任何地方我们都不需要去修改。有人会说那还是修改代码,其实在开发中我们很难避免修改,但是我们可以尽量做到只修改一处。结构图图1.11-10结构图1.11.7-8.4适用性在以下情况下,适用于工厂方法模式:1.当一个类不知道它所必须创建的对象的类的时候。2.当一个类希望由它的子类来指定它所创建的对象的时候。3.当类将创建对象的职责委托给多个帮助子类中的某一个,并且你希望将哪一个帮助子类是代理者这一信息局部化的时候。第九-十课时教学目标观察者模式介绍。1.11.9-10.1观察者模式概述观察者模式(有时又被称为发布/订阅模式)是软件设计模式的一种。在此种模式中,一个目标对象管理所有相依于它的观察者对象,并且在它本身的状态改变时主动发出通知。这通常透过呼叫各观察者所提供的方法来实现。此种模式通常被用来实现事件处理系统。图1.11-11观察者模式结构图1.11.9-10.2参与类别参与本模式的各类别列出如下。成员函数以模拟的方式列出。抽象目标类别此抽象类别提供一个接口让观察者进行增加与删除作业。此类别内有个不公开的观察者集合,并透过下列函数(方法)进行作业。增加:新增观察者到集合内,以追踪目标对象的变化。删除:将已经存在的观察者从删除中移除。通知:利用观察者所提供的更新函数来通知此目标已经产生变化。添附函数包涵了一个观察者对象参数。也许是观察者类别的虚拟函数(即更新函数),或是在非面向对象的设定中所使用的函数指标(更广泛来讲,函数子或是函数对象)。目标类别此类别提供了观察者欲追踪的状态。也利用其源类别(例如前述的抽象目标类别)所提供的方法,来通知所有的观察者其状态已经更新。此类别拥有以下函数。取得状态:回传该目标对象的状态。抽象观察者接口抽象观察者类别是一个必须被实做的抽象类别。这个类别定义了所有观察者都拥有的更新用接口,此接口是用来接收目标类别所发出的更新通知。此类别含有以下函数更新(Update):会被实做的一个抽象(虚拟)函数。观察者类别这个类别含有指向目标类别的参考,以接收来自目标类别的更新状态。此类别含有以下函数更新(Update):是前述抽象函数的实例化。当这个函数被目标对象呼叫时,观察者对象将会呼叫目标对象的取得状态函数,来更新所拥有更新目标的对象信息。每个观察者类别都要做它自己的更新函数,以应对状态更新的情形。当目标对象改变时,会通过呼叫它自己的通知函数来将通知送给每一个观察者对象,这个通知函数则会去呼叫已经增加在集合内的观察者更新函数。通知与更新函数可能会有一些参数,好指明是目前目标对象内的何种改变。这么做将可增进观察者的效率(只更新那些改变部份的状态)。1.11.9-10.3观察者模式实例代码importjava.util.Iterator;importjava.util.Random;importjava.util.Vector;interfaceObserver{ publicabstractvoidnotify(NumberGeneratorgenerator); }abstractclassNumberGenerator{ privateVector<Observer>observers=newVector<Observer>();//存储 publicvoidaddObserver(Observerobserver
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 工伤保险条例岗位笔试模拟试题及答案解析2026年
- 2026年中医耳鼻喉科鼻外伤冷敷热敷护理培训试卷及答案
- 煤矿放震动炮施工安全技术措施培训
- 采煤工作面专用回风巷施工安全技术措施培训
- 消防灭火作业安全操作规程培训
- 港口节能减排现状及措施浅谈
- 洞口地层加固施工安全交底培训
- (2026年)医院老年人绿色通道管理制度
- (2026年)学校食堂从业人员培训考核制度
- 2026年食堂健康管理制度-食堂健康管理制度条例
- DB45T 1914-2018 降真香鉴定方法
- 开学第一课(教学设计)人教版体育四年级上册
- 人教版部编道德与法治一年级上册《全册完整》课件
- 知识点复习提纲 高一统编版2019必修中外历史纲要上册
- 老年痴呆健康教育知识讲座
- 数字化教材与传统教材的比较研究与发展趋势
- 《长征精神》课件
- 除雪设备操作保养规程
- 音乐欣赏(高职)PPT完整全套教学课件
- 设施农业环境工程学(陈)课件
- 2022年辽宁医药职业学院教师招聘考试真题
评论
0/150
提交评论