Java软件体系结构设计模式之结构模式 知识点摘录

JavaSE 专栏收录该内容
13 篇文章 0 订阅

       以下知识点摘录自:《Java软件体系结构设计模式标准指南》一书。其中可能包含本人的一些感悟。

       Java软件体系结构设计模式之结构模式(11种)

       结构模式主要用来:

1)处理把责任委托给其他对象的对象。这样一来就会引入一种耦合度低的分层体系结构;

2)在不同情况下方便对象间的通信。比如说某个对象通过通常的方式无法访问,或者由于接口不兼容导致某个对象不可用时;

3)提供了组织一个聚合对象的方式,从而使其完整地被创建;并且结构模式还提供了及时回收系统资源的方式。


(一)装饰器

       描述:不是通过继承方式而是以对客户端透明的方式扩展一个对象的功能。

       1)装饰器模式用于动态地扩展一个对象的功能,而不需要改变原始的类代码或使用继承。这一点是通过在一个实际对象的外围创建一个被称为装饰器的封装对象来做到的。

       2)装饰器模式建议生成一个包围在一个对象外面的封装类,通过对象组合而不是继承来实现功能的扩展。

       3)装饰器对象必须提供与它所封装的对象完全相同的接口。当客户对象创建了一个装饰器的实例之后,它们将调用完全一样的接口,以与原始对象完全相同的方式来跟装饰器对象进行交互。

       4)一个装饰器对象可以包含另一个装饰器对象,并将调用转达给它。使用这种方法,新的装饰器,即新的功能就可以通过封装一个已有的装饰器对象来实现。


(二)适配器

       描述:允许把一个类的接口转换成客户端希望的另一个接口。这样可以让具有不同接口的多个类一起工作。

       1)一般说来,一个类的客户对象通过类提供的接口来访问它的服务。有些时候,一个类可以提供客户对象需要的功能,但它的接口却不同于客户对象的期望。这种情况的出现可能有多种原因,比如已有的接口太过详细,或者还不够详细,又或者这些接口使用的术语与客户对象所寻求的有所不同。

       在这样的情况下,已有的接口就需要被转换为客户对象所期望的另一个接口,以保留已有类的可重用性。没有这样的转换过程,客户对象将不能够使用该类提供的服务。这一点可以通过使用适配器模式来作用。

       2)适配器模式建议在接口不相容的对象的周围定义一个封装类。这个封装类的对象就称为适配器,而它所封装的对象称为一个适配源。适配器提供客户所期望的接口。适配器的接口实现将客户对象的调用转换为对适配源类接口的调用。

       以上讨论中使用的术语“接口”:不是指Java编程语言中的接口概念,虽然一个类的接口可以使用Java接口来声明;也不是指由Windows和GUI控件组成的典型GUI应用当中的用户界面;而是指一个类对外显示的编程接口,这些接口将提供给其他类使用。例如,如果一个类被设计为一个抽象类或Java接口的形式,它所声明的方法集就构成了这个类的接口。

       3)适配器:类适配器和对象适配器。

       4)类适配器被设计为适配源类的一个子类的形式。除了继承自适配源类外,适配器类还实现客户对象所期望的接口。当客户对象调用一个适配器方法的时候,适配器在内部调用它继承来的一个适配器源方法。

       5)对象适配器:一个对象适配器拥有适配源对象的一个引用。与类适配器相似,对象适配器也实现客户对象期望的接口。当客户对象调用一个对象适配器方法的时候,对象适配器将通过它拥有的适配源实例的引用调用一个合适的适配源方法。

       在Java应用当中:使用对象适配器,不能对使用protected访问标识符声明的方法进行适配,除非将适配器设计在与适配源相同的包中。(因为这样做的话,适配器才能访问到适配源中protected访问标识符声明的方法。)


(三)责任链

       描述:避免一个请求的发送对象和接收对象的互相耦合。允许一个发送对象把它的请求传递给一串对象(对象链),而且不必知道哪个对象最终将处理这个请求。

       1)责任链(CoR)模式建议在发出请求的对象和该请求的潜在处理对象集之间建立一种低耦合的关联关系。

       2)当存在多于一个对象可以处理或完成客户的请求的时候,CoR模式建议以某种顺序的次序为其中的每个对象提供处理客户的请求的机会。在这种情况下使用CoR模式,就可以将所有这些潜在的处理对象安排为一种链的形式,链当中的每个对象都拥有一个指向下一个对象的指针。链当中的第一个对象接受客户的请求,并且做出对请求进行处理或者将请求继续传给下一个对象的决定。这样,客户的请求就会顺次地从链当中的一个对象流向另一对象,直至某个对象对它进行处理,或者直到请求到达链的末端而没有得到处理。


