代理模式

1.什么是代理模式

代理模式给某一个对象提供一个代理对象,并由代理对象控制对原对象的引用。通俗的来讲代理模式就是我们生活中常见的中

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

2什么时候使用代理模式

当一个类不想或者不能直接引用一个委托对象,而代理类对象可以在客户类和委托对象之间起到中介的作用,其特征是代理类和

委托类实现相同的接口

3.代理模式的扩展种类

代理模式总共分三类分别是普通代理、强制代理、动态代理前两种也叫静态代理

通用类图

1.普通代理

下面以游戏升级打怪为例子,我们可以花钱找代练帮我们干刷怪升级这些枯燥的事,而我们就可以完全沉浸在PK与帮派战争的快乐中代码如下

1.创建游戏接口 定义三个方法 分别是登录 、杀怪、 升级

/**
 * JC2
 */
public interface IGamePlayer {

    void login(String user);

    void killBoss();

    void updategrade();
}

 2.创建玩家类

/**
 * JC2
 */
public class GamePlayer implements IGamePlayer {

    private String name = "";

    public GamePlayer(IGamePlayer iGamePlayer,String name){
        if(null==iGamePlayer){
            try {
                throw new Exception();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }else{
            this.name = name;
        }
    }
    @Override
    public void login(String user) {
        System.out.println(user+":"+this.name+"登录了");
    }

    @Override
    public void killBoss() {
        System.out.println(this.name+"刷怪");
    }

    @Override
    public void updategrade() {
        System.out.println(this.name+"升级");
    }
}

 3.创建代练类 

/**
 * JC2
 */
public class GamePlayerPoxy implements IGamePlayer {

    private IGamePlayer iGamePlayer = null;

    public GamePlayerPoxy(String name){
        iGamePlayer = new GamePlayer(this,name);
    }

    @Override
    public void login(String user) {
        this.iGamePlayer.login(user);
    }

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

    @Override
    public void updategrade() {
        this.iGamePlayer.updategrade();
    }
}

 4.场景类

/**
 * JC2
 */
public class ProxyMain {
    public static void main(String[] args) {
        //普通代理
        GamePlayerPoxy gamePlayerPoxy = new GamePlayerPoxy("张三");
        gamePlayerPoxy.login("l57418460");
        gamePlayerPoxy.killBoss();
        gamePlayerPoxy.updategrade();
    }
}

5.打印结果

l57418460:张三登录了
张三刷怪
张三升级

 

2.强制代理

1.还是创建游戏接口 定义三个方法 分别是登录 、杀怪、 升级再加一个getproxy()方法

/**
 * JC2
 */
public interface IGamePlayer {

    void login(String user);

    void killBoss();

    void updateGraed();

    IGamePlayer getproxy();
}

2.定义玩家类 实现游戏接口 定义私有方法isProxy用于判断执行方法时是否是当前代理

/**
 * JC
 */
public class GamePlayer implements IGamePlayer {

    private String name = "";

    private IGamePlayer gamePlayerProxy = null;

    public GamePlayer(String name){
        this.name = name;
    }
    @Override
    public void login(String user) {
        if(this.isPoxy()){
            System.out.println(user+":"+this.name+"上线了");
        }else{
            System.err.println("请使用指定代理访问");
        }

    }

    @Override
    public void killBoss() {
        if(this.isPoxy()){
            System.out.println(name+"杀怪");
        }else{
            System.err.println("请使用指定代理访问");
        }
    }

    @Override
    public void updateGraed() {

        if(this.isPoxy()){
            System.out.println(name+"升级");
        }else{
            System.err.println("请使用指定代理访问");
        }
    }

    @Override
    public IGamePlayer getproxy() {
        this.gamePlayerProxy = new GamePlayerPoxy(this);
        return this.gamePlayerProxy;
    }

    private boolean isPoxy(){
        if(null==this.gamePlayerProxy){
            return false;
        }else{
            return true;
        }
    }
}

