代理模式


23种设计模式

1.什么是代理模式

代理这个词在生活中也很多。
最经典的一个就是在香港的警匪片中,反派老大被抓到警察局,然后反派老大说,我什么都不会交代,和我的律师说吧。
此时,律师就是反派老大在与警察交涉过程中的代理人。
还有一种情况就是反派老大管理的地盘太大,有些管理不过来,于是就设立了一个个的代理人。
不过,不管怎么样,当其他的反派老大拜访时,老大还是需要亲自招待的。
总结一下:代理就是一方面是补充本体不足,另一方面分担本体工作。
而有些事情只能由本体完成。

2.代理模式的角色

抽象的共同的操作
本体
代理人
调用者

3.例子

3.1 背景

相信每一个人都去过超市,或者商场等等。
所以呢,每一个人都会购物。
那么购物的步骤是怎么样的?
看到商品,先看看是不是自己需要的东西,然后看下商品的价格,与卖家砍砍价,最后成交。

大型的商场都有导购员,当你在看某件商品时,导购员就会介绍商品的有关信息。如果你接受导购员的服务,那么在这一时间内,导购员只会为你服务,不过,不管导购员如何诱惑,买不买还是买家的决定。

情况比较紧急或者商品不允许挑选(类似药品等特殊品)时,买家只需要付款就行。(还没见过砍价砍到药店的人才。。。。)

3.2 例子结构

23种设计模式----代理模式----结构型模式_代理模式

3.3 抽象的共同的方法

package proxyable;

/**
*
* 到超时买东西必备的技能
* 1.东西的名称
* 2.买家的名称
* 3.问价格
* 4.砍价
* 5.成交
*
*
*/
public interface BuySomething {

String getThingName();

String getBuyerName();

void setBuyerName(String buyerName);

int getThingPrice(String thingName);

int bargainirg(String thingName,String buyerName);

void deal(String thingName,String buyerName);

}

3.4 导购

package proxy;

import proxyable.BuySomething;

/**
*
* 从某种程度上来说,导购就是买家的一个代理人
*
*/
public class Guide implements BuySomething{

private String buyerName;

private BuySomething buySomething;

public Guide(String buyName) {
this.buyerName = buyName;
}

@Override
public String getThingName() {
System.out.println("导购熟悉超市环境,获取商品名称的速度比买家快");
return "thingName";
}

@Override
public void setBuyerName(String buyerName) {
System.out.println("导购需要明确的知道,自己服务的买家是谁"+buyerName);
if(buySomething == null){
try{
buySomething = create(buyerName);
} catch (Exception e){
e.printStackTrace();
}
}
buySomething.setBuyerName(buyerName);
this.buyerName = buyerName;
}

@Override
public int getThingPrice(String thingName) {
System.out.println("导购询问价格一般都比较贵");
return 100;
}

@Override
public int bargainirg(String thingName, String buyerName) {
System.out.println("导购砍价几乎是象征性的砍价");
return 0;
}

/**
* 被代理者无法替代的工作
*/
@Override
public void deal(String thingName, String buyerName) {
System.out.println("不管导购多么的努力,决定权还是在买家身上");
if(buySomething == null){
try {
buySomething = create(buyerName);
} catch (Exception e){
e.printStackTrace();
}
}
buySomething.deal(thingName, buyerName);
}

private synchronized BuySomething create(String buyerName) throws InstantiationException, IllegalAccessException, ClassNotFoundException{
return (BuySomething) Class.forName("real."+buyerName).newInstance();
}

@Override
public String getBuyerName() {
return this.buyerName;
}

}

3.5 买家

package real;

import proxyable.BuySomething;

public class Buyer implements BuySomething{

private String name;

@Override
public String getThingName() {
System.out.println("买家不熟悉超市的环境,所以获取商品的名称比较慢");
return "thingName";
}

@Override
public int getThingPrice(String thingName) {
System.out.println("买家询问价格同样贵");
return 100;
}

@Override
public int bargainirg(String thingName, String buyerName) {
System.out.println("买家砍价比较狠");
return 10;
}

@Override
public void deal(String thingName, String buyerName) {
System.out.println("买家经过长时间的考虑,最终决定买下来");
}

@Override
public void setBuyerName(String buyerName) {
System.out.println("现在的操作人"+buyerName);
this.name = buyerName;
}

@Override
public String getBuyerName() {
return this.name;
}

}

3.6 调用者

package client;

