[设计模式]代理模式

无人久伴 提交于 2020-01-29 19:09:11

1. 定义

  为其他对象提供一种代理以控制对这个对象的访问。

  代理模式是通过创建一个代理对象,用这个代理对象去代表真实的对象,客户端得到这个代理对象后,对客户端并没有什么影响,就跟得到了真实对象一样来使用。

    当客户端操作这个代理对象的时候,实际上功能最终还是会由真实的对象来完成,只不过是通过代理操作的,也就是客户端操作代理,代理操作真正的对象。

2. 类图

  

  Proxy: 代理对象,通常包含了以下功能,实现了与具体目标对象一样的借口,保存一个指向具体目标对象的引用,可以在需要的时候调用具体的目标对象,可以控制对具体目标对象的访问,并可以负责创建和删除它。

  Subject: 目标对象,定义代理和具体目标对象的借口。

  RealSubject: 具体目标对象,真正实现目标对象要求的功能。

3. 实例

  

package com.jerry.designpattern.proxy;
/**
 * 
 * @author Jerry
 * @date 2015年1月21日 上午10:39:09
 */
public interface Player {
    void killMonster();
}

package com.jerry.designpattern.proxy;
/**
 * 
 * @author Jerry
 * @date 2015年1月21日 上午10:46:10
 */
public class PlayerImpl implements Player{
    
    /**
     * 经验值 experience points
     */
    private int exp;
    
    /**
     * 等级
     */
    private int level;
    
    public PlayerImpl() {
        level = 1;
    }
    
    @Override
    public void killMonster() {
        // TODO Auto-generated method stub
        System.out.println("杀死一个怪物,获得50点经验");
        exp += 50;
        upgrade();
    }
    
    /**
     * 升级
     */
    private void upgrade() {
        // TODO Auto-generated method stub
        if (exp % 100 == 0) {
            this.level++;
            System.out.println("恭喜你升级了,当前等级为: " + this.level);
        }
    }

}

package com.jerry.designpattern.proxy;
/**
 * 
 * @author Jerry
 * @date 2015年1月21日 上午11:05:01
 */
public class GameProxy implements Player{
    
    private Player player;
    
    public GameProxy(Player player) {
        this.player = player;
    }
    
    @Override
    public void killMonster() {
        // TODO Auto-generated method stub
        System.out.println("游戏公式代理升级,一次升10级");
        for (int i = 0; i < 20; i++) {
            player.killMonster();
        }
    }
    
}

package com.jerry.designpattern.proxy;
/**
 * 
 * @author Jerry
 * @date 2015年1月21日 上午11:00:54
 */
public class Client {
    public static void main(String[] args) {
        
        /*
         * 不使用游戏代理,自己手动杀怪升级
         */
        Player player1 = new PlayerImpl();
        player1.killMonster();
        player1.killMonster();
        player1.killMonster();
        player1.killMonster();
        
        /*
         * 花费money找代理升级
         * 一次升10级
         */
        Player player2 = new PlayerImpl();
        Player proxy = new GameProxy(player2);
        proxy.killMonster();
        proxy.killMonster();
    }
}

4. 代理的分类

 代理大致可以分为:

  虚代理:根据需要来创建开销很大的对象,该对象只有在真正使用的时候才被创建。  

  远程代理:用来在不同地址空间上代表相同的一个对象,这个不同地址空间可以在本机上,也可以在其他机器上。在Java中最经典的是RMI

  copy-on-write代理:在客户端操作的时候,只有对象确实改变了,才会真正的拷贝或克隆一个目标对象,算是虚代理的一个分支。

  保护代理:控制原始对象的访问,如果有需要,可以给不同的用户提供不同的访问权限,以控制对原始对象的访问。

  Cache代理:为那些昂贵操作的结构提供临时空间,以便多个客户端可以共享这些结果。

    防火墙代理:保护对象不被恶意用户访问和操作。

    同步代理:使多个用户能够同时访问目标对象而没有冲突。

    智能指引:在访问对象时执行一些附加的操作。

5. 动态代理

  Java对代理模式提供了内建的支持,在java.lang.reflect包下面,提供了一个Proxy和一个InvacationHandler接口,通常前面自己实现的代理模式称为静态代理,使用Java提供的功能实现的代理模式称为动态代理,

  

package com.jerry.designpattern.dynamicproxy;
/**
 * 
 * @author Jerry
 * @date 2015年1月21日 上午10:39:09
 */
public interface Player {
    void killMonster();
}

package com.jerry.designpattern.dynamicproxy;
/**
 * 
 * @author Jerry
 * @date 2015年1月21日 上午10:46:10
 */
public class PlayerImpl implements Player{
    
    /**
     * 经验值 experience points
     */
    private int exp;
    
    /**
     * 等级
     */
    private int level;
    
    public PlayerImpl() {
        level = 1;
    }
    
    @Override
    public void killMonster() {
        // TODO Auto-generated method stub
        System.out.println("杀死一个怪物,获得50点经验");
        exp += 50;
        upgrade();
    }
    
    /**
     * 升级
     */
    private void upgrade() {
        // TODO Auto-generated method stub
        if (exp % 100 == 0) {
            this.level++;
            System.out.println("恭喜你升级了,当前等级为: " + this.level);
        }
    }

}

package com.jerry.designpattern.dynamicproxy;

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

/**
 * 
 * @author Jerry
 * @date 2015年1月21日 上午11:13:19
 */
public class GameProxy implements InvocationHandler{
    
    public Player player;
    
    public GameProxy(Player player) {
        this.player = player;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable {
        // TODO Auto-generated method stub
        System.out.println("使用游戏代理升级,一次升10级");
        for (int i = 0; i < 20; i++) {
            method.invoke(player, args);
        }
        return null;
    }
    
    public Player getInstance() {
        return (Player)Proxy.newProxyInstance(player.getClass().getClassLoader(), 
                player.getClass().getInterfaces(), 
                this);
    }

}

package com.jerry.designpattern.dynamicproxy;
/**
 * 
 * @author Jerry
 * @date 2015年1月21日 上午11:20:16
 */
public class Client {
    public static void main(String[] args) {
        Player player = new PlayerImpl();
        GameProxy gameProxy = new GameProxy(player);
        Player playerProxy = gameProxy.getInstance();
        playerProxy.killMonster();
    }
}

 

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!