 3.创建一个代理接口用于在代码中插入执行逻辑

/**
 * JC2
 */
public interface Iproxy {
    void count();
}

4.创建玩家代理类实现游戏类及代理类,在updateGraed()方法执行完成插入一段执行逻辑

/**
 * JC
 */
public class GamePlayerPoxy implements IGamePlayer ,Iproxy{

    private IGamePlayer gamePlayer = null;

    public GamePlayerPoxy(IGamePlayer iGamePlayer){
        this.gamePlayer = iGamePlayer;
    }

    @Override
    public void login(String user) {
        this.gamePlayer.login(user);
    }

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

    @Override
    public void updateGraed() {
        this.gamePlayer.updateGraed();
        this.count();
    }

    @Override
    public IGamePlayer getproxy() {
        return this;
    }

    @Override
    public void count() {
        System.out.println("升级共需要150");
    }
}

5.场景类

/**
 * JC2
 */
public class ConstraintProxyMain {
    public static void main(String[] args) {
        //强制代理
        GamePlayer gamePlayer = new GamePlayer("李四");
        IGamePlayer iGamePlayerPoxy = gamePlayer.getproxy();
        iGamePlayerPoxy.login("l8323881");
        iGamePlayerPoxy.killBoss();
        iGamePlayerPoxy.updateGraed();
    }
}

6.执行结果

l8323881:李四上线了
李四杀怪
李四升级
升级共需要150

7.这样就必须使用玩家类指定的代理如果不使用GamePlayer里面的getProxy方法而是自己创建一个代理如下

/**
 * JC2
 */
public class ConstraintProxyMain {
    public static void main(String[] args) {
        //强制代理
        GamePlayer gamePlayer = new GamePlayer("李四");
        GamePlayerPoxy GamePlayerPoxy = new GamePlayerPoxy(gamePlayer);
        GamePlayerPoxy.login("l8323881");
        GamePlayerPoxy.killBoss();
        GamePlayerPoxy.updateGraed();
    }
}

 8.运行结果

请使用指定代理访问
请使用指定代理访问
请使用指定代理访问

3.动态代理

JDK已经提供了动态代理接口 InvocationHandler 我门只需要实现此接口就可以使用动态代理

1.还以游戏为例 创建一个游戏接口

/**
 * JC2
 */
public interface IGamePlayer {

    void login(String user);

    void killBoss();

    void updateGraed();

}

2.创建玩家类实现游戏类 这次不需要依赖代理类

/**
 * JC2
 */
public class GamePlayer implements IGamePlayer {

    private String name = "";

    public GamePlayer(String name){
        this.name = name;
    }
    @Override
    public void login(String user) {
        System.out.println(user+":"+this.name+"登录了");
    }

    @Override
    public void killBoss() {
        System.out.println(this.name+"刷怪");
    }

    @Override
    public void updateGraed() {
        System.out.println(this.name+"升级");
    }
}

 3.创建一个代理类实现InvocationHandler 接口 并重写其invoke方法

/**
 * JC2
 */
public class GamePlayIH implements InvocationHandler {
    //被代理者
    Object obj ;

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

        return method.invoke(this.obj,args);
    }
}

4.创建动态代理类  添加静态方法newProxyInstance  

Proxy.newProxyInstance 该方法可以帮助我们生成一个对象,参数为 目标对象的类加载器、目标对象的接口(gamePlayer.getClass().getInterfaces()找到该类的所有接口并实现这些接口的所有方法)、InvocationHandler(目标对象) 类型

/**
 * JC2
 */
public class DynamicProxy {
    public static <T> T newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h){
        return (T)Proxy.newProxyInstance(loader,interfaces, h);
    }
}

5.场景类

/**
 * JC2
 */
