设计模式之代理模式

Posted ProChick

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了设计模式之代理模式相关的知识,希望对你有一定的参考价值。

1.简要概述

  • 代理模式就是通过代理对象来控制对真实对象的访问,也就是详细的控制访问某个对象的方法,从而将一些统一的流程代码放到代理类中处理。
  • 代理模式中,被代理的对象可以是远程对象、创建开销大的对象、需要安全控制的对象。
  • 代理模式是面向切面编程的核心实现思想。

2.模式分类

  • 静态代理

    在静态代理中,需要定义一个公共接口,代理对象和被代理对象都要实现这个公共接口中的方法。

    // 教师接口
    public interface CommonTeacher{
        void teach();
    }
    
    // 真实教师角色
    public class RealTeacher implements CommonTeacher{
        @Override
        public void teach(){
            System.out.println("开始上课");
        }
    }
    
    // 代理教师角色
    public class ProxyTeacher implements CommonTeacher{
        private CommonTeacher realTeacher;
        
        public ProxyTeacher(CommonTeacher realTeacher){
            this.realTeacher = realTeacher;
        }
        
        @Override
        public void teach(){
            System.out.println("通知某个教师");
           	realTeacher.teach();
        }
    }
    
    // 测试客户端
    public class Client{
        public static void main(String[] args) {
    		ProxyTeacher proxy = new ProxyTeacher(new RealTeacher());
    		
    		proxy.teach();
    	}
    }
    

    👉优点:在不修改目标对象功能的前提下,能够通过代理对象实现对目标对象的扩展。

    👉缺点:由于代理对象和目标对象都要实现统一的接口,一旦接口中增加新的功能方法,那么二者都需要进行更改实现。

  • JDK动态代理

    在JDK动态代理中,需要定义一个接口,被代理对象要实现这个接口中的方法。但代理对象不需要实现接口,而是利用JDK中提供的API,动态的在内存中构建代理对象。

    // 教师接口
    public interface CommonTeacher{
        void teach();
    }
    
    // 真实教师角色
    public class RealTeacher implements CommonTeacher{
        @Override
        public void teach(){
            System.out.println("开始上课");
        }
    }
    
    // 代理教师角色
    public class ProxyTeacher implements InvocationHandler{
        private CommonTeacher realTeacher;
        
        public ProxyTeacher(CommonTeacher realTeacher){
            this.realTeacher = realTeacher;
        }
        
        @Override
        public Object invoke(Object proxy, Method method, Object[] args){
    		if(method.getName().equals("teach"))
    		{
                System.out.println("通知某个教师");
    			method.invoke(realTeacher, args);
    		}
    		
    		return null;
    	}
        
        public Object getProxy(){
            return Proxy.newProxyInstance(
                        ClassLoader.getSystemClassLoader(), 
                        new Class[] {CommonTeacher.class},
                        realTeacher);
        }
    }
    
    // 测试客户端
    public class Client{
        public static void main(String[] args) {
    		ProxyTeacher proxy = new ProxyTeacher(new RealTeacher());
    		CommonTeacher teacher = (CommonTeacher) proxy.getProxy();
    	
    		teacher.teach();
    	}
    }
    

    👉优点:它是Java原生支持的API,不需要任何其它第三方依赖

    👉缺点:它只能基于接口进行实现

  • Cglib代理

    在Cglib动态代理中,不需要定义接口,需要定义一个类去实现Cglib包中的MethodInterceptor类,然后在重写的intercept方法中完成被代理对象的调用,最后再通过Enhance工具类生成被代理对象的一个子类,让这个子类充当代理对象。Cglib是一个高性能的代码生成包,底层是通过使用字节码处理框架ASM来转换并生成新的类。

    // 真实教师角色
    public class RealTeacher{
        public void teach(){
            System.out.println("开始上课");
        }
    }
    
    // 代理教师角色
    public class ProxyTeacher implements MethodInterceptor{
        private RealTeacher realTeacher;
        
        public ProxyTeacher(RealTeacher realTeacher){
            this.realTeacher = realTeacher;
        }
        
        @Override
        public Object intercept(
            Object arg0, Method arg1, Object[] arg2, MethodProxy arg3){
            
    		System.out.println("通知某个教师");
            Object result = arg3.invokeSuper(arg0, arg2);
    		
    		return result;
    	}
        
        public Object getProxy(){
            Enhancer enhancer = new Enhancer();
    		enhancer.setSuperclass(RealTeacher.class);
    		enhancer.setCallback(realTeacher);
    
            return (RealTeacher) enhancer.create();
        }
    }
    
    // 测试客户端
    public class Client{
        public static void main(String[] args) {
    		ProxyTeacher proxy = new ProxyTeacher(new RealTeacher());
    		ProxyTeacher teacher = (ProxyTeacher) proxy.getProxy();
    
    		teacher.teach();
    	}
    }
    

    👉优点:它与代理的目标对象没有使用限制,无需定义和实现任何接口

    👉缺点:无法处理被final修饰的方法,因为在创建子类对象的时候无法继承

