设计模式之代理模式

 

一:代理模式

在代理模式(Proxy Pattern)中,一个类代表另一个类的功能。这种类型的设计模式属于结构型模式。

在代理模式中,我们创建具有现有对象的对象,以便向外界提供功能接口。

二:应用场景

如果需要在已有代码的基础上扩展功能,比如日志记录,性能统计,事务管理,直接在现有代码中添加代码, 会导致职责不够单一, 代码复用性不好,不方便后期维护,此时需要考虑采用代理模式

三:jdk静态代理(继承的方式)

  • 核心作用:

通过代理,控制对对象的访问可以在调用目标标方法之前做一些其他的事情,增强目标类的业务方法。

  • 原则:
  1. 代理类和委托类实现同一个接口,并且代理类继承自委托类
  2. 代理类增强委托类的行为
  • 缺点:

代理类和委托类都实现同一接口,如果增加接口方法,委托类和代理礼物i都要维护

  1. 创建一个接口及委托类
public interface Moveable {
	void move();
}

public class Car implements Moveable{

	@Override
	public void move() {
		try {
			System.out.println("汽车在移动中...");
			Thread.sleep(new Random().nextInt(2000));
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
}

2.继承的方式创建一个代理类,增加日志的功能

public class CarTimeProxy extends Car{

	@Override
	public void move() {
		//记录一个开始时间
		long startTime=System.currentTimeMillis();
		System.out.println("汽车开始移动...");
		super.move();
		//记录一个结束时间
		long endTime=System.currentTimeMillis();
		System.out.println("结束移动,总耗时:"+(endTime-startTime)+"毫秒!");
	}
	
}

四:jdk静态代理(实现的方式)

  •  创建一个接口
public interface Moveable {
	void move();
}
  • 创建实现该接口的委托类
public class Car implements Moveable{

	@Override
	public void move() {
		try {
			System.out.println("汽车在移动中...");
			Thread.sleep(new Random().nextInt(2000));
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
}
  • 通过实现的方式创建实现类
public class CarTimeProxy implements Moveable{
	private Moveable moveable;
	public CarTimeProxy(Moveable moveable){
		this.moveable=moveable;
	}
	
	@Override
	public void move() {
		//记录一个开始时间
		long startTime=System.currentTimeMillis();
		System.out.println("汽车开始移动...");
		moveable.move();
		//记录一个结束时间
		long endTime=System.currentTimeMillis();
		System.out.println("结束移动,总耗时:"+(endTime-startTime)+"毫秒!");
	}
}
  •  缺点:不管是继承还是实现都需要一个明确的接口

五:Jdk动态代理(运行的时候,动态生成代理)

  • 创建一个接口
public interface Flyable {
	void fly();
}
  • 创建该接口的实现类
public class Aircraft implements Flyable{

	@Override
	public void fly() {
		System.out.println("飞机在飞...");
	}
	
}
  •  创建代理类,实现InvocationHandler接口,重写invoke方法;通过method参数.invoke() 可以执行到被代理类的本身方法
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

public class LogProxy implements InvocationHandler{
	/**
	 * 初始化被代理的对象
	 */
	private Object obj;
	/**
	 * 通过构造器给被代理的对象赋值
	 * @param obj
	 */
	public LogProxy(Object obj){
		this.obj=obj;
	}
	/**
	 * proxy 代理对象
	 * method 被代理的方法
	 * args  被调用方法的实参列表
	 * 返回 方法执行的结果
	 * 
	 */
	@Override
	public Object invoke(Object proxy, Method method, Object[] args)
			throws Throwable {
		System.out.println("日志开始...");
		method.invoke(obj, args);
		System.out.println("日志结束...");
		return null;
	}
	
}
  •  获取代理对象 Proxy.newProxyInstance(类加载器,类的接口集合,InvocationHandler的实现类对象)
import java.lang.reflect.Proxy;

/**
 * jdk动态代理     限制    被代理的类必须是实现了接口的类,如果这个类没有实现接口,则这个类一定不能被代理
 * 
 * 1)写一个普通的java类,实现InvocationHandler接口,重写invoke方法。
 * 2)通过method参数.invoke() 可以执行到被代理类的本身方法。
 * 3)获取代理对象 Proxy.newProxyInstance(类加载器,类的接口集合,InvocationHandler的实现类对象)
 * 
 * 
 * 
 * 
 * @author Administrator
 *
 */
public class Test {
	public static void main(String[] args) {		
		//代理飞机
		Flyable aircraft=(Flyable) Proxy.newProxyInstance(Aircraft.class.getClassLoader(), 
				Aircraft.class.getInterfaces(), new LogProxy(new Aircraft()));
		aircraft.fly();
		
	}
}

 六:Cglib实现动态代理

  • Cglib功能更加强大,不必要求委托类必须有接口,创建一个普通类即可
public class Aircraft{

	public void fly() {
		System.out.println("飞机在飞...");
	}
	
}
  • 需要先倒入Cglib的jar
  • 创建代理类实现methodInterceptor的接口,重写intercept方法,通过proxy.invokeSuper(obj, args)可以调用到被代理类的本身方法,还需要在代理类中写一个获取代理对象的方法 
  • Enhancer允许为非接口类型创建一个代理对象,Enhancer动态创建了给定类型的子类但是拦截了所有方法,和jdk的动态代理不同,不管目标类是否有接口都能正常工作,被代理对象不能有final修饰
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

public class LogProxy implements MethodInterceptor{

	/**
	 * 获取一个代理对象
	 * @return
	 */
	public Object getProxy(Class clazz){
		//产生代理对象的对象
		Enhancer enhancer=new Enhancer();
		//设置被代理类的反射模板
		enhancer.setSuperclass(clazz);
		//设置回滚函数
		enhancer.setCallback(this);
		//返回代理对象
		return enhancer.create();
	}
	
	/**
	 * obj  被代理的对象
	 * method 被代理的方法
	 * args 调用方法的实参列表
	 * proxy 代理对象
	 */
	@Override
	public Object intercept(Object obj, Method method, Object[] args,
			MethodProxy proxy) throws Throwable {
		System.out.println("日志开始...");
		// proxy.invokeSuper(被代理的对象,实参列表)
		proxy.invokeSuper(obj, args);
		System.out.println("日志结束...");
		return null;
	}
	
}
  • 调用代理
public class Test {
	public static void main(String[] args) {	
		Aircraft aircraft=(Aircraft) new LogProxy().getProxy(Aircraft.class);
		aircraft.fly();
	}
}
基于html+python+Apriori 算法、SVD(奇异值分解)的电影推荐算法+源码+项目文档+算法解析+数据集,适合毕业设计、课程设计、项目开发。项目源码已经过严格测试,可以放心参考并在此基础上延申使用,详情见md文档 电影推荐算法:Apriori 算法、SVD(奇异值分解)推荐算法 电影、用户可视化 电影、用户管理 数据统计 SVD 推荐 根据电影打分进行推荐 使用 svd 模型计算用户对未评分的电影打分,返回前 n 个打分最高的电影作为推荐结果 n = 30 for now 使用相似电影进行推荐 根据用户最喜欢的前 K 部电影,分别计算这 K 部电影的相似电影 n 部,返回 K*n 部电影进行推荐 K = 10 and n = 5 for now 根据相似用户进行推荐 获取相似用户 K 个,分别取这 K 个用户的最喜爱电影 n 部,返回 K*n 部电影进行推荐 K = 10 and n = 5 for now Redis 使用 Redis 做页面访问次数统计 缓存相似电影 在使用相似电影推荐的方式时,每次请求大概需要 6.6s(需要遍历计算与所有电影的相似度)。 将相似电影存储至 redis 中(仅存储 movie_id,拿到 movie_id 后还是从 mysql 中获取电影详细信息), 时间缩短至:93ms。 十部电影,每部存 top 5 similar movie 登录了 1-6 user并使用了推荐系统,redis 中新增了 50 部电影的 similar movie,也就是说,系统只为 6 为用户计算了共 60 部电影的相似度,其中就有10 部重复电影。 热点电影重复度还是比较高的
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值