十一、代理模式
1、概念
代理模式为另一个对象提供一个替身或占位符以控制对这个对象的访问。
使用代理模式创建代表(representative)对象,让代表对象控制某对象的访问,被代理的对象可以是远程的对象、创建开销大的对象或需要安全控制的对象。
2、类图
- 首先是Subject,它为RealSubject和Proxy提供接口。通过实现统一接口,Proxy在RealSubject出现的地方取代它
- RealSubject是真正做事的对象,它是被proxy代理和控制访问的对象
- 客户和RealSubject的交互都必须通过Proxy
- Proxy也控制了对RealSubject的访问,在某些情况下,我们可能需要这样的控制。这些情况包括被代理的对象可以是远程的对象、创建开销大的对象或需要安全控制的对象。
3、远程代理
远程代理可以作为另一个JVM上对象的本地代表。调用代理的方法,会被代理利用网络转发到远程执行,并且结果会通过网络返回给代理,再由代理将结果转给客户。
代码:书441页
4、虚拟代理
虚拟代理作为创建开销大的对象代表。虚拟代理经常知道我们真正需要一个对象的时候才创建它。当对象在创建前和创建中时,由虚拟代理来扮演对象的替身。对象创建之后,代理就会将请求直接委托给对象。
代码:书465
5、动态代理
Java在java.lang.reflect包中有自己的代理支持,利用这个包你可以在运行时动态地的创建一个代理类,实现一个或多个接口,并将方法的调用转发到你所指定的类。
- 动态代理之所以叫动态代理,是因为运行时才将它的类创建出来。代码开始执行时,还没有proxy类,它是根据需要从你传入的接口集通过静态方法Proxy.newProxyInstance()在运行时动态创建的
可以使用动态代理的方式实现保护代理是的不同权限的类可以访问不同接口
类图:
例子
实现NonOwnerInvocationHandler,它允许其他类调用PersonBean的setHotOrNotRating和get方法,不允许调用set方法。
//reflect包含InvocationHandler,所有调用处理器都需要实现InvocationHandler
import java.lang.reflect.*;
public class NonOwnerInvocationHandler implements InvocationHandler{
PersonBean person;
//将PersonBean对象通过构造器传递给引用
public NonOwnerInvocationHandler(PersonBean person){
this.person = person;
}
//每次proxy的方法被调用,就会导致proxy调用此方法
public Object invoke(Object proxy, Method method, Object[] args)
throw IllegalAccessException{
//允许调用setHotOrNotRating和get方法,不允许调用set方法以及其他方法
try{
if (method.getName().startsWith("get")){
return method.invoke(preson, args);
} else if ("setHotOrNotRating".equals(method.getName())){
return method.invoke(preson, args);
} else if(method.getName().startsWith("set")){
throw new IllegalAccessException();
}
} catch(InvocationTargetException e){
//如果真正的主题抛出异常的话,就会执行到这里
e.printStackTrace();
}
return null;
}
}
//创建动态代理类
//此方法需要一个person对象作为参数,然后返回它的代理
//因为代理和主题有相同的接口,所以返回一个PersonBean
PersonBean getOwnerProxy(PersonBean person){
return (PersonBean) Proxy.newProxyInstance(
person.getClass().getClassLoader(),
person.getClass().getInterface(),
new OwnerInvocationHandler(person));
}
//获取非本人代理
PersonBean getNonOwnerProxy(PersonBean person){
return (PersonBean) Proxy.newProxyInstance(
person.getClass().getClassLoader(),
person.getClass().getInterface(),
new NonOwnerInvocationHandler(person));
}
6、要点
- 代理模式为另一个对象提供代表,以便控制客户对对象的访问,管理访问的方式有许多种
- 远程代理管理客户和远程对象之间的交互
- 虚拟代理控制访问实例化开销大的对象
- 保护代理基于调用者控制对对象方法的访问
- 代理模式有许多变体,例如:缓存代理、同步代理、防火墙代理和写入时复制代理
- 代理在结构上类似装饰者,但是目的不同。装饰者模式为对象加上行为,而代理则是控制范围
- Java内置的代理支持,可以根据需要建立动态代理,并将所有调用分配到所选的处理器
- 就和其他的包装者(Wrapper)一样,代理会造成你的设计中类的数目的增加
十二、复合模式
模式通常被一起使用,并被组合在同一个设计解决方案中。复合模式在一个解决方案中结合两个或者多个模型,以解决一般或重复发生的问题。
1、MVC内的模式
MVC是指:
- V:视图。用来呈现模型。视图通常直接从模型中取得它需要显示的状态和数据
- C:控制器。取得用户的输入并解读其对模型的意思。同也是可以改变视图的状态。
- M:模型。模型持有所有数据、状态和程序逻辑。模型没有注意到视图和控制器,虽然它提供了操作和检索状态的接口,并发送状态改变通知给观察者。
MVC中的设计模式:
- 模型利用“观察者”让控制器和视图可以随最新的状态改变而更新
- 视图和控制器则实现了“策略模型”。控制器是视图的行为,如果希望有不同的行为,可以直接换一个控制器
- 视图内部使用组合模式来管理窗口、按钮以及其他显示组件
2、要点
- MVC是复合模式,结合了观察者模式、策略模式和组合模式
- 模型使用观察者模式,以便观察者更新,同时保持两者之间解耦
- 控制器是视图的策略,视图可以使用不同的控制器实现,得到不同的行为
- 视图使用组合模式实现用户界面,用户界面通常组合了嵌套的组件,像面板、框架和按钮
- 这些模式携手合作,把MVC模型的三层解耦,这样可以保持设计干净又有弹性
- 适配器模式用来将新的模型是配成已有的视图和控制器
- Model 2是MVC在Web上的应用
- 在Model 2中,控制器实现成Servlet,而JSP/HTML实现视图
十三、真实世界的模式
1、什么是模式
模式是在某情景(context)下,针对某问题的某种解决方案。
-
情景就是应用某种模式的情况。这应该是不断出现的情况
-
问题就是你想在某种情境下达到的目标,但也可以是某种情境下的约束
-
解决方案就是你所追求的,一个通用的设计、用来解决约束,达到目标
-
模式必须应用于一个重复出现的问题
-
过度使用设计模式可能导致代码被过度工程化。应该总是用最简单的解决方案完成工作,并在真正需要模式的地方才使用它
2、模式分类
3、要点
-
让设计模式自然而然地出现在你的设计中,而不是为了使用而使用
-
设计模式并非僵化的教条;你可以依据自己的需要采用或者调整
-
总是使用满足需要的最简单的解决方案,不管它用不用模式
-
学习设计模式的类目,可以帮助熟悉这些模式以及他们之间的关系
-
模式的分类是将模式分成不同的族群
-
你所遇到的大多数模式都是现有模式的变体,而非新的模式
-
模式的最大好处是让团队拥有共享词汇
要采用或者调整**
-
总是使用满足需要的最简单的解决方案,不管它用不用模式
-
学习设计模式的类目,可以帮助熟悉这些模式以及他们之间的关系
-
模式的分类是将模式分成不同的族群
-
你所遇到的大多数模式都是现有模式的变体,而非新的模式
-
模式的最大好处是让团队拥有共享词汇