您的位置:首页 > 其它

大话设计模式——代理模式

2017-08-17 23:02 197 查看

需求

小明一直暗恋着小花,想了很久,下定决心要向她表白,对她说出我爱你 :)

鉴于笔记整理需要,将原文的故事背景进行改编。

初步实现

妹子类:

public class Meizi {
private String name;

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}
}


汉子类:

public class Hanzi {
private Meizi meizi;

public Hanzi(Meizi meizi) {
this.meizi = meizi;
}

public void sayLoveToHer() {
System.out.println("I love you, " + meizi.getName() + "!");
}
}


客户端类:

public class Client {
public static void main(String[] args) {
Meizi xiaohua = new Meizi();
xiaohua.setName("小花");

Hanzi xiaoming = new Hanzi(xiaohua);
xiaoming.sayLoveToHer();
}
}


运行结果:



分析

大家都知道,现实情况小明很有可能有点害羞,不好意思直接对小花说我爱你。所以,小明想了个办法,决定让小红(小花的闺密)转述,简单来说,小红是个“僚机”。那么,这样的实现方式小红充当一个代理。

代理模式

定义:为其他对象提供一种代理以控制对这个对象的访问。通过引入一个新的对象,来实现对真实对象的操作或者将新的对象作为真实对象的一个替身。即代理对象。

结构示意图:



代理模式代码实现如下:

Subject类:定义了RealSubject和Proxy的公用接口,这样就可以在任何使用RealSubject的地方使用Proxy;

public abstract class Subject{
public abstract void request();
}


RealSubject类:定义了Proxy所代表的真实实体;

public class RealSubject extends Subject{
public void request(){
System.out.println("真实的请求");
}
}


Proxy类:保存了一个引用使得代理可以访问实体,并提供一个与Subject的接口相同的接口,这种代理就可以用来替代实体;

public class Proxy extends Subject{
private RealSubject realSubject;
public void request(){
if(realSubject != null)
realSubject = new RealSubject();
realSubject.request();
}
}


客户端代码:

public class Client {
public static void main(String[] args) {
Proxy proxy = new Proxy();
proxy.request();
}
}


再次实现

了解代理模式的实现过程,我们很容易写出运用代理模式的案例实现。小红作为代理对象,代替小明去表白,所以表白是俩者共同的功能接口,小明和小红都要去实现这个功能。

定义接口:表白

public interface IExpress {
void sayLoveToHer();
}


汉子实现接口;

public class Hanzi implements IExpress{
private Meizi meizi;

public Hanzi(Meizi meizi) {
this.meizi = meizi;
}

@Override
public void sayLoveToHer() {
System.out.println("I love you, " + meizi.getName() + "!");
}
}


代理类实现接口;

public class Proxy implements IExpress {

private Hanzi hanzi;

public Proxy(Hanzi hanzi) {
this.hanzi = hanzi;
}

@Override
public void sayLoveToHer() {
System.out.println("昨天,有个汉子和我说:");
hanzi.sayLoveToHer();
}
}


客户端。

public class Client {
public static void main(String[] args) {
Meizi xiaohua = new Meizi();
xiaohua.setName("小花");

Proxy xiaohong = new Proxy(new Hanzi(xiaohua));
xiaohong.sayLoveToHer();
}
}


运行结果



再次分析

可能已经发现了,代理对象小红如实的转达了小明的意思,那么如果小明和小红关系很好,可能小红会在小花面前多美言几句,这其实就是代理模式可以增强原本类的功能。例如,在JavaEE中,我们会通过Spring来管理Hibernate的事务,我们并没有去写开启事务、关闭事务的语句,但其实这一切都在背后帮我们做了,我们仅仅需要在Spring的配置文件中去配置好Hibernate的事务管理,其实这背后就是代理模式。

深入代理模式

上面所实现的是一般的静态代理模式,下面介绍一下JDK动态代理:

动态代理和上面静态代理实现区别就是少一个代理类Proxy的实现,而在客户端动态实现功能。

因此,可以看出静态代理在如下情况显得捉襟见肘:

代理对象的一个接口只服务于一种类型的对象,如果要代理的方法很多,势必要为每一种方法都进行代理,静态代理在程序规模稍大时就无法胜任了。

如果接口增加一个方法,除了所有实现类需要实现这个方法外,所有代理类也需要实现此方法。增加了代码维护的复杂度。

JDK动态代理实现

因为创建出来的这个代理类,一定是接口的子类,所以JDK动态代理一定要有接口,并且真实的业务类要实现该接口。

客户端代码:

public class Client {
public static void main(String[] args) {
Meizi xiaohua = new Meizi();
xiaohua.setName("小花");

IExpress xiaoming = new Hanzi(xiaohua);

IExpress xiaohong = (IExpress) Proxy.newProxyInstance(xiaoming.getClass().getClassLoader(), xiaoming.getClass().getInterfaces(), new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if(method.getName().equals("sayLoveToHer")){
System.out.println("昨天,小明和我说:");
Object obj  = method.invoke(xiaoming, args);
System.out.println("我觉得很不错,答应他吧!");
return obj;
}
return method.invoke(proxy, args);
}
});

xiaohong.sayLoveToHer();
}
}


运行结果:



最后

动态代理还有Cglib动态代理,在Spring中经常用到。Spring这个框架运用到的设计模式确实非常多,这里推荐前几日掘金上的一篇文章,关于代理模式:JAVA中的静态代理、动态代理以及CGLIB动态代理

个人公众号:每日推荐一片技术博客,坚持每日进步一丢丢…欢迎关注,想建个微信群,主要讨论安卓和Java语言,一起打基础、用框架、学设计模式,菜鸡变菜鸟,菜鸟再起飞,愿意一起努力的话可以公众号留言,谢谢…

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息