1代理模式

代理模式

代理模式(Proxy Pattern)也叫委托模式,是一个使用率非常高的模式。

1代理模式的定义
代理模式的英文原话是:
Provide a surrogate or placeHolder for another object to control access to it.
意思是:为其他对象提供一种代理以控制对这个对象的访问。

代理模式是一项基本的设计技巧,许多其他模式,如状态模式策略模式访问者模式本质上也采用了代理模式
代理模式提供一下3个角色。
  • 抽象主题(Subject)角色:该角色是真实主体和代理主体的共同接口,以便在任何可以使用真实主体的地方都可以使用代理主体。
  • 代理主体(Proxy Subject)角色:也叫作委托类、代理类,该角色负责控制对真实主体的引用,负责在需要的时候创建或删除真实主题对象,并且在真实主题角色处理完毕前后座预处理和善后处理工作。
  • 真实主题(Real Subject)角色:也叫被委托角色、被代理角色,是业务逻辑具体执行者。

一些比较易于理解的例子:
1.Windows里的快捷方式。
2.猪八戒找高翠兰,结果是孙悟空变的。可以理解为,把高翠兰的外貌抽象出来,高翠兰本人和孙悟空都实现了这个接口,猪八戒访问高翠兰时看不出来高翠兰这个代理类。
3.买火车票不一定在火车站买,也可以去代售点。
4.一张支票或银行存单是账户中资金的代理。支票在市场交易中用来代替现金,并提供对签发人账号上资金的控制。
5.spring中的aop。

代理模式的类图

创建抽象主题
Subject.java
package com.eric.结构型模式.代理模式.引例;

/**
 * @author Eric
 * @ProjectName my_design_23
 * @description 抽象主题类
 * @CreateTime 2020-11-28 08:32:13
 */
public interface Subject {
    //定义一个请求方法
    public void request();
}
创建真实主题
RealSubject.java
package com.eric.结构型模式.代理模式.引例;

/**
 * @author Eric
 * @ProjectName my_design_23
 * @description 真实主题
 * @CreateTime 2020-11-28 08:33:10
 */
public class RealSubject implements Subject{
    @Override
    public void request() {
        //业务处理
        System.out.println("我处理了一个业务...");
    }
}
创建代理类
ProxySubject.java
package com.eric.结构型模式.代理模式.引例;

/**
 * @author Eric
 * @ProjectName my_design_23
 * @description 代理主题
 * @CreateTime 2020-11-28 08:34:31
 */
public class ProxySubject implements Subject {
    private Subject subject;
    public ProxySubject(Subject subject){
        this.subject = subject;
    }
    //实现请求方法
    @Override
    public void request() {
        this.beforeRequest();
        subject.request();
        this.afterRequest();
    }

    //请求前操作
    private void beforeRequest()
    {
        //预处理
        System.out.println("代理类的预处理...");
    }
    //请求后的操作
    private void afterRequest()
    {
        System.out.println("代理类的善后处理...");
    }
}

注意事项:
  • 与适配器模式的区别:适配器模式主要改变所考虑对象的接口,而代理模式不能改变所代理类的接口。
  • 与装饰者模式的区别:装饰者模式是为了增强功能,代理模式则是为了加以控制。

2代理模式的应用
    a.代理模式的种类
    • 远程(Remote)代理:为一个位于不同空间的对象提供一个局部代表对象。这个不同地址空间,可以使本机也可以在另一台机器中。  
    • 虚拟(Virtual)代理:有时需要创建一些消耗较多资源的对象,可以首先创建代理对象,而将真实对象的创建延迟。例如,加载一个很大的图片,可以通过图片的代理来代替真正的图片。
    • 保护(Protect Access)代理:控制对一个对象的访问,如果需要,可以给不同的用户提供不同级别的使用权限。
    • 缓存(Cache)代理:为一个目标操作的结果提供链式的存储空间,以便多个客户端可以共享这些结果。
    • 同步(Sychronization)代理:使几个用户能够同时使用一个对象而没有冲突。
    • 智能(Smart Reference)引用:当一个对象被引用时,提供一些额外的操作,例如,记录访问的流量和次数等。
注意: 在所有种类的代理中,虚拟代理远程代理智能代理保护代理是最为常见的代理模式。  

    b.代理模式的优点
    • 职责清晰:真实角色实现实际的业务逻辑,不用关心其他非本职的事物,通过后期的代理完成附加的事物,附带的结果就是编程简洁清晰。
    • 高扩展性:具体主体角色随需求不同可能有很多种,但只要实现了接口,代理类就完全可以在不作任何修改的情况下代理各种真实主题角色。
    • 智能化:代理类可以在运行时才确定需要去代理的真实主题,这是一种强大的功能。
    c.代理模式的使用场景
运用很广泛,大到系统框架、企业平台,小到事务处理、代码片段,随处可见代理模式的使用。例如,java RMI的远程调用就是一种代理模式的应用,现在流行的AOP也可以通过代理模式实现。
3代理模式实例
例1:游戏代练
IGamePlayer接口对游戏玩家进行抽象
IGamePlayer.java
package com.eric.结构型模式.代理模式.例1;

