Hi,我是十三,是不是越长大就更难做到坚持…
前言
自从上次十三有了女神闺蜜的情报,十三最后是否成功抱得美人归呢?这可能是个谜,因为写这篇文章的十三自己都不知道呢,嘿嘿。好吧,说着说着话题都偏了…不知道十三在说啥的同学,请到传送门接受安检 十三校园泡妞记。
有了闺蜜的精准情报,十三每次自然不会扑空,只是当十三想要上去搭讪或是有进一步动作的时候,十三就怂了,没错,怂了。他害怕又感些许自卑,可又担心这样下去会失去,就这样一直循环重复,就连卧底闺蜜都抱怨十三太怂了,嚷嚷着不提供情报了,可每次看到十三那一脸痴情样又叹了口气。
某天晚上,十三手捧着束花,他动作熟练地打开手机微信,发了条信息,上面写着:“恩人阿恩人,我在你楼下帮我送束花给她吧,您的大恩大德永不忘!”,没过多久,对方回信:“可以啊,还懂得送花了,开窍了,不过自己送。”,原来十三想送花给女神,可他又不好意思当面送,看来十三是真的怂…只好委托她闺蜜帮他送花了,只是人家并不答应他,最后还是十三提出请她吃大餐才答应送花的…
注意,这里开始可是要画风突变了,上面这个委托送花过程其实可以用到个设计模式,它便是代理模式,好,接下来我们一起来看看代理模式的介绍。
代理模式 (Proxy)
代理模式也被称为委托模式,它是结构型设计模式的一种。在我们平时日常生活中类似代理模式的场景也非常常见,比如说请律师代理打官司、代理工具上网等等。
定义:为其他对象提供一种代理以控制对这个对象的访问.
代理模式中的角色及职责 :
-
Subject : 抽象主题类,声明真实主题与代理的共同接口方法.
-
RealSubject : 真实主题类,代理类所代表的真实主题,客户端通过代理类间接地调用真实主题类的方法.
-
Proxy : 代理类,持有对真实主题类的引用,在其所实现的接口方法中调用真实主题类中相应的接口方法执行.
学了就要用,接下来我们把上面十三委托送花的事用代理模式简单实现下:
public interface GiveGift{
public void GiveFlowers();
}
首先我们先定义了一个抽象主题接口,抽象主题类它具有真实主题类和代理的共同接口方法,而这个共同方法就是送花了,所以在里面提供了 GiveFlowers 这个方法,继续往下看 :
public class Pursuit implements GiveGift {
private String girlName;
private String boyName;
public Pursuit(String girlName, String boyName) {
this.girlName = girlName;
this.boyName = boyName;
}
@Override
public void GiveFlowers() {
System.out.println(girlName + "," + boyName + "送你花耶!");
}
}
然后我们定义了个追求者类,它实现了抽象主题类并重写接口里面的方法,实际上,它是代理模式中真实主题类这个角色,在送花这里十三无疑便是这个角色了。
public class Proxy implements GiveGift {
private String proxyName;
Pursuit pursuit;
public Proxy(String proxyName, String girlName, String boyName) {
this.proxyName = proxyName;
pursuit = new Pursuit(girlName, boyName);
}
@Override
public void GiveFlowers() {
System.out.print(proxyName + ":");
pursuit.GiveFlowers();
}
}
接下来就是代理类了,它同样也是实现了抽象主题接口,我们可以看到它持有对真实主题类的引用,并在重写的接口方法中调用真实主题类重写的接口方法,也就是说,闺蜜代理帮十三完成送花这个动作,之所以通过调用真实主题类重写的方法,是因为这是十三委托我们的闺蜜帮他送花。
public class Client {
public static void main(String[] args) {
Subject proxy = new Proxy("LL闺蜜", "LL", "十三");
proxy.GiveFlowers();
}
}
LL闺蜜:LL,十三送你花耶!
客户端的代码非常简单,我们直接通过代理对象并调用相关方法就完成了送花这个动作,最终调用的是真实主题类里实现的方法,我们这里就成功使用代理模式做了个简单实现。
事实上上面我们写的例子是静态代理,代理模式主要分为静态代理和动态代理。静态代理在代码运行前就已经存在了代理类的 class 编译文件;动态代理则是在运行时通过反射来动态生成代理类的对象,并确定是谁来代理。
动态代理
既然静态代理我们上面已经实现过了,那么这个动态代理应该怎么来做呢?别急,JDK 提供了相关的类库供我们使用,InvocationHandler 是代理实例的调用程序实现的接口,实现了该接口需要重写 invoke() 方法,那么下面我们用十三送花这个例子来实现动态代理 :
public class DynamicProxy implements InvocationHandler {
private Object object;
public DynamicProxy(Object object) {
this.object = object;
}
// 在代理实例上处理方法调用并返回结果
@Override
public Object invoke(Object proxy, Method method, Object[] arg) throws Throwable {
Object result = method.invoke(object, arg);
return result;
}
}
首先我们先声明了一个 Object 对象,它指向引用与真实主题类,也就是被代理类,紧接着我们在重写的 invoke 方法中去调用执行被代理类的具体方法。
public class Client {
public static void main(String[] args) {
Subject realSubject = new Pursuit("LL", "十三");
DynamicProxy mDynamicProxy = new DynamicProxy(realSubject);
ClassLoader loader = Pursuit.class.getClassLoader();
Subject dynamicProxy = (Subject) java.lang.reflect.Proxy.
newProxyInstance(loader, new Class[]{Subject.class}, mDynamicProxy);
dynamicProxy.GiveFlowers();
}
}
最后我们得要在客户端调用 Proxy.newProxyInstance() 方法来生成动态代理类,接着通过它去调用 GiveFlowers() 方法,而它则会去调用上面我们写的 DynamicProxy 类中的 invoke 方法,这样我们便简单完成了动态代理。
LL,十三送你花耶!
## 总结 ##
那么到最后我们来简单总结下 :
使用场景 (通过网络搜索,一般分下面几种):
-
远程代理,也就是为一个对象在不同的地址空间提供局部代表,这样便于隐藏.
-
虚拟代理,根据需要创建开销很大的对象,通过它来存放实例化需要很长时间的真实对象.
-
安全代理,用来控制真实对象访问时的权限.
-
智能指引,当调用真实对象时,代理处理另外一些事.
优点 :
-
真实主题类只需关心本职工作.
-
即使真实主题类发生变化,代理类仍然不受影响,因为真实主题类实现了公共接口.
这里来张代理模式的合照,一 二 三,茄子 :
后话
后来,LL 收到了十三送的花,其实 LL 知道十三喜欢她,因为闺蜜已经把什么都和她说了…LL 拿着花并轻轻说了句:“呆子!“。我 TM 编故事真累…
更好的阅读体验请移步到【十三的个人博客】:https://binshao.site/