代理模式(Proxy Pattern)

23种设计模式完整教程

介绍

代理模式(Proxy Pattern)是指为其他对象提供一种代理,以控制对这个对象的访问。 代理对象在客服端和目标对象之间起到中介作用,代理模式属于结构型设计模式。

在生活中,我们经常见到这样的场景,如:租房中介、售票黄牛、婚介、经纪人、快递、 事务代理、非侵入式日志监听等,这些都是代理模式的实际体现。

目的

1、保护目标对象

2、增强目标对象。

分类

1、静态代理

2、动态代理

动态代理与静态代理的区别

1、静态代理只能通过手动完成代理操作,如果被代理类增加新的方法,代理类需要同步 新增,违背开闭原则。

2、动态代理采用在运行时动态生成代码的方式,取消了对被代理类的扩展限制,遵循开 闭原则。

3、若动态代理要对目标类的增强逻辑扩展,结合策略模式,只需要新增策略类便可完成, 无需修改代理类的代码。

优点

1、代理模式能将代理对象与真实被调用的目标对象分离。

2、一定程度上降低了系统的耦合度,扩展性好。

3、可以起到保护目标对象的作用。

4、可以对目标对象的功能增强。

缺点

1、代理模式会造成系统设计中类的数量增加。

2、在客户端和目标对象增加一个代理对象,会造成请求处理速度变慢。

3、增加了系统的复杂度。

使用场景

1、日志监听

2、保护目标对象或则增强目标对象

3、Spring 利用动态代理实现 AOP 有两个非常重要的类,一个是 JdkDynamicAopProxy 类 和 CglibAopProxy 类。

4、有分库场景时,数据库的动态选择---可考虑这种模式去实现。

使用建议

具体实现

静态代理(MVC模式就是一个典型的静态代理)

(静态代理实例一)老子帮儿子相亲:

类图:

代码:

package com.knowledge.system.software_design_pattern.proxy_pattern.course_instance.static_proxy;

public interface Person {
    void findLove();
}
package com.knowledge.system.software_design_pattern.proxy_pattern.course_instance.static_proxy;

/**
 * @program: demo-pom
 * @description:
 * @author: bo.hu
 * @create: 2020-01-23 14:12
 **/
public class Son implements Person{
    @Override
    public void findLove() {
        System.out.println("不傻就行");
    }
}
package com.knowledge.system.software_design_pattern.proxy_pattern.course_instance.static_proxy;

/**
 * @program: demo-pom
 * @description: 代理对象类
 * @author: bo.hu
 * @create: 2020-01-23 14:13
 **/
public class Father {
    private Son son;

    public Father(Son son) {
        this.son = son;
    }
    public void findLove(){
        System.out.println("父母角度出发:选择");
        this.son.findLove();
        System.out.println("双方父母同意交往,确立关系。");
    }

    public static void main(String[] args) {
        Father f=new Father(new Son());
        f.findLove();
    }
}

(静态代理实例二)数据库的动态选择:

类图:

代码:

package com.knowledge.system.software_design_pattern.proxy_pattern.course_instance.static_proxy_2;

import lombok.Data;

/**
 * @program: demo-pom
 * @description: 订单实体类
 * @author: bo.hu
 * @create: 2020-01-23 14:38
 **/
@Data
public class Order {
    private Object orderInfo;
    private Long createTime;
    private String id;
}
package com.knowledge.system.software_design_pattern.proxy_pattern.course_instance.static_proxy_2;

/**
 * @program: demo-pom
 * @description:
 * @author: bo.hu
 * @create: 2020-01-23 14:44
 **/
public class OrderMapper {
    public int insert(Order order){
        System.out.println("OrderMapper 创建 Order 成功");
        return 1;
    }
}
package com.knowledge.system.software_design_pattern.proxy_pattern.course_instance.static_proxy_2;

public interface OrderService {
    int createOrder(Order order);
}
package com.knowledge.system.software_design_pattern.proxy_pattern.course_instance.static_proxy_2;

/**
 * @program: demo-pom
 * @description:
 * @author: bo.hu
 * @create: 2020-01-23 14:47
 **/
public class OrderServiceImpl implements OrderService {
    private OrderMapper orderMapper;