(四)外观

        描述:为一个由类组成的子系统提供了一个高层接口,使得这个子系统更易使用。

        1)外观模式用来处理子系统。一个子系统包含多个类,它们协同合作提供一系列的相关特性(功能)。

        2)外观也是一个类,它把客户对象所需要的子系统的功能简化到简单的接口上。有了外观对象,客户就不需要和子系统中具体完成某个功能的类直接交互,而是简单地调用外观对象所提供的接口。外观对象把所有子系统的功能接管过来,客户对象和外观对象打交道,外观对象去调用具体的功能。

        3)在使用外观模式时,下面是一些需要注意的问题:

        3.1)外观类不提供超出原来子系统的其他额外功能;3.2)不要从外观类的方法里返回内部类的引用。

        4)外观模式的目的在于提供一种高层次的接口。所以外观类的接口方法最好是一种综合的商业事务层次的方法,而不是原来的个别低层次方法的简单包装。


(五)代理

        描述:允许一个独立的对象被用作一个替代者以提供对一个对象的受控访问,而通常方法下这个对象是不可访问的。

        1)有时候,客户对象可能无法以正常的方式去直接访问服务提供者对象(又称做目标对象)。这样的情况下,我们可以使用代理模式,这时客户对象不是直接去访问目标对象,而是通过一个代理对象去访问。这个代理对象可以允许不同的客户对象以一种更为普通和直接的方式来间接访问到目标对象。

        2)代理对象和目标对象有同样的调用接口,它代替客户去和目标对象打交道,并负责处理和目标对象之间交流上的特别细节。这样做的好处就是,客户对象不需要满足目标对象的特别需要就可以轻松地访问它所提供地服务。客户对象调用代理的某个方法,代理对象随即把这些调用转发给目标对象。因为代理对象和目标对象的接口是一样的,客户对象可能根本不需要知道自己实际上是在和一个代理打交道。所有原来不方便的地方,不论是因为目标对象是一个远程对象,还是因为目标对象尚未初始化,或者是目标对象需要特别的认证,这些问题统统由代理对象自己去设法解决。换句话说,代理对象就好像是在客户对象和(一个遥不可及的)目标对象之间的一个透明通道。

        3)在不同的环境下需要不同特性的代理对象。

        4)所有的代理对象都有下面两种特性:1. 它是客户对象和目标对象之间的一个中;2. 它接受客户对象的请求,并把它转发给目标对象。

        5)其中,在Java中,远程方法调用(RMI)概念就大量地使用了远程代理模式。

        RMI允许客户对象访问远程对象,就好像它们都在本地一样。

        一般来说,客户对象是无法用普通方式来直接调用远程对象的方法的。


(六)桥接

       描述:允许一个抽象接口和它的实现相分离。这样减少了两者的一来关系,允许两者可以被独立修改。

       1)桥接模式进一步把一个抽象体(abstraction)的接口和实现分离开来。在这里,抽象体指的是把对象的和某种具体用途相关的属性和行为分离出来的表现形式。从这个意义上来说,一个对象是一系列抽象体的集合,其中每一个抽象体只包含该项功能的相关属性和行为。彼此之间没有相互干扰。

       一个抽象体的方法(行为)可以有一个或多个实现方式。在具体实现上,抽象体可以被定义为一个接口,然后有一个或多个实例类来实现它。


(七)虚代理

       描述:以对对象的客户端对象保持透明的方式,延迟一个对象的创建,直到这个对象被真正需要创建时。虚代理模式能简化这种机制。

       1)虚代理模式是一种节省内存的技术,以便确保对象只有在被用到的时候才得到创建,尤其是这样的对象创建需要大量的内存消耗或者其他资源。

       2)使用虚代理模式后,我们可以创建一个和原有应用程序对象具有同样接口的对象。不同的客户对象可以创建这个虚代理的对象。虚代理的内部有一个应用指向真正的应用程序对象。但是这个代理并不会在一开始就自动创建这个应用程序对象。只有当客户调用的一个具体方法需要实际的应用程序对象做出响应的时候,虚代理才会创建这个对象。

       如果实际的对象已经创建了,虚代理把调用转发给这个对象。

       如果实际对象还没被创建,那么虚代理:1.创建实际的对象;2.把这个对象保存在一个内部的引用中;3.把调用转发给这个对象。