public class DynamicProxyMain {
    public static void main(String[] args) {
        IGamePlayer gamePlayer= new GamePlayer("王五");
        GamePlayIH gamePlayIH = new GamePlayIH(gamePlayer);
        IGamePlayer gamePlayerProxy = (IGamePlayer)DynamicProxy.newProxyInstance(gamePlayer.getClass().getClassLoader(),gamePlayer.getClass().getInterfaces(),gamePlayIH);
        gamePlayerProxy.login("王五");
        gamePlayerProxy.killBoss();
        gamePlayerProxy.updateGraed();
    }
}

6.运行结果

王五:王五登录了
王五刷怪
王五升级

4.扩展(AOP的实现)

1.创建一个Subject接口定义两个方法 我们目标是要在其中一个方法前后执行一段逻辑(相当于上面案例的游戏接口)

/**
 * JC2
 */
public interface Subject {
    void doSomthing(String str);
    void doSomthing1(String str);
}

2.实现该接口(相当于上面案例的玩家类)

/**
 * JC2
 */
public class RealSubject implements Subject {
    @Override
    public void doSomthing(String str) {
        System.out.println("doSomthing------------->"+str);
    }

    @Override
    public void doSomthing1(String str) {
        System.out.println("doSomthing1------------->"+str);
    }
}

3.创建通知接口用于植入逻辑

/**
 * JC2
 */
public interface IAdvice {
    public void exec();
}

4.添加前置 后置实现

/**
 * JC2
 */
public class BeforeAdvice implements IAdvice{
    @Override
    public void exec() {
        System.out.println("我是前置通知 我被执行了");
    }
}
/**
 * JC2
 */
public class AfterAdvice implements IAdvice{
    @Override
    public void exec() {
        System.out.println("我是后置通知 我被执行了");
    }
}

5.创建代理类实现InvocationHandler

/**
 * JC2
 */
public class MyInvocationHandler implements InvocationHandler {

    private Object object;
    private String methodName;

    public MyInvocationHandler(Object object,String methodName){
        //暂时不考虑入参null值问题
        this.object = object;
        this.methodName = methodName;
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Object retVal = null;
        if(methodName.equals(method.getName())){
            //暂不考虑方法重载问题可以通过获取方法的参数来解决
            // method.getParameterAnnotations();
            (new BeforeAdvice()).exec();
            retVal = method.invoke(object,args);
            (new AfterAdvice()).exec();
        }else{
            retVal = method.invoke(object,args);
        }

        return retVal;
    }
}

6.创建动态代理类

/**
 * JC2
 */
public class DynamicProxy {
    public static <T> T newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h){
        return (T)Proxy.newProxyInstance(loader,interfaces, h);
    }
}

7.场景类为 doSomthing1()前后植入逻辑

/**
 * JC2
 */
public class DynamicProxyMain {
    public static void main(String[] args) {
        Subject subject = new RealSubject();
        InvocationHandler invocationHandler = new MyInvocationHandler(subject,"doSomthing1");
        Subject proxy = DynamicProxy.newProxyInstance(subject.getClass().getClassLoader(),subject.getClass().getInterfaces(),invocationHandler);
        proxy.doSomthing("proxy is doing");
        proxy.doSomthing1("proxy1 is doing");
    }
}

8.执行结果

doSomthing------------->proxy is doing
我是前置通知 我被执行了
doSomthing1------------->proxy1 is doing
我是后置通知 我被执行了

总结

普通代理

调用者只知道代理而不知道真实主体角色是谁  而真实主体角色可以随意修改而不和高层代码耦合,适合扩展性要求高的场景

但必须得通过编程规范约定来禁止new真实主体

强制代理

强制通过创建真实主体获取到代理 通过代理或者直接new主体角色都不能访问,只有通过真实主体指定的代理类才能访问可以

不知道代理的存在 代理的管理由真实角色自己完成

动态代理

通常情况下代理的职责并不单一为了让一个代理类代理多个主体角色并断开主体角色与代理的耦合关系扩展出了动态代理

要实现动态代理的首要条件是:被代理类必须实现一个接口。现在也有很多技术如CGLIB可以实现不需要接口也可以实现动态代

理的方式

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值