从坦克聊聊代理模式之静态代理

本文可作为北京尚学堂代理模式课程的学习笔记


    首先请大家忘记题目上所说的代理模式 咱们一步一步来

     首先有一个坦克 它能跑

package proxy;

public class Tank {

	public void move() {
		// TODO Auto-generated method stub
		System.out.println("i can move...");
	}
}
package proxy;

public class Client {
	public static void main(String[] args) {
		Tank t=new Tank();
		t.move();
	}

}
考虑到针对接口编程 我们为坦克提炼出一个接口IMoveable 里面就一个方法move如下 让tank实现它即可

package proxy;

public interface Imoveable {
	void move();
}
package proxy;

public class Client {
	public static void main(String[] args) {
		IMoveable t=new Tank();
		t.move();
	}

}



现在的问题是 我想在坦克move前后做一点工作 如在move前打印出time start 后面打印出time end

大家暂时不要想任何高级模式什么  就简单来

大家想到的第一个方法应该是给i can move前后直接加代码

这个很简单 也很容易想到 但是违反了开闭原则

再想想其它办法 继承

package proxy;

public class Tank2 extends tank {

	public void move() {
		// TODO Auto-generated method stub
            System.out.println("time start");
            super.move();
            System.out.println("time end"); 
       }
  }
     

 
 

在client调用的时候 只用把new tank()改成new tank2();即可

还有一种方法就是 我再新建一个类  实现IMoveable接口

package proxy;

public class ProxyTimeTank  implements Imoveable{

	private Imoveable tank;
	
	public ProxyTimeTank(Imoveable move){
		tank=move;
	}
	@Override
	public void move() {
		// TODO Auto-generated method stub
		System.out.println("time start");
		tank.move();
		System.out.println("time end");
	}
}
这个类里面"有一个"tank

所以这种方法的client

package proxy;

public class Client {
	public static void main(String[] args) {
		Imoveable tank=new Tank();
		Imoveable t=new ProxyTimeTank(tank);
		t.move();
	}

}
这种方法其实就是代理模式

    Proxy Pattern,23种java常用设计模式之一。代理模式的定义:为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。                            

从坦克聊聊代理模式之静态代理_第1张图片

                                                                                        -------------摘自百度百科

仔细考虑上述三种方法

第一种改tank类 直接加代码 违法开闭原则 

第二种让一个新的类tank2继承tank 我们在tank2上做修改 不违法开闭原则

第三种让一个新的类ProxyTimeTank实现了IMoveable接口 我们修改新的类

第一种方法太差 我们不考虑 第二种第三种似乎差不多

那么 请问如果我想记下日志呢 在坦克移动前打印log start 移动后打印log end

我还想 检测权限在坦克移动前 打印check start 移动后打印check end

(我们将记录时间 日志 检测权限都精简成一条语句)

怎么办? 按照继承的方法 tank3继承tank2 让tank3记录日志

同时tank4继承tank3 让tank4 检查权限

......

这样一来如果我有n重业务 我就有个n重的继承链

这还不是最麻烦的

最麻烦的是 假如我想先记录日志 在记录时间 再检查权限 怎么办?

如果我想先记录时间 再记录日志 最后检查权限 又如何 我们只能修改继承链

所以在这个问题上  A is B 的继承思路不合适 我们可以采用 A has B的方法 来操作

具体如何做? 看下面

package proxy;

public class ProxyLogTank implements Imoveable{
    private Imoveable tank;
    
    public ProxyLogTank(Imoveable moveable){
        tank=moveable;
    }

    @Override
    public void move() {
        // TODO Auto-generated method stub
        System.out.println("log start");
        tank.move();
        System.out.println("log end");
    }
    
}
这个类与TimeProxyTank相似 其实新的检查权限的类与这个它也相似

麻烦的是 我们如何随意调换 这几个业务的顺序?

如何大家没有装饰模式的概念 可以在网上百度一下相关资料

也可以查阅拙作 从咖啡谈装饰模式

client如下

package proxy;

public class Client {
	public static void main(String[] args) {
		Imoveable tank=new Tank();
		Imoveable tankTime=new ProxyTimeTank(tank);
		Imoveable t=new ProxyLogTank(tankTime);
		t.move();
	}
}
结果如下

log start
time start
i can move...
time end
log end

问题 搞定 其实如果只对目标对象加一种业务逻辑 也就用不上 装饰模式了

car也可以移动 我们这个代理模式依然可以用

准确的说 我们的一组proxy类(time log等等)可以负责一个实现了同一个接口的多种类

如果 我想看看一个人 他可以吃饭 我想对吃饭 做time log等的记录 该怎么办?

再写一组proxy类? 不嫌麻烦么?

请看下一篇  动态代理


你可能感兴趣的:(java,设计模式,jdk,代理模式,interface)