(八)审计代理

       描述:当有需要执行一些附加的操作时,比如在一个对象的方法被调用前后记录日志与计账,这个模式建议把附加功能封装在一个独立的对象中。

       1)当客户程序需要在调用服务提供者对象的方法之前或之后执行一些类似于日志或计数的额外操作时,就可以使用计数代理模式。

       2)计数代理模式并不是把这些额外操作的代码直接添加进服务提供者的实现中,而是把它们封装在一个单独的对象里,这个对象就叫计数代理。

       3)一个好的设计意味着每个对象只关注于它自身的功能。换句话说,一个理想的对象不该做任何其他无关的事情。

       4)一个计数代理具有和它的服务提供者对象同样的调用接口。客户程序不是直接调用服务提供者对象的方法,而是调用计数代理的方法。代理负责执行如日志或计数的操作,并把方法传递给真正的服务提供者对象。


(九)聚合强制器

       描述:这个模式建议当一个聚合对象被实例化时,代表组成对象的成员变量也必须被实例化。换句话说,只要一个聚合对象被实例化时它必须被完全实例化。

       1)有时候,一个对象会包含其他的对象作为它的各种成分。这种对象作为其他对象的一个集合称为聚合对象。

       2)聚合强制器模式旨在确认,当一个聚合对象被创建的时候,它必须是被完整创建的。这就意味着,当实例化一个聚合对象时,它的那些代表各个部分对象的成员变量也必须被全部初识化。这样一来,一个聚合对象总是被完整创建的,要么就压根儿不被创建出来。

       3)有两种聚合关系,我们成为集合体和组合体。不论是哪种情形,聚合对象总是包含若干个成分对象。

       4)在集合体中,聚合对象的各个成分即使离开了聚合对象还是有意义的。而组合体就要更加严格一些,组合体的各个成分如果没有聚合对象的存在是没有意义的。

       5)代表成分对象的成员变量可以在创建聚合对象的时候就初始化(称为早期初始化)或者在这个变量要被使用的时候再初始化。

       6)在Java里,把一个成员变量声明为final就意味着它必须在构造函数里被初始化(读者认为:当然也可以在声明成员变量的时候就同时进行初始化,这样就不需要在构造函数中初始化了。如果声明了final成员变量却没有初识化,就必须在所在类中的构造方法中进行初始化)。如果一个类没有在构造方法里全部初始化它的final成员变量,编译器将会给出错误。

       7)在Java中使用final修饰符对聚合对象中的成员对象进行修饰,可以确保在创建聚合对象后,聚合对象的各个部分对象成员也全部被初始化。这样一来,这个聚合对象就算是被完整的创建。

       8)有时,聚合对象内可能包含很多大规模的复杂成分对象。这时候,在创建聚合对象时,就把这些成分对象全部初始化可能就会非常耗时耗力。在这种情况下,可以使用虚代理模式(Virtual Proxy)为每一个成分对象都设计一个代理(虚代理模式在上面已经提到过了哦,忘了怎么回事,翻翻前面看看)。在创建聚合对象时,只需要先初始化这些代理对象即可。


(十)显式对象释放

       描述:这个模式建议当一个对象位于作用域以外时,由它绑定的系统资源也必须及时地被释放。

       1)显式对象释放模式就是说,当一个对象不再需要的时候,它所使用的外部资源应当被主动、及时地释放掉。

       2)Java语言提供以下两种方式来主动地释放外部资源:finalize() 方法;finally语句。

       3)Java虚拟机(JVM)负责在一个对象离开其作用域之后自动回收该对象占用的内存空间。这个过程称为垃圾回收。

       4)当垃圾回收过程运行的时候,在回收一个对象之前,Java运行时系统会调用对象的finalize()方法。所有必需的释放任何外部系统资源的动作,比如关闭文件或者断开套接字都要实现在这个方法里面。finalize()方法必须声明为: protected void finalize() throws Throwable。

       5)Java的finally代码块,在这里可以实现任何需要的释放外部资源的显式动作。和finalize()方法不同的是,finally代码块不依赖于垃圾回收过程,而是用户工作线程执行的一部分。在finally代码块里执行资源释放会更加可靠,因为这些代码肯定会得到执行,即使发生了未曾预料的运行时异常也不例外。


(十一)对象缓存器

       描述:这个模式把针对一个对象的方法调用存放在一个库中。当多个客户端对象调用同一方法时,结果被从库中取出返回给客户端对象,而并不去访问实际对象。这么做主要是为了获得一个更快的响应时间。


展开阅读全文
  • 0
    点赞
  • 0
    评论
  • 1
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

相关推荐
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值