import proxy.Guide;
import proxyable.BuySomething;

public class Main {

public static void main(String[] args) {

System.out.println("逛超市吧");
System.out.println("导购全权购买");
BuySomething buySomething = new Guide("Guide");
System.out.println(buySomething.getThingName());
System.out.println(buySomething.getBuyerName());
System.out.println(buySomething.getThingPrice(buySomething.getThingName()));
System.out.println(buySomething.bargainirg(buySomething.getThingName(),
buySomething.getBuyerName()));
buySomething.deal(buySomething.getThingName(), "Buyer");

System.out.println("导购帮助选购,本人砍价,购买");
System.out.println(buySomething.getThingName());
System.out.println(buySomething.getBuyerName());
System.out.println(buySomething.getThingPrice(buySomething.getThingName()));
buySomething.setBuyerName("Buyer");
System.out.println(buySomething.bargainirg(buySomething.getThingName(),
buySomething.getBuyerName()));
buySomething.deal(buySomething.getThingName(), buySomething.getBuyerName());

System.out.println("本人出马");
buySomething.setBuyerName("Buyer");
System.out.println(buySomething.getThingName());
System.out.println(buySomething.getBuyerName());
System.out.println(buySomething.getThingPrice(buySomething.getThingName()));
System.out.println(buySomething.bargainirg(buySomething.getThingName(),
buySomething.getBuyerName()));
buySomething.deal(buySomething.getThingName(), buySomething.getBuyerName());

}

}

3.7 结果

逛超市吧
导购全权购买
导购熟悉超市环境,获取商品名称的速度比买家快
thingName
Guide
导购熟悉超市环境,获取商品名称的速度比买家快
导购询问价格一般都比较贵
100
导购熟悉超市环境,获取商品名称的速度比买家快
导购砍价几乎是象征性的砍价
0
导购熟悉超市环境,获取商品名称的速度比买家快
不管导购多么的努力,决定权还是在买家身上
买家经过长时间的考虑,最终决定买下来
导购帮助选购,本人砍价,购买
导购熟悉超市环境,获取商品名称的速度比买家快
thingName
Guide
导购熟悉超市环境,获取商品名称的速度比买家快
导购询问价格一般都比较贵
100
导购需要明确的知道,自己服务的买家是谁Buyer
现在的操作人Buyer
导购熟悉超市环境,获取商品名称的速度比买家快
导购砍价几乎是象征性的砍价
0
导购熟悉超市环境,获取商品名称的速度比买家快
不管导购多么的努力,决定权还是在买家身上
买家经过长时间的考虑,最终决定买下来
本人出马
导购需要明确的知道,自己服务的买家是谁Buyer
现在的操作人Buyer
导购熟悉超市环境,获取商品名称的速度比买家快
thingName
Buyer
导购熟悉超市环境,获取商品名称的速度比买家快
导购询问价格一般都比较贵
100
导购熟悉超市环境,获取商品名称的速度比买家快
导购砍价几乎是象征性的砍价
0
导购熟悉超市环境,获取商品名称的速度比买家快
不管导购多么的努力,决定权还是在买家身上
买家经过长时间的考虑,最终决定买下来

4.总结

大概有一下几点:
首先对于一些方法,代理相当于是透明的,比如上述例子中的setBuyerName方法和deal方法,不管调用的是代理的方法还是本体的方法,最后都是调用本体的方法。所以代理在这两个方法中就相当于是透明的。

至于透明的实现方式,是通过委托来实现的。
可以很清楚的知道,每一个代理都会持有一个本体的对象,当遇到代理无法完成的操作时,代理就会创建本体的对象,然后把操作交给本体完成。

当代理和反射之间的关系非常的复杂或者调用非常的频繁时,可以使用反射的方式。比如在例子中,新增一个本体,只需要重新写一个本体的类就行,调用的时候设置名字就是类名就ok。可以无限的复用代理类。

同样的由于代理类持有的是接口,而接口代理与本体都需要实现方法,所以,新增一个代理可以使用原来的本体。

这样就做到本体与代理相互补充,无限扩充。

考虑到多线程或者多个代理需要创建同一个本体的情况,代理创建本体的方法应该用synchronized关键词修饰。

还有就是创建一个对象比较费时,使用代理可以先处理代理能够处理的操作,只有等到需要本体执行特定的操作时,才创建本体对象。
所以使用代理可以实现懒加载,懒创建等等,加快加载的速度。​