3.模式结构

👉通常由一个抽象角色( 负责定义真实角色和代理角色的一些公共方法 ),一个代理角色( 负责通过真实角色的业务逻辑方法来实现抽象方法,并附加一些别的操作 ),一个真实角色( 负责实现抽象角色,定义真实角色所要实现的业务逻辑供代理角色调用 ),一个客户类( 负责调用代理对象,完成对真实角色的访问)共同组成。

4.实现代码

举例 💡 :假设我们现在要租房,而房东希望我们先和中介进行商量已确定价格,然后我们才给房东进行付钱,那么这个处理过程我们就可以使用代理模式处理。

房子(抽象角色)

public interface House {
	// 谈价格
	void talk();
    
    // 付租金
	void pay();
}

房子中介(代理角色)

public class HouseProxy implements House{
	
	private Landlord landlord;
	
	public HouseProxy(Landlord landlord) {
		this.landlord = landlord;
	}

    @Override
	public void talk() {
		System.out.println("找中介谈价格");
	}

    @Override
	public void pay() {
		landlord.pay();
	}
}

房东(真实角色)

public class Landlord implements House{
	@Override
	public void talk() {
		System.out.println("");
	}
    
	@Override
	public void pay() {
		System.out.println("给房东付钱");
	}
}

客户类

// 测试客户端
public class HouseClient{
    public static void main(String[] args) {
        House proxy = new HouseProxy(new Landlord());
		
		proxy.talk();
		proxy.pay();
    }
}

5.优点好处

  • 代理对象可以在客户端和目标对象之间起到中介的作用,这样就起到了保护了目标对象的作用。
  • 代理对象可以扩展目标对象的功能。
  • 代理模式能将客户端与目标对象分离,在一定程度上降低了系统的耦合度。

6.缺点弊端

  • 在客户端和目标对象之间增加一个代理对象,会造成请求处理速度变慢。
  • 一定程度上增加了系统的复杂度。

7.应用场景

  • 当我们想通过代理来控制对远程对象的访问,可以使用远程代理。
  • 当我们想利用权限来控制对对象的访问,以此来屏蔽对真实对象的直接访问,可以使用安全代理。
  • 当我们需要创建开销很大的对象,先加载一个轻量级的代理对象,以便延迟对真实对象的访问,可以使用虚拟代理。
  • 当我们在处理真实对象的时候,希望代理去处理另外一些事情,可以使用智能代理。

8.应用示例

Spring源码中的AOP面向切面编程

以上是关于设计模式之代理模式的主要内容,如果未能解决你的问题,请参考以下文章

Spring之代理模式

#yyds干货盘点# 设计模式之代理模式:动态代理

设计模式之代理模式(Proxy)详解及代码示例

代理模式之静态代理实现代码

设计模式之代理模式

设计模式之代理模式