/**
 * @author Eric
 * @ProjectName my_design_23
 * @description 游戏接口
 * @CreateTime 2020-11-29 18:01:15
 */
public interface IGamePlayer {
    public void killBoss();//杀Boss
    public void upGrade();//升级
}
GamePlayer实现IGamePlayer接口,是玩家
GamePlayer.java
package com.eric.结构型模式.代理模式.例1;

/**
 * @author Eric
 * @ProjectName my_design_23
 * @description 玩家类
 * @CreateTime 2020-11-29 18:02:38
 */
public class GamePlayer implements IGamePlayer{
    private String name= "";
    public GamePlayer(String name){
        this.name = name;
    }

    public void killBoss(){
        System.out.println(this.name+"杀Boss中...");
    }
    public void upGrade(){
        System.out.println("成功升了一级!!!");
    }
}
代理类则实现IGamePlayer接口,并实现两个私有方法日志和消耗时间方法。
GamePlayerProxy.java
package com.eric.结构型模式.代理模式.例1;

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

/**
 * @author Eric
 * @ProjectName my_design_23
 * @description 游戏代练
 * @CreateTime 2020-11-29 18:05:44
 */
public class GamePlayerProxy implements IGamePlayer {
    private IGamePlayer player = null;
    public GamePlayerProxy(IGamePlayer player){
        this.player = player;
    }
    //记录打怪时间
    private void log(){
        String pattern = "YYYY-MM-dd HH:mm:ss";
        SimpleDateFormat sdf = new SimpleDateFormat(pattern);

        System.out.println("打怪时间: "+sdf.format(new Date()));
    }

    @Override
    public void killBoss() {
        this.log();
        player.killBoss();
    }

    @Override
    public void upGrade() {
        player.upGrade();
        this.count();
    }
    //计算升级所用时间
    private void count()
    {
        System.out.println("升1级耗费100小时!");
    }
}
测试
ClientDemo.java
package com.eric.结构型模式.代理模式.例1;

/**
 * @author Eric
 * @ProjectName my_design_23
 * @description 测试类
 * @CreateTime 2020-11-29 18:35:46
 */
public class ClientDemo {
    public static void main(String[] args) {
        IGamePlayer player = new GamePlayer("Eric");
        GamePlayerProxy proxy = new GamePlayerProxy(player);

        proxy.killBoss();
        proxy.upGrade();
    }
}
测试结果:

例2:图片的代理
我们将创建一个Image接口和实现了Image接口的实体类。ImageProxy是一个代理类,减少RealImage对象加载的内存占用。
ProxyPatternDemo类使用ProxyImage来获取要加载的Image对象,并按照需求进行显示。

步骤1
创建接口
Image.java
package com.eric.结构型模式.代理模式.例2;

/**
 * @author Eric
 * @ProjectName my_design_23
 * @description 图片接口
 * @CreateTime 2020-11-29 19:03:44
 */
public interface Image {
    void display();
}

步骤2
创建接口的实现类
RealImage.java
package com.eric.结构型模式.代理模式.例2;

/**
 * @author Eric
 * @ProjectName my_design_23
 * @description 真实的图片
 * @CreateTime 2020-11-29 19:04:48
 */
public class RealImage implements Image {
    private String fileName;

    public RealImage(String fileName){
        this.fileName = fileName;
        loadFromDisk(fileName);
    }

    @Override
    public void display() {
        System.out.println("正在显示..."+fileName);
    }

    private void loadFromDisk(String fileName){
        System.out.println("从硬盘加载中..."+fileName);
    }
}
ImageProxy.java
package com.eric.结构型模式.代理模式.例2;

/**
 * @author Eric
 * @ProjectName my_design_23
 * @description 图片代理类
 * @CreateTime 2020-11-29 19:25:24
 */
public class ImageProxy implements  Image {
    private RealImage realImage;
    private String fileName;

    public ImageProxy(String fileName){
        this.fileName = fileName;
    }

    @Override
    public void display() {
        if(realImage == null)
            realImage = new RealImage(fileName);
        realImage.display();
    }

}
步骤三
测试
package com.eric.结构型模式.代理模式.例2;

/**
 * @author Eric
 * @ProjectName my_design_23
 * @description 测试类
 * @CreateTime 2020-11-29 19:28:26
 */
public class ProxyPatternDemo {
    public static void main(String[] args) {
        Image image = new ImageProxy("test01.jpg");
        //图片从硬盘加载
        image.display();
        System.out.println("--------------------");
        //图片不需要从硬盘加载
        image.display();
    }
}
测试结果
可以看出第一次从硬盘中加载了图片,而第二次则是从缓存中加载图片。





posted @ 2020-12-10 12:19  喵酱张-Eric  阅读(117)  评论(0编辑  收藏  举报