代理模式
这几天学了Java设计模式的远程代理,两天时间除了上课就是在搞代理模式的远程代理。这篇文章首先介绍代理模式,下篇文章在介绍远程代理。
代理模式:
由于某些原因,客户端不想或不能直接访问一个对象,此时可以通过一个称为“代理”的第三者来实现间接访问。即,给某一个对象提供一个代理,并由代理对象来控制对原对象的访问。
代理模式的结构:
①Subject(抽象主题角色):他声明了真实主题和代理主题的公共接口,客户端通常需要针对抽象主题角色来进行编程。
②Proxy(代理主题角色):他包含了对真实主题的引用,从而可以任何时间操作真实主题。通常,在代理主题角色中还要进行其他的操作,而不仅仅是调用真实主题的操作。因此,在代理主题角色中,往往还添加了新的方法。
③RealSubject(真实主题角色):他定义了代理角色所代表的真实对象,客户端可以通过调用代理主题角色间接的调用真实主题角色中定义的操作。
结构图如图:
例如:向原有信息查询功能的系统中增加身份验证和日志记录功能。
/**
* @description:定义了代理对象和真实对象的公共接口doSearch
*/
public interface Searcher {
public String doSearch(String userId,String keyword);
class Tester{
public static void main(String args[]){
Searcher searcher = new ProxySearcher();
searcher.doSearch("杨过","玉女心经");
}
}
}
/**
* @description:新增加的身份验证功能
*/
public class AccessValidator {
public boolean validate(String userId){
System.out.println("在数据库中验证用户" + userId + "是否为合法用户?");
if (userId.equals("杨过")){
System.out.println(userId + "登录成功");
return true;
}else {
System.out.println(userId + "登录失败");
return false;
}
}
}
/**
* @description:新增加的日志记录功能
*/
public class Logger {
public void log(String userId){
System.out.println("更新数据库,用户 " + userId + "查询次数加1!");
}
}
/**
* @description:真实对象实现了公共接口,实现了公共方法
*/
public class RealSearcher implements Searcher{
@Override
public String doSearch(String userID,String keyword){
System.out.println("用户:" + userID + "使用关键词" + keyword + "查询商务信息!");
return "返回具体内容";
}
}
/**
* @description:代理对象实现了Serach接口,并包含一个真是对象的引用,还有包含有其他的方法
* 最后将其他方法耦合到公共接口方法中,拓展了工作接口中的方法.
*/
public class ProxySearcher implements Searcher {
private RealSearcher realSearcher = new RealSearcher();
private AccessValidator accessValidator;
private Logger logger;
@Override
public String doSearch(String userId, String keyword) {
if (this.validate(userId)){
String result = realSearcher.doSearch(userId,keyword);
this.log(userId);
return result;
}else {
return null;
}
}
public boolean validate(String userId){
accessValidator = new AccessValidator();
return accessValidator.validate(userId);
}
public void log(String userId){
logger = new Logger();
logger.log(userId);
}
}
运行公共接口中的内部类,运行main方法,可以看到main方法使用了公共接口编程方法,并调用代理ProxySearcher()。
/**
* @description:定义了代理对象和真实对象的公共接口doSearch
*/
public interface Searcher {
public String doSearch(String userId,String keyword);
class Tester{
public static void main(String args[]){
Searcher searcher = new ProxySearcher();
searcher.doSearch("杨过","玉女心经");
}
}
}/*
在数据库中验证用户杨过是否为合法用户?
杨过登录成功
用户:杨过使用关键词玉女心经查询商务信息!
更新数据库,用户 杨过查询次数加1!
*/
通过XML配置文件,生成代理实例对象
<?xml version="1.0" encoding="UTF-8" ?>
<configuration>
<classname>net.fuqian.learn.java.大话设计模式.代理模式.简单代理模式.ProxySearcher</classname> //中间那部分为package包名
</configuration>
/**
* @description:XML工具类获取实例对象
*/
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import java.io.File;
public class XMLUtil {
public static Object getBean(){
try{
//创建DOM文档对象
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
Document document = db.parse(new File("src//net//fuqian//learn//java//大话设计模式//代理模式//简单代理模式//config.xml"));
//获取包含类名的文本结点
NodeList n1 = document.getElementsByTagName("classname"); //getElementsByTagName 返回指定标签的内容
Node classNode = n1.item(0).getFirstChild();
String cName = classNode.getNodeValue();
//通过类名生成实例对象并将其返回
Class c = Class.forName(cName);//Class.forName(String classname)生成指定类的class的对象
Object object = c.newInstance(); //调用class对象.newInstance创建一个类的对象
return object;
}catch (Exception e){
e.printStackTrace();
return null;
}
}
static class Tester{
public static void main(String args[]){
Searcher searcher;
searcher = (Searcher)XMLUtil.getBean();
String result = searcher.doSearch("杨过","玉女心经");
}
}
}
调用静态的内部类Tester中的main方法运行,结果和上面一样。可以使用XML配置文件中的参数作为方法调用的参数。因此,可以在不更换客户端代码的情况下,通过更换方法的参数,来改变效果,这在策略模式,工厂模式里更有效
代理模式就是这么简单。下面一篇文章介绍远程代理,跑步回来更新。