首页 > 其他分享 >代理模式

代理模式

时间:2024-01-21 21:00:16浏览次数:20  
标签:void System 模式 代理 println public out

  • 定义:为其他对象提供一种代理,以控制对这个对象的访问,代理对象在客户端和目标对象之间起到中介作用
  • 类型:结构型
  • 适用场景:
    •   保护目标对象
    •   增强目标对象
  • 优点:
    •   代理模式能将代理对象与真实被调用的目标对象分离
    •   一定程度上降低了系统的耦合度,扩展性好
    •   保护目标对象
    •   增强目标对象
  • 缺点:
    •   代理模式会造成系统设计中类的数目增加
    •   在客户端和目标对象增加一个代理对象,会造成请求处理速度变慢
    •   增加系统的复杂度
  • 扩展:
    •   静态代理:在代码中显示指定的代理
    •   动态代理:无法代理类,可以代理接口
    •   Cglib代理:可以代理类,针对类实现进行代理,如果代理一个类,Cglib会生成一个被代理类的子类,通过继承覆盖其中的方法,然后还有重写
  • Spring代理选择
    •   当Bean有实现接口时,Spring就会用JDK的动态代理
    •   当Bean没有实现接口时,Spring使用Cglib代理
    •   也可以强制使用Cglib:在spring配置中加入<aop:aspectj-autoproxy proxy-target-class="true"/>
  • 相关设计模式:
    •   代理模式和装饰者模式:实现上相似,但是目的不同,装饰者模式是为对象加上行为,而代理模式是控制访问,代理模式更加注重通过设置代理人的方式来增强目标对象,通常使用代理模式时,会在代理类中创建一个对象的实例,而装饰者模式的时候,通常会把原始对象作为一个参数传给装饰者的构造器
    •   代理模式和适配器模式:适配器模式主要改变所考虑对象的接口,而代理模式是不能改变所代理类的接口的

Service coding

/**
 * <p>商品接口</p>
 *
 */
public interface CommodityService {

    /**
     * 获取指定商品
     */
    void getCommodity(String name);

}
/**
 * <p>宠物狗实现商品接口 == 获取狗粮</p>
 *
 */
public class DogImpl implements CommodityService {

    @Override
    public void getCommodity(String name) {
        System.out.println("宠物狗获得商品:" + name);
    }

}
/**
 * <p>用户实现商品类 == 获取吃的</p>
 *
 */
public class UserImpl implements CommodityService {

    @Override
    public void getCommodity(String name) {
        System.out.println("用户获得商品:" + name);
    }

}

 

非代理Coding

/**
 * <p>用户自己去超市取商品 </p>
 *
 */
public class UserOwn implements CommodityService {

    @Override
    public void getCommodity(String name) {
        goSuperMarket();
        choose(name);
        pay();
        System.out.println("用户获得商品:" + name);
        goHome();
    }

    private void goSuperMarket() {
        System.out.println("去超市");
    }

    private void choose(String name) {
        System.out.println("选商品: " + name);
    }

    private void pay() {
        System.out.println("付钱");
    }

    private void goHome() {
        System.out.println("买完商品,回家");
    }

 

静态代理 Coding

/**
 * <p>用户代理类 == 静态代理模式,被代理的对象在编译时就知道了</p>
 *
 */
public class UserProxy implements CommodityService {

    /**
     * 区别于装饰器模式,这里的被代理的对象的实例是在代理的类中完成实例化的,不对外暴露
     * 虽然代理模式有点类似于装饰器模式,但是本质上还是有区别的
     * 1、代理模式主要是控制某个特定对象的访问
     * 2、装饰器模式主要是给对象添加行为,具有增强对象原有行为的能力
     * 3、不是所有实现了接口的类对象都可以成为被代理的对象【要深刻理解这句话】
     * 4、所有实现了接口的类对象都可以成为被装饰的对象
     */
    private UserImpl user;

    public UserProxy() {
        // 预先确定代理与被代理者的关系 -- 被代理的对象是人
        user = new UserImpl();
    }

    @Override
    public void getCommodity(String name) {
        System.out.println("我是UU跑腿的工作人员,我去超市帮助用户取商品:" + name);
        user.getCommodity(name);
        System.out.println("商品已成功交给用户,期待用户好评");
    }

}
/**
 * <p>宠物狗代理类 == 静态代理模式</p>
 *
 */
public class DogProxy implements CommodityService {

