首页 > 其他分享 >【设计模式(六)】结构性模式--代理模式

【设计模式(六)】结构性模式--代理模式

时间:2024-07-05 15:30:54浏览次数:15  
标签:-- args 代理 模式 SellTickets 对象 TrainStation 设计模式 public

结构型模式描述如何将类或对象按某种布局组成更大的结构。它分为类结构型模式对象结构型模式,前者采用继承机制来组织接口和类,后者釆用组合或聚合来组合对象。由于组合关系或聚合关系比继承关系耦合度低,满足“合成复用原则”,所以对象结构型模式比类结构型模式具有更大的灵活性。

由于某些原因需要给某对象提供一个代理以控制对该对象的访问。这时,访问对象不适合或者不能直接引用目标对象,代理对象作为访问对象和目标对象之间的中介。

Java中的代理按照代理类生成时机不同又分为静态代理和动态代理。静态代理代理类在编译期就生成,而动态代理代理类则是在Java运行时动态生成。动态代理又有JDK代理和CGLib代理两种。

代理(Proxy)模式分为三种角色:

  • 抽象主题(Subject)类: 通过接口或抽象类声明真实主题和代理对象实现的业务方法。
  • 真实主题(Real Subject)类: 实现了抽象主题中的具体业务,是代理对象所代表的真实对象,是最终要引用的对象。
  • 代理(Proxy)类 : 提供了与真实主题相同的接口,其内部含有对真实主题的引用,它可以访问、控制或扩展真实主题的功能。

【例】火车站卖票(静态代理)

抽象主题

//卖票接口
public interface SellTickets {
    void sell();
}

真实主题

//火车站  火车站具有卖票功能,所以需要实现SellTickets接口
public class TrainStation implements SellTickets {

    public void sell() {
        System.out.println("火车站卖票");
    }
}

代理类

//代售点
public class ProxyPoint implements SellTickets {

    private TrainStation station = new TrainStation();

    public void sell() {
        System.out.println("代理点收取一些服务费用");
        station.sell();
    }
}

客户端

//测试类
public class Client {
    public static void main(String[] args) {
        ProxyPoint pp = new ProxyPoint();
        pp.sell();
    }
}

动态代理
Java中提供了一个动态代理类Proxy,Proxy并不是我们上述所说的代理对象的类,而是提供了一个创建代理对象的静态方法(newProxyInstance方法)来获取代理对象。

//代理工厂,用来创建代理对象
public class ProxyFactory {

    private TrainStation station = new TrainStation();

    public SellTickets getProxyObject() {
        //使用Proxy获取代理对象
        /*
            newProxyInstance()方法参数说明:
                ClassLoader loader : 类加载器,用于加载代理类,使用真实对象的类加载器即可
                Class<?>[] interfaces : 真实对象所实现的接口,代理模式真实对象和代理对象实现相同的接口
                InvocationHandler h : 代理对象的调用处理程序
         */
        SellTickets sellTickets = (SellTickets) Proxy.newProxyInstance(station.getClass().getClassLoader(),
                station.getClass().getInterfaces(),
                new InvocationHandler() {
                    /*
                        InvocationHandler中invoke方法参数说明:
                            proxy : 代理对象
                            method : 对应于在代理对象上调用的接口方法的 Method 实例
                            args : 代理对象调用接口方法时传递的实际参数
                     */
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

                        System.out.println("代理点收取一些服务费用(JDK动态代理方式)");
                        //执行真实对象
                        Object result = method.invoke(station, args);
                        return result;
                    }
                });
        return sellTickets;
    }
}

//测试类
public class Client {
    public static void main(String[] args) {
        //获取代理对象
        ProxyFactory factory = new ProxyFactory();
        
        SellTickets proxyObject = factory.getProxyObject();
        proxyObject.sell();
    }
}

如果没有定义SellTickets接口,只定义了TrainStation(火车站类)。很显然JDK代理是无法使用了,因为JDK动态代理要求必须定义接口,对接口进行代理。

CGLIB是一个功能强大,高性能的代码生成包。它为没有实现接口的类提供代理,为JDK的动态代理提供了很好的补充。

CGLIB是第三方提供的包,所以需要引入jar包的坐标:

<dependency>
    <groupId>cglib</groupId>
    <artifactId>cglib</artifactId>
    <version>2.2.2</version>
</dependency>
//代理工厂
public class ProxyFactory implements MethodInterceptor {

    private TrainStation target = new TrainStation();

    public TrainStation getProxyObject() {
        //创建Enhancer对象,类似于JDK动态代理的Proxy类,下一步就是设置几个参数
        Enhancer enhancer =new Enhancer();
        //设置父类的字节码对象
        enhancer.setSuperclass(target.getClass());
        //设置回调函数
        enhancer.setCallback(this);
        //创建代理对象
        TrainStation obj = (TrainStation) enhancer.create();
        return obj;
    }

