《模块化架构》PPT课件.ppt_第1页
《模块化架构》PPT课件.ppt_第2页
《模块化架构》PPT课件.ppt_第3页
《模块化架构》PPT课件.ppt_第4页
《模块化架构》PPT课件.ppt_第5页
已阅读5页,还剩40页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

模块化架构 7 第七 章 操作系统操作系统及其之上的应用程序都是基及其之上的应用程序都是基 于于模块化模块化的开发方式完成的。最终的开发方式完成的。最终产品由产品由 独立组件独立组件组装完成,从而使得异地协作开组装完成,从而使得异地协作开 发可以以相当可靠的方式进行。发可以以相当可靠的方式进行。 随着复复杂度的提高,单个应用也在转随着复复杂度的提高,单个应用也在转 向基于向基于独立开发的块组装独立开发的块组装完成。达到此完成。达到此目目 的的办法就是模块化开发办法就是模块化开发。 随着软件规模的增大以及功能复杂性的提高随着软件规模的增大以及功能复杂性的提高 ,越来越有必要将,越来越有必要将单个应用单个应用拆分为拆分为独立的块独立的块、组组 件件、模块模块或者或者插件插件。每个这样的。每个这样的部件部件都是模块化都是模块化 架构的架构的有机组成单元有机组成单元。每个部件都应该是独立的。每个部件都应该是独立的 ,并提供定义良好的,并提供定义良好的对外接口对外接口供外部调用。符合供外部调用。符合 此类标准的部件也称为模块。此类标准的部件也称为模块。 简单的面向对象编程在某些方面类似于结构化简单的面向对象编程在某些方面类似于结构化 编程确立之前的情况:一个程序由编程确立之前的情况:一个程序由众多的类构成众多的类构成 ,往往任何一个方法都可以调用其他的方法。,往往任何一个方法都可以调用其他的方法。 大型软件的基本构成大型软件的基本构成 模块化程序组成:是由不同模块构成的,而一个模 块是一组类的集合。模块中有些类是public级别的 ,作为供其他模块访问的IAP,同时另外一些类是 private级别的,外部不能访问。 传统小系统开发方式:不分模块进行,人们习惯小 系统开发方式来解决大系统设计,更倾向于保留原 有代码,尽管原有代码往往庞杂且难以维护,但还 能正常运行。 减少模块交叉引用:首先清除不必要的交叉引用关 系,并将OpenIAPs按照逻辑功能进行模块分解。 模块化程序模块化程序 设计清晰设计清晰:模块化架构可以使得设计更加清楚:模块化架构可以使得设计更加清楚 管理方便管理方便:也可以更好地管理模块间的依赖关系:也可以更好地管理模块间的依赖关系 维护灵活维护灵活:在维护方面则体现为更高的灵活性。:在维护方面则体现为更高的灵活性。 不管项目的规模如何,从一开始就不管项目的规模如何,从一开始就使用模块使用模块 化化的思想去进行设计,这才是的思想去进行设计,这才是正道。正道。 模块设计的优点 7.1 7.1 模块化设计的类型模块化设计的类型 最简单模块形式:它完全封闭,不需要对外提供 一些类,因为不需要外部代码来调用其功能。 功能扩展问题,就是说在设计模块的时候要考虑 到其他第三方基于对该是模块进行二次开发的可 能性,也就是说要要支持其他的开发商来根据自 己的实际需求对模块提供功能扩展。第三方开发 商就可以编写相应的API类,且能做到价码与发 布的规范保持一致。有些规范制定者通常还会提 供一个该是规范的默认实现。 利用模块化实现适应性多开发商问题 如果有多个开发商对同一个API提供了多个实 现产品,而这些产品很可能是无法同时使用 。因为不同开发商提供的JAR包在功能的上 有所重复,这样的做的直接后果 就是可能没 有一个产品能够正常运行。最好的还是老老 实实地承认这类API比较特殊,它与现实无关 ,而应该从其当前所在的模块中分离出来。 模块化架构 规范与实现分离:规范与具体实现分离,分别放置在 不同的模块中。可以定义一个模块专用于放置规范 ,需要实现规范的开发商可能会提供一个或者多个 单独的模块,用来实现具体的功能。 接口:在规范所在的模块中,至少会有一个小的“入 口点”,比如说构造函数或者是静态工厂方法,这样 客户端代码就可以通过这样的的入口获取具体的实 现内容。 提供一个独立模块对外口 在模块化系统中,将模块表现为类库的方式 更加直接一些,不需要为“规范”或者“具体实 现”提供特殊语义。只要一个独立模块对外提 供很多接口,然后再加上一、两个工厂类, 就可以用来定义一套“规范”,同时还可以加 上一些文档对其进行说明。 7.2 组件定位和交互 模块化目的非常简单,就是要实现一个程序中 各组成部分的松耦合。希望两个模块是独立的,那 么两个模块彼此就不应该知道相互间存在。 下面例子演示模块调用关系,整个系统最核心 三部分的关系:一个类库用来生成原始单词,一个 业务逻辑层用来扰乱单词,还有一覓用户界面模块 负责将这个单词展示给用户看。 演示模块调用关系(1) Public interface Scrambler Public String scramble(String word); Public interface WordLibrary Public String getWords(); Public interface UI Public void display(); 演示模块调用关系(2) Public abstract class Anagrams extends javax.swing.JFrame implements UI Protected abstract WordLibrary getWordLibrary(); Protected abstract Scrambler getScrambler(); Public void display() Initword(); setVisible(true); 演示模块调用关系(3) Public final class Launcher Private static Class wordLibrary; Private static Class scrambler; Private static Class ui; Private Launcher() Public static void registerWordLibrary(Class libraryClass) wordLibrary=libraryClass; Public static void registerScrambler(Class scramblerClass) Scrambler=scramblerClass; 演示模块调用关系(4) Public static void registerScrambler(Class uiClass) Ui=uiClass; Public static UI Launch() throws Exception WordLibrary w=wordLibrary.newInstance(); Scrambler s=scrambler.newInstance(); Return ui.getConstructor(WordLibrary.class,Scrambler. class).newInstance(w,s); 演示模块调用关系(5) Public class AnsgramsWithConstructor extends Anagrams Private final WordLibrary library; Private final Scrambler scrambler ; Public AnagramsWithConstructor(WordLibrary library,Scrambler scrambler) This.library=library;This.scrambler=scrambler; Override Protected WordLibrary getWordLibrary() Return library; Override Protected Scrambler getScrambler() Return scrambler; 学会用代码来注册配置 学会利用程序代码注册配置系统 减少多次注册:很多实现类要注册到系统中,而 且会调用很多次注册方法,那么系统的启动速 度就会很慢。 利用声明绑定服务:最好不要使用那种直接调用 代码来绑定服务的方式,而是使用一种声明的 方式进行服务绑定,这样就不需要去写具体的 代码,而是以更加说明性的方式来注册。 学会用代码来注册配置(2) 学会用代码来注册配置(3) XML文件的方式对于那些不是很了解整个系统的集成 人员来说是比较好的. Spring框架的解决方案较那种使用属性配置的方案更加 灵活,只不过它看上去仍然要求应用程序的集成人员 要知道相应JavaBean的类名,以便进行装配。采用 这种方案,那么每个模块需要把相应的实现类公开给 那些负责最终集成的人员,所以这些公开的类其实也 就成了API的一部分。 Spring框架提供的解决方案非常有效,已经成为了一种 标准,依赖注入通常都是指Spring提供的这种方案。 使用Annotation的方式来实现注入 在对APIService Public class SimpleScramblerAnnotated extends SimpleScrambler Public SimpleScramblerAnnotated() Service Public class StaticWordLibraryAnnotated extends StaticWordLibrary Public StaticWordLibraryAnnotated() Service (“ui”) Public class AnagramsAnnotated extends AnagramsWithConstructor Autowired Public Anagramsannotated(WordLibrary library,Scrambler scrambler) Super(library,scrambler); 组件注入(1) 一般注入:集成人员只需要选择必要的类库,包括提供 API的类库和提供具体实现的类库,再编写一个相应 的配置文件并且在此基础上启动程序就可以了。 Spring注入:通过对Spring注入方案进行一些扩展,是 可以用做到完全没有配置文件的。 常见组件注入:方案在一般原则上没有很大的区别。都 是通过定义抽象的服务,要求开发方提供具体的服务 实现,然后以注册的方式将服务实现放到缓存池中。 Spring是通过外部操作注入的。 组件注入(2) LOOKUP注入: LOOKUP机制能够准确的部署各种实 现,既不用通过访问类的元数据,也不需要配置文件 ,整个过程只需要调用LOOKUP提供的方法。 要特别说明的是,这样的做会使得程序的静态分 析变得非常困难,根本无法做到通过分析一个程序就 能知道其所有的注入口。每一次动态调用Lookup都 会建立一个服务入口。然后该库就会在运行环境中查 找相关服务,并为可用的具体服务建立缓存池,然后 再根据需求返回具体的服务。 组件注入或服务定位(1) 一些纯粹的技术人员会认为这种解决方案只不过是 一种服务定位的模式。的确如此,对Lookup的 调用看起来就是这样一种模式。 可以很容易地使用一种服务的具体实现来替换另外 一种服务的具体实现,与此同时,不需修改那些 使用服务的代码。 这样对单元测试就非常有用。 组件注入或服务定位(2) Private Lookup.Result libraries=Lookup.getDefault().lookupResul t(Wordibrary.class); Private LookupListener listener=new LookupListener() Public void resultChanged(LookupEvent ev) Initword(); Libraries.addLookupListener(listener); 选择LOOKUP的理由 使用JDK是老版本:只能选择LOOKUP。 基于NETBEANS程序应该具有动态性:NETBEANS可 以在运行是动态添加或移去模块。 Lookup提供了两个API:第三个也是最后一个选择 Lookup而非ServiceLoader的理由,是因为Lookup提 供了两个API:一类API为客户端代码服务,用来查 询已经注册的服务,还有一类API则为开发者服务, 方便他们编写自己的服务池,定义如何注册和获取服 务。 7.3 编写扩展点(1) 所谓的扩展点就是一个抽象服务,其他 模块可以通过实现该是服务来为原来的基 础模块提供功能扩展。 核心模块中声明一个扩展接口,以API 的形式公布出去,这表示这个接口对外公 开,允许外部通过实现该接口来扩展功能 。Pack.age org.apidesign.extensionpoint.api; Public interface TipOfTheDay Public String sayHello(); 7.3 编写扩展点 Collection all=lookup.getDefault().lookupALL(TipOfTheDay.class); List arr=new ArrayList(all);Collections.shuffle(arr); String msg;String title;Int type; If (arr.isEmpty() Msg=”I do not what to say!”; Title=”No vprovider registered”; Type=JoptionPane.WARNING_MESSAGE; else Msg=arr.get(0).sayHello(); Title=”Selected from “+arr.size()+”providers”; Type=JoptionPane.INFORMATION_MESSAGE; 7.3 编写扩展点(3) 基于Lookup机制可以很简单地实现各种服 务的注册,并让其他模块以扩展卡点的方式来注 入新的扩展功能以加强系统功能。 Package rg.apidesign.extensionpoint.impl2; Import org.apidesign.extensionpoint.api.TipOfTheDay Public class HelloWorld implements TipOfTheDay Public String sayHello() Return “Hello World!”; 7.3 编写扩展点(4) 只要按照Java标准版本指定的格式将功能注册到系 统中即可:编写一个文本文件 org.apidesign.extensionpoint.api.TipOfTheDay放在 META-INF/service目录下面,文件只包含如下所示 的一行内容: org.apidesign.extensionpoint.impl2.HelloWorld 这样的扩展点机制,可以将模块进行关联。 7.4循环依赖的必要性(1) 有些系统在运行时是允许循环依赖的,特别是对那些 遗留代码更是如此。模块和模块之间复杂的引用关系, 不是所人都喜欢这种一刀切的处理方式。 对于一个容器 来讲,其规则定义得越严格,其用户基于该容器进行程 序开发的系统架构就越清晰。不允许循环依赖正是 NetBeans对付那种面向对象的。对于新开发的代码,一 定要避免出现循环依赖。 NetBeans的Lookup机制或者是Java6引入的 ServiceLoader机制,作为组件注入机制都可以避免在编 译时的循环依赖,从而做到模块间的分离。 7.4循环依赖的必要性(2) Package org.apidesign.cycles.array; Import java.io.IoException; Import java.io.outputStream; Import org.apidesign.cycles.crypt.Encryptor; Public class MutableArray Private byte arr; Public MutableArray(byte arr) This.arr=arr; Public void xor(byte b) For (int i=0;iarr.length;i+) arri=b; Public void and(byte b) For (int i=0;iarr.length;i+ arri 7.4循环依赖的必要性(2) Public void or(byte b ) For (int i=0;iarr.length;i+) arri =b; Public void encrypt(OutputSream os) throws IoException Encryptor en=new Encryptor(); Byte clone =(byte) arr.clone(); En.encode(clone); Os.write(clone); Package org.apidesign.cycles.crypt; Import final class Encryptor Public void encode(byte arr) MutableArray m=new MutableArray(arr); m.xor(byte)ox3d); 7.4循环依赖的必要性(3) 可以看到有两个独立的包,它们之间存在着相互调用的 关系。 Encryptor,不需要进行修改,因为不管是编译还是具体 运行的时候,它都是依赖于MutableArray所地的模块, 可以直接使用MutableArray类。但MutableArray类在编 译的时候不能直接使用Encryptor类了。 分成两个模块的应用 Lookup MutableArray Encryptor DoEncode DoEncodelmpl 查找DoEncode的实现 实现 通过META-INF/SERVERS注册 DoEncodelmpl 调用 7.5 满城尽是Lookup 优点只有真正Lookup机制的时候才能体会得到。与 JDK提供的ServiceLoader相比,NetBeans提供的Lookup 可以有多个实例,每个实例都是有自己的缓存池。 “Lookup就象一个缓存池,对象可以随意进出“。 Public interface ExtIcon extends Icon ,Lookup.Provider Public void paintIcon(Component c,Graphics g,int x ,int y); Public int getIconWidth(); Public int getIconHeight(); Public Lookup getlookup(); 满城尽是Lookup(2) ExtIcon这个接口继承了lookup.Provider,这就表示这个 类可以提供一个自己的lookup,这样就可以提供一个额外 的功能,或者临时标记图标使之看上去具有某些功能。 Public static Image toImage(ExtIcon icon) Image img=icon.getLookup().lookup(Image.class); If (img!=null) Return img ; bufferedImage buf=new BufferedImage( icon.getIconWidth(),icon.getIconHeight(), bufferedImage.TYPE_INT_RGB); icon.paintIcon(null,buf.getGraphics(),0,); return buf; 满城尽是Lookup(3) 每个ExtIcon的子类都可以自行决定是否有更加优化的方 式将自己转成一个Image对象,如果没有这种优化方式, 则将图标输出到默认的BufferedImage对象中。这个例子 展示如何以一种静态的方式对一个接口进行功能方便的 增强,因为是否能转化Image对象这个固定的。 Public interface Modified Public void save() throws IoException; Public void discard() throws IoException; 满城尽是Lookup(4) Modified的实现可以随意讲出 ExtIcon提供的Lookup池 ,这样就可以让相应的监听者知道其状态了。 Private Abstractlookup lookup; Private InstanceContent ic; ModifiableIcon() Ic=new InstanceContent(); Lookup=new AbstractLookup(ic); Public Lookup getLookup() Return lookup; Public void markModified() If(lookup.lookup(ModifiedImpl.class)=null) Ic.add(new ModifiedImpl(); Private final class ModifiedImpl implements Modified Public void save() throws IoException Public void diacard() throws IoException / discard changes 满城尽是Lookup(4) 通过调用这个ModifiedImpl对象的 save的方法来完成保 存操作,待操作完成后,就可以从 Lookup中移除相应的 ModifiedImpl对象。这样外部代码,就可以通过Lookup 机制来执行各种操作,如保存和撒销,还可以对Lookup 中的内容进行监听。 对于这个场景,Lookup就好像一个事件总线。这样的 事件总线类似于一个对象可以进出的池,可以用来处理 用户界面上的各种事件。接下来,就使用Listener机制来 监听Lookup的变化,先注Listener册到Lookup,然后就 开始监听相应对象的变化。 满城尽是Lookup(5) 在API中需要判断该是图标到底是什么。尽管设计这个查 询方法的第一目标是简单易用,但可扩展性也很重要, 只有具有了良好的扩展性,外部才能够利用模块的扩展 功能将相关内容注入到API中. Public class CatQuery Private CatQuery() Public static Boolean isCat(EtIcon icon) For (catQueryImplementation impl: Lookup.getDefault().lookupALL(CatQueryImplementation.class) Boolean res =impl.isCat(icon); If (res!=null) Return res; 满城尽是Lookup(6) For (catQueryImplementation impl : icon.getLookup()lookupALL(CatQueryImplementation.cl ass) Boolean res=impl.isCat(cion); If (res!=null) Return res; Return false; Public abstract class CatQueryImplementation Protected CatQueryImplementation() Protected abstract Boolean isCat(ExtIcon icon); 满城尽是Lookup(7) 每一个扩展都注册一个CatQueryImplementation,并将 其注入系统。 这个例子演示了组件注入的使用。这个API对外开放,允 许外部将相应的实现注册进来以增强系统的功能。 在NetBeans中,Lokkup 的优点在于它在佤范围内使用 Adaptable模式,从而以一致的方式来管理各种内容注入 。 7.6 Lookup 的滥用(1) Lookup 自身有趣的动态特性注定它是一个很受人关 注的功能,很多开发人员会在不同的场合使用它,甚至 在一些有

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论