    private DogImpl dog;

    public DogProxy() {
        // 预先确定代理与被代理者的关系 -- 被代理的对象是宠物狗
        dog = new DogImpl();
    }

    @Override
    public void getCommodity(String name) {
        System.out.println("我是UU跑腿的工作人员,我去超市帮助狗狗取狗粮:" + name);
        dog.getCommodity(name);
        System.out.println("商品已成功交给狗狗,期待狗狗的主人好评");
    }

}

 

UML

动态代理Coding

/**
 * <p>动态代理类 == 程序运行时,代理类才知道被代理的对象是哪个</p>
 *
 */
public class DynamicProxy implements InvocationHandler {

    /**
     * 被代理的目标对象
     */
    private Object targetObj;

    /**
     * 暂时不知道被代理的对象是人还是动物或是其它...etc
     */
    public DynamicProxy(Object object) {
        this.targetObj = object;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("我是UU跑腿的工作人员,我去超市帮助客户取商品:" + args[0]);
        Object object = method.invoke(targetObj, args);
        System.out.println("拿到被代理对象调用的方法名:" + method.getName() + ",方法参数个数:" + method.getParameterCount());
        System.out.println("商品已成功转交给被代理的对象,期待对象好评");
        return object;
    }

}

 

代理工厂

/**
 * <p>代理类工厂</p>
 *
 */
public class ProxyFactory {

    /**
     * 获取一个静态用户代理类对象
     */
    public static CommodityService getUserProxy() {
        return new UserProxy();
    }

    /**
     * 获取一个静态宠物狗的代理类对象
     */
    public static CommodityService getDogProxy() {
        return new DogProxy();
    }

    public static Object getDynProxy(Object target) {
        InvocationHandler handler = new DynamicProxy(target);
        return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), handler);
    }

}

 

虚拟代理

/**
 * <p>签订接口 </p>
 *
 */
public interface Signable {
    /**
     * 定义签订方法
     */
    void sign();
}
/**
 * <p>领导 == 实现签订接口</p>
 *
 */
public class Leader implements Signable {

    {
        System.out.println("各位久等了,我来了!");
    }

    /**
     * 合同列表
     */
    private List<String> deals;

    public Leader() {
        deals = new LinkedList<>();
    }

    public List<String> getDeals() {
        return deals;
    }

    public void setDeals(List<String> deals) {
        this.deals = deals;
    }

    public void addDeal(String deal) {
        this.deals.add(deal);
    }

    public void addDeals(List<String> deals) {
        this.deals.addAll(deals);
    }

    @Override
    public void sign() {
        Collections.sort(this.deals);
        for (String deal : deals) {
            System.out.println("领导签订了合同:" + deal);
        }
        System.out.println();
    }

}
/**
 * <p>领导身边的秘书 == 将领导作为被代理的对象,但是会延缓被代理对象的创建时间,最后实现签订接口</p>
 *
 */
public class Secretary implements Signable {

    /**
     * 合同列表 == 当领导在的时候,这个合同列表会递交给老板,反之,则先放在秘书这里
     */
    private List<String> deals;
    private Leader leader;

    public Secretary() {
        this.deals = new LinkedList<>();
    }

    /**
     * 添加一份合同
     */
    public void addDeal(String deal) {

        // 如果领导不在的话,秘书先揽收
        if (leader == null) {
            this.deals.add(deal);
            System.out.println("秘书揽收了合同:" + deal);
        } else {
            // 否则,直接递交给领导
            this.leader.addDeal(deal);
            System.out.println("领导亲自揽收了合同:" + deal);
        }
    }

    @Override
    public void sign() {
        if (leader == null) {
            System.out.println("领导不在,请稍等");
        } else {
            // 否者的话,领导将秘书揽收的合同拿过来
            this.leader.addDeals(this.deals);
            this.leader.sign();
        }
    }

    static class LeaderFactory {
        public static Leader getLeader() {
            return new Leader();
        }
    }

    public void initLeader(int second) {
        int n = 0;
        do {
            System.out.println("等待领导出现:" + (++n) + "秒");
        } while (--second > 0);
        this.leader = LeaderFactory.getLeader();
    }

}

 