    /*
        intercept方法参数说明:
            o : 代理对象
            method : 真实对象中的方法的Method实例
            args : 实际参数
            methodProxy :代理对象中的方法的method实例
     */
    public TrainStation intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        System.out.println("代理点收取一些服务费用(CGLIB动态代理方式)");
        TrainStation result = (TrainStation) methodProxy.invokeSuper(o, args);
        return result;
    }
}

//测试类
public class Client {
    public static void main(String[] args) {
        //创建代理工厂对象
        ProxyFactory factory = new ProxyFactory();
        //获取代理对象
        TrainStation proxyObject = factory.getProxyObject();

        proxyObject.sell();
    }
}

标签:--,args,代理,模式,SellTickets,对象,TrainStation,设计模式,public
From: https://www.cnblogs.com/hudad/p/18285848

相关文章

  • 面试必会之事物控制
    01-什么是事务?事务就是用户定义的一系列数据库操作,这些操作可以视为一个完成的逻辑处理工作单元,要么全部执行,要么全部不执行,是不可分割的工作单元02-事务的特性有哪些?原子性(Atomicity):事务是不可分割的最小操作单元,要么全部成功,要么全部失败。一致性(Consistency):事务......
  • 字节面试 用double,1.0-0.9的结果不是0.1,为什么?
    让我详细解释一下为什么1.0-0.9在二进制中不能精确表示。1.0的二进制表示1.0在二进制中可以精确表示。它的二进制表示为:1.0=1.0(二进制)0.9的二进制表示0.9是一个无法在二进制中精确表示的小数。二进制小数是通过求和1/2,1/4,1/8,1/16,...等幂次表示的。对......
  • 房屋结构安全性监测,云监测实时守护建筑安全
    现代化城市之中的建筑结构形式的复杂多样,对结构安全性的要求自然也变得日益严苛。同时,老旧房屋的安全隐患引人注目,其安全性随时间推移愈发凸显。诸多老旧房屋已达到使用年限,其持续安全使用的可行性需要验证。在环境因素及外部荷载的共同作用下,建筑物可能会出现不均匀沉降、倾......
  • Nacos 2.x 系列【20】集群部署
    文章目录1.前言2.部署服务端2.1准备工作2.2集群节点配置2.3鉴权配置2.4配置数据源2.5配置IP2.6配置端口2.7启动集群3.部署模式3.1直连模式3.2地址服务器模式3.2.1地址服务器3.2.2配置3.3VIP模式(推荐)3.3.1Nginx3.3.1域名1.前言官方文档在实......
  • 道路桥梁健康监测,城市桥梁管养智慧化趋势
    道路桥梁作为现代交通网络的动脉,承载着日益繁重的交通负荷以及人们对安全、顺畅出行的殷切期盼。随着车辆流量的激增与交通工具的多样化,对桥梁结构的稳固性与持久性的要求也随之提升。在这种背景下,对桥梁结构进行全面的健康监测不仅显得十分紧急,更成为了确保公众出行安全、维护......
  • 井盖液位传感器,实时评估井盖健康危险度
    井盖这个小小的身躯,在城市之中却承载着大大的重担。它们遍布在城市的各个角落,无论是繁华的街道还是僻静的巷弄,都能见到它们默默的身影。它们“出事”的概率和它们的数量却是成正比的,如倾斜、移动、井下水位、健康危险度超过阈值等异常情况。不过现在对于这些问题无需过度担心......
  • 河南一胡辣汤店燃气闪爆致20人受伤,燃气泄漏如何及时预警
    在2024年7月3日正午12时47分,高新区赵营社区的一家胡辣汤店突遇了一场燃气闪爆事故。事故的原因已经得到了初步确认:这是由物业公司在进行小区自来水管维修施工过程中,不慎对燃气管道造成了损害。由于燃气管道的破裂,导致了燃气的泄漏,进而引发了这场惊险的闪爆事故。由此可见,对燃......
  • 水库大坝监测预警系统,水库不垮坝汛期更安心
    水库大坝关系着亿万人民的生命财产安全,也是维护地区生态稳定和经济发展的重要保障。尤其是在汛期,大坝的安全更是牵动着无数人的心。建立一套完善的水库大坝监测预警系统,实现对水库大坝全天候、全方位的监测,也是城市防汛减灾过程之中浓墨重彩的一笔。一、水库大坝的安全问题1......
  • 基于javaweb二手闲置物品在线交易平台系统作品成品
     博主介绍:黄菊华老师《Vue.js入门与商城开发实战》《微信小程序商城开发》图书作者,CSDN博客专家,在线教育专家,CSDN钻石讲师;专注大学生毕业设计教育和辅导。所有项目都配有从入门到精通的基础知识视频课程,学习后应对毕业设计答辩。项目配有对应开发文档、开题报告、任务书、P......
  • 静态 top tree 入门
    理论我们需要一个数据结构维护树上的问题,仿照序列上的问题,我们需要一个方法快速的刻画出信息。比如说线段树就通过分治的方式来通过将一个区间划分成\(\logn\)个区间并刻画出这\(\logn\)个区间的信息。然后我们考虑把这个东西放到树上类比。你发现线段树上每个非叶节点都......