    public OrderServiceImpl(OrderMapper orderMapper) {
        this.orderMapper = orderMapper;
    }

    @Override
    public int createOrder(Order order) {
        System.out.println("OrderService 调用 orderMapper 创建订单");
        return orderMapper.insert(order);
    }
}
package com.knowledge.system.software_design_pattern.proxy_pattern.course_instance.static_proxy_2;

import javax.xml.crypto.Data;

/**
 * @program: demo-pom
 * @description:
 * @author: bo.hu
 * @create: 2020-01-23 15:12
 **/
public class DynamicDataSourceEntry {

    public final static String DEFAULT = null;

    private final static ThreadLocal<String> local = new ThreadLocal<>();

    public DynamicDataSourceEntry() {
    }

    public static void clear() {
        local.remove();
    }

    public static void get() {
        local.get();
    }

    public static void restore() {
        local.set(DEFAULT);
    }

    public static void set(String resource) {
        local.set(resource);
    }

    public static void set(int year) {
        local.set("DB_" + year);
    }

}
package com.knowledge.system.software_design_pattern.proxy_pattern.course_instance.static_proxy_2;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * @program: demo-pom
 * @description: 创建订单静态代理类
 * @author: bo.hu
 * @create: 2020-01-23 15:22
 **/
public class CreateOrderProxy implements OrderService{
    private SimpleDateFormat yearFormat = new SimpleDateFormat("yyyy");
    private OrderService orderService;

    public CreateOrderProxy(OrderService orderService) {
        this.orderService = orderService;
    }

    public int createOrder(Order order){
        before();
        Long time = order.getCreateTime();
        Integer dbRouter = Integer.valueOf(yearFormat.format(new Date(time)));
        System.out.println("静态代理类自动分配到【DB_" + dbRouter + "】数据源处理数据。");
        DynamicDataSourceEntry.set(dbRouter);
        orderService.createOrder(order);
        after();
        return 0;
    }

    private void before() {
        System.out.println("Proxy before method.");
    }

    private void after() {
        System.out.println("Proxy after method.");
    }

    public static void main(String[] args) {
        Order order=new Order();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd");
        Date date = null;
        try {
            date = sdf.parse("2017/02/01");
        } catch (ParseException e) {
            e.printStackTrace();
        }
        order.setCreateTime(date.getTime());
        OrderService orderService = new CreateOrderProxy(new OrderServiceImpl(new OrderMapper()));
        orderService.createOrder(order);
    }

}

动态代理

JDK自带的动态代理

类图:

代码:

package com.knowledge.system.software_design_pattern.proxy_pattern.course_instance.static_proxy;

public interface Person {
    void findLove();
}
package com.knowledge.system.software_design_pattern.proxy_pattern.course_instance.dynamic_proxy_jdk;

import com.knowledge.system.software_design_pattern.proxy_pattern.course_instance.static_proxy.Person;

/**
 * @program: demo-pom
 * @description: 顾客
 * @author: bo.hu
 * @create: 2020-01-23 16:19
 **/
public class Customer  implements Person {

    @Override
    public void findLove() {
        System.out.println("不傻就行");
    }
}
package com.knowledge.system.software_design_pattern.proxy_pattern.course_instance.dynamic_proxy_jdk;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;


/**
 * @program: demo-pom
 * @description: 动态代理类java实现方式
 * @author: bo.hu
 * @create: 2020-01-23 16:09
 **/
public class JDKMeipo implements InvocationHandler {

    private Object target;

    public Object getIntence(Object object){
        this.target=object;
        Class<?>clazz=target.getClass();
        return Proxy.newProxyInstance(clazz.getClassLoader(),clazz.getInterfaces(),this);
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        before();
        Object obj=method.invoke(this.target,args);
        after();
        return obj;
    }

    private void before() {
        System.out.println("开始  物色人选");
    }

    private void after() {
        System.out.println("结束  物色人选");
    }

}
package com.knowledge.system.software_design_pattern.proxy_pattern.course_instance.dynamic_proxy_jdk;


import com.knowledge.system.software_design_pattern.proxy_pattern.course_instance.static_proxy.Person;

/**
 * @program: demo-pom
 * @description:
 * @author: bo.hu
 * @create: 2020-01-23 16:20
 **/
public class Test {
    public static void main(String[] args) {
//        动态代理类和被代理类必须继承同一个接口。
//        动态代理只能对接口中声明的方法进行代理。
//        每一个动态代理实例都有一个关联的InvocationHandler。
//        通过代理实例调用方法,方法调用请求会被转发给InvocationHandler的invoke方法。
//        只能代理声明在接口中的方法。
        Person obj=(Person)new JDKMeipo().getIntence(new Customer());
        obj.findLove();
    }
}

CGLIB实现的动态代理(Spring中同时使用了JDK与CGLIB这两种代理)

类图:

代码:

package com.knowledge.system.software_design_pattern.proxy_pattern.course_instance.static_proxy;

public interface Person {
    void findLove();
}
package com.knowledge.system.software_design_pattern.proxy_pattern.course_instance.dynamic_proxy_cglib;

import com.knowledge.system.software_design_pattern.proxy_pattern.course_instance.static_proxy.Person;

public class Customer implements Person {
    @Override
    public void findLove() {
        System.out.println("cglib   findLove()");
    }
}
package com.knowledge.system.software_design_pattern.proxy_pattern.course_instance.dynamic_proxy_cglib;

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

public class CgLibMeipo implements MethodInterceptor {

    public Object getInstence(Class<?> clazz){
        Enhancer enhancer =new Enhancer();
        enhancer.setSuperclass(clazz);
        enhancer.setCallback(this);
        return enhancer.create();
    }

    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        before();
        Object obj=methodProxy.invokeSuper(o,objects);
        after();
        return obj;
    }

    private void after() {
        System.out.println("代理类前置处理");
    }

    private void before() {
        System.out.println("代理类后置处理");
    }

}
package com.knowledge.system.software_design_pattern.proxy_pattern.course_instance.dynamic_proxy_cglib;

public class Test {
    public static void main(String[] args) {
        Customer customer=(Customer)new CgLibMeipo().getInstence(Customer.class);
        customer.findLove();
    }
}

 

以下是组合模式、装饰器模式、外观模式、享元模式和代理模式的应用案例和代码实现步骤的简要说明: 1. 组合模式 (Composite Pattern): 应用案例:文件系统的目录结构可以使用组合模式来表示,其中目录和文件都可以作为容器或叶子节点,可以方便地进行递归操作。 代码实现步骤:创建一个抽象类或接口表示组件,其中包含添加、删除和获取子组件的方法。实现类分别表示叶子节点和容器节点,容器节点可以包含其他组件。 2. 装饰器模式 (Decorator Pattern): 应用案例:在一个图形绘制软件中,可以使用装饰器模式来实现不同的图形对象以及对图形进行装饰,例如添加颜色、添加边框等。 代码实现步骤:创建一个抽象类或接口表示基本对象或装饰器,其中包含一个基本对象的引用。具体装饰器类继承自该抽象类,并在调用方法时添加额外的功能。 3. 外观模式 (Facade Pattern): 应用案例:在一个电子商务平台中,可以使用外观模式来创建一个统一的接口,将不同子系统的功能封装起来,便于客户端调用。 代码实现步骤:创建一个外观类,该类提供了一个简单的接口来调用多个子系统的功能,并在内部进行协调和管理。 4. 享元模式 (Flyweight Pattern): 应用案例:在一个游戏中,可以使用享元模式来共享不同的游戏资源对象,例如共享相同的纹理、音频等,以减少内存的使用。 代码实现步骤:创建一个享元工厂类来管理共享对象,通过池化技术来缓存和重用对象,并提供一个获取共享对象的方法。 5. 代理模式 (Proxy Pattern): 应用案例:在一个网络请求中,可以使用代理模式来代表真实的网络请求对象,以进行一些额外的操作,例如鉴权、缓存等。 代码实现步骤:创建一个接口或抽象类来表示真实对象和代理对象,代理对象持有一个真实对象的引用,并在调用方法时进行一些额外的处理。 以上是这些设计模式的简要应用案例和代码实现步骤。在实际开发中,可以根据具体需求选择合适的设计模式,并根据设计模式的原则进行设计和实现。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值