测试

/**
 * <p>代理模式测试</p>
 *
 */
public class ProxyTest {

    public static void main(String[] args) {

        String uName = "奥利奥饼干";
        String dName = "狗粮";
        // 1、不使用代理
        noProxy(uName);
        // 2、使用静态代理
        useStaticProxy(uName, dName);
        // 3、使用动态代理
        useDynamicProxy(uName, dName);

        int second = 5;
        // 4、使用虚拟代理
        useVirtualProxy(second);

        /**
         * 不使用代理:没有对比就没有伤害,主要和下面使用了代理模式的对象进行比较
         * 静态代理:针对特定对象的访问进行"装饰",虽和装饰者模式很像,但也只是很像,切记搞混淆
         * 动态代理:区别静态代理,静态代理模式在程序编译时即确定了被代理的对象
         *             而动态代理只有在程序运行时才确定要被代理的对象是谁
         *        动态代理主要应用于框架,即反射技术一般用不到,如果用到了,那多半是用于框架级的项目
         *        典型代表:Spring框架 -- AOP【面向切面编程】
         * 虚拟代理:可延缓被代理对象的创建
         *        优点: 程序启动快
         *        缺点: 因为被代理的实例不是在第一时间创建的,因此在使用的时候,
         *             需要狠小心的判断null值,以防止NullPointException
         *
         * 
         */
    }


    /**
     * 不使用代理
     *
     * @param uName 用户商品名称
     */
    private static void noProxy(String uName) {
        // 使用代理模式,用户自己去超市买商品
        UserOwn userOwn = new UserOwn();
        userOwn.getCommodity(uName);
        System.out.println("===========分割线");
    }


    /**
     * 使用静态代理
     *
     * @param uName 用户商品名称
     * @param dName 宠物狗商品名称
     */
    private static void useStaticProxy(String uName, String dName) {
        // 使用静态代理模式,通过UU跑腿服务,用户拿到自己要的薯片
        ProxyFactory.getUserProxy().getCommodity(uName);
        System.out.println("===========分割线");
        // 使用静态代理模式,通过UU跑腿服务,宠物狗拿到自己要的狗粮
        ProxyFactory.getDogProxy().getCommodity(dName);
        System.out.println("===========分割线");
    }

    /**
     * 使用动态代理
     *
     * @param uName 用户商品名称
     * @param dName 宠物狗商品名称
     */
    private static void useDynamicProxy(String uName, String dName) {
        // 使用动态代理模式,通过UU跑腿服务,用户拿到自己要的薯片
        CommodityService userProxy = (CommodityService) (ProxyFactory.getDynProxy(new UserImpl()));
        userProxy.getCommodity(uName);
        System.out.println("===========分割线");

        // 使用动态代理模式,通过UU跑腿服务,宠物狗拿到自己要的狗粮
        CommodityService dogProxy = (CommodityService) (ProxyFactory.getDynProxy(new DogImpl()));
        dogProxy.getCommodity(dName);
        System.out.println("===========分割线");
    }

    /**
     * 使用虚拟代理
     *
     * @param second 秒数
     */
    private static void useVirtualProxy(int second) {

        Secretary secretary = new Secretary();
        secretary.addDeal("合同1");
        secretary.addDeal("合同2");
        secretary.sign();

        // 期望领导什么时候出现
        secretary.initLeader(second);

        secretary.addDeal("合同3");
        secretary.addDeal("合同4");
        secretary.sign();

    }

}

 

源码中的应用

  • org.springframework.aop.framework.ProxyFactoryBean:代理工厂Bean,核心方法是getObject()
 public Object getObject() throws BeansException {
        this.initializeAdvisorChain();
        if (this.isSingleton()) {
            return this.getSingletonInstance();
        } else {
            if (this.targetName == null) {
                this.logger.warn("Using non-singleton proxies with singleton targets is often undesirable. Enable prototype proxies by setting the 'targetName' property.");
            }
            return this.newPrototypeInstance();
        }
}
  • org.springframework.aop.framework.JdkDynamicAopProxy:JDK动态代理
  • org.springframework.aop.framework.CglibAopProxy:对类进行代理增强
  • org.apache.ibatis.binding.MapperProxyFactory:Mapper代理工厂

标签:void,System,模式,代理,println,public,out
From: https://www.cnblogs.com/wangzhilei-src/p/17978351

相关文章

  • 设计模式—行为型模式之观察者模式
    设计模式—行为型模式之观察者模式观察者模式(ObserverPattern):定义对象间的一种一对多依赖关系,使得每当一个对象状态发生改变时,其相关依赖对象皆得到通知并被自动更新。观察者模式又叫做发布-订阅(Publish/Subscribe)模式、模型-视图(Model/View)模式、源-监听器(Source/Listener)模......
  • js设计模式之观察者模式
    <!DOCTYPEhtml><htmllang="en"><head><metacharset="UTF-8"><title>观察者模式</title></head><body><script>classEvent{constructor(){}//事件容器,可以是一个也可以是......
  • Centos7 nat网络模式静态ip配置。
    配置流程:1.本机找到 VMwareNetworkAdapterVMnet8,然后配置ipv4: 2:vm里找到编辑->虚拟网络编辑器,然后按第一步里配置的信息来配置 VMwareNetworkAdapterVMnet8里的网关这些。   3:进入centos7系统,配置ifcfg-ens33,vi /etc/sysconfig/network-scripts/ifcfg......
  • 《图解设计模式》PDF
    内容简介原版连续畅销12年、重印25次!194张图表+Java示例代码=轻松理解GoF的23种设计模式《程序员的数学》《数学女孩》作者结城浩又一力作◆图文并茂194张图表(包括57张UML类图)穿插文中,帮助理解各设计模式◆通俗易懂用浅显的语言逐一讲解23种设计模式,读完此书会......
  • 软件测试/测试开发/全日制|Page Object模式:为什么它是Web自动化测试的必备工具
    为UI页面写测试用例时(比如web页面,移动端页面),测试用例会存在大量元素和操作细节。当UI变化时,测试用例也要跟着变化,PageObject很好的解决了这个问题。使用UI自动化测试工具时(包括selenium,appium等),如果无统一模式进行规范,随着用例的增多会变得难以维护,而PageObject让自......
  • springboot项目结合filter,jdk代理实现敏感词过滤(简单版)
    我们对getParameter()这个方法得到的参数进行敏感词过滤。实现思路:利用过滤器拦截所有的路径请求同时在在过滤器执行的时候对getParameter得到的value值进行过滤。最后呢,到我们自己的实现的逻辑中呢?这个value值就被我们做过处理了。1:自定义的过滤配置文件把文件位置放在resource下的......
  • 模拟jdk动态代理(完整版)
    实现思路1:定义一个字符串s2:加载s利用流生成对应的java文件3:通过类加载器加载java文件生成class文件4:通过class生成代理对象5:测试成功我使用过jdk代理的场景1:通过拦截request对象,代理其中的get参数的方法来过滤敏感词2:通过阅读aop源码发现,底层用的也是动态代理(jdk,cglib)3:jdk代......
  • spring--JDK动态代理的实现原理
    JDK动态代理的实现原理涉及到Java的反射机制。它允许在运行时动态创建一个代理类,这个代理类实现了一组接口,并将所有方法调用转发到一个InvocationHandler实例。下面是JDK动态代理的实现原理的详细步骤:定义接口:首先,定义一个或多个接口,这些接口声明了需要被代理的方法。......
  • spring--CGLIB动态代理的实现原理
    CGLIB(CodeGenerationLibrary)是一个强大的、高性能、高质量的代码生成库,它可以在运行时扩展Java类和实现Java接口。CGLIB动态代理是基于继承的方式来实现的,它不需要接口,可以代理普通类。以下是CGLIB动态代理的实现原理:继承:CGLIB动态代理通过继承目标类来创建子类,并在......
  • spring--JDK动态代理和CGLIB代理的区别
    JDK动态代理和CGLIB代理是Java中常用的两种动态代理实现方式,它们各有特点和适用场景:JDK动态代理:JDK动态代理是基于接口的代理方式,它使用Java反射机制来创建代理对象,并要求目标对象实现一个或多个接口。在代理过程中,JDK动态代理会创建一个实现了目标对象所有接口的代......