代理角色作为客户端角色和真实主题角色的中介。
例子中,我们用商店作为代理角色。
package com.secondgod.proxy;
import java.text.MessageFormat;
/\*\*
\* 商店(代理主题)
\*
\* @author 二当家的白帽子 https://le-yi.blog.csdn.net/
\*/
public class Store implements INotebookSeller {
/\*\*
\* 名称
\*/
private final String name;
/\*\*
\* 供应商品的工厂
\*/
private final NotebookFactory notebookFactory;
/\*\*
\* 合同约定按照固定量的倍数采购
\*/
private final int purchaseQuantity;
/\*\*
\* 库存
\*/
private int stockBalance;
public Store(String name, NotebookFactory notebookFactory, int purchaseQuantity) {
this.name = name;
this.notebookFactory = notebookFactory;
this.purchaseQuantity = purchaseQuantity;
System.out.println(MessageFormat.format("[{0}]的笔记本商店开业了,请笔记本工厂做了自己的供应商,他们约定每次按照[{1}]个的倍数采购。", name, purchaseQuantity));
}
@Override
public void sell(int quantity) {
if (quantity > stockBalance) {
int needPurchaseQuantity = ((quantity - stockBalance) + (purchaseQuantity - 1)) / purchaseQuantity \* purchaseQuantity;
System.out.println(MessageFormat.format("商店笔记本库存不足,于是向供应商采购了[{0}]个。", needPurchaseQuantity));
notebookFactory.sell(needPurchaseQuantity);
stockBalance += needPurchaseQuantity;
}
stockBalance -= quantity;
System.out.println(MessageFormat.format("商店卖出了[{0}]个笔记本,库存余[{1}]个。", quantity, stockBalance));
}
}
我们还需要对main方法做一点修改来引入代理角色。需要注意的是,我们的客户端角色,抽象主题角色和真实主题角色都不需要做修改。
package com.secondgod.proxy;
import java.text.MessageFormat;
/\*\*
\* 打工人
\*
\* @author 二当家的白帽子 https://le-yi.blog.csdn.net/
\*/
public class Worker {
/\*\*
\* 打工人的名字
\*/
private final String name;
public Worker(String name) {
this.name = name;
System.out.println(MessageFormat.format("打工人[{0}],为了得到自己想要的东西拼命赚钱。", name));
}
public void buy(INotebookSeller seller, int quantity) {
System.out.println(MessageFormat.format("打工人[{0}]要买[{1}]个笔记本。", name, quantity));
seller.sell(quantity);
}
private static void newDays() {
System.out.println();
System.out.println("有一天:");
}
public static void main(String[] args) {
// 打工人的故事开始了
newDays();
NotebookFactory notebookFactory = new NotebookFactory("大当家的");
INotebookSeller seller = new Store("二当家的", notebookFactory, 10);
Worker worker = new Worker("小明");
worker.buy(seller, 15);
}
}
商店作为代理,做了库存储备,这样打工人只需要在自己家楼下就能很快买到笔记本了。
但是当抽象主题,真实主题增加时,静态代理就显得不太合理了,因为它要跟着一起改变。
比如,很快又有了钢笔的卖家,和钢笔厂,商店想要代理,就需要做出改变,之后每次要代理卖新的东西,商店都要做出调整,商店不开心了。
动态代理的出现
商店做大做强后,发现其实各种卖家和工厂都有着一些共性,而客户端也有着相似的需求,所以商店决定成立一个平台,想办法统一流程。
引入新的抽象主题,钢笔卖家。
package com.secondgod.proxy;
/\*\*
\* 钢笔卖家(抽象主题角色)
\*
\* @author 二当家的白帽子 https://le-yi.blog.csdn.net/
\*/
public interface IPenSeller {
/\*\*
\* 卖钢笔
\*
\* @param quantity
\*/
void sell(int quantity);
}
引入新的真实主题,钢笔工厂。
package com.secondgod.proxy;
import java.text.MessageFormat;
/\*\*
\* 钢笔工厂(真实主题)
\*
\* @author 二当家的白帽子 https://le-yi.blog.csdn.net/
\*/
public class PenFactory implements IPenSeller {
/\*\*
\* 厂长名
\*/
private final String name;
public PenFactory(String name) {
this.name = name;
System.out.println(MessageFormat.format("[{0}]的钢笔工厂开业了。", name));
}
@Override
public void sell(int quantity) {
System.out.println(MessageFormat.format("[{0}]卖掉[{1}]个钢笔。", name, quantity));
}
}
引入新的代理,电商平台,很快我们就可以看到动态代理相对于静态代理的优势。
package com.secondgod.proxy;
import java.lang.reflect.Proxy;
import java.text.MessageFormat;
import java.util.HashMap;
import java.util.Map;
/\*\*
\* 平台
\*
\* @author 二当家的白帽子 https://le-yi.blog.csdn.net/
\*/
public class Platform {
/\*\*
\*
\*/
private final String name;
/\*\*
\* 平台下的卖家
\*/
private final Map<Class<?>, Object> storeMap = new HashMap<>();
public Platform(String name) {
this.name = name;
System.out.println(MessageFormat.format("[{0}]的电商平台开业了。", name));
}
/\*\*
\* 供普通卖家注册为平台卖家
\*
\* @return
\*/
public <T> void registerStore(String name, Class<T> clazz, T factory, int purchaseQuantity) {
T seller = (T) Proxy.newProxyInstance(this.getClass().getClassLoader(), new Class<?>[]{clazz}, new PlatformStore(name, this, factory, purchaseQuantity));
storeMap.put(clazz, seller);
}
/\*\*
\* 供用户查找
\*
\* @return
\*/
public <T> T findStore(Class<T> clazz) {
return (T) storeMap.get(clazz);
}
}
平台化以后,商店也要有所改变。
package com.secondgod.proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.text.MessageFormat;
/\*\*
\* 平台店
\*
\* @author 二当家的白帽子 https://le-yi.blog.csdn.net/
\*/
public class PlatformStore implements InvocationHandler {
/\*\*
\* 商品名
\*/
private final String name;
/\*\*
\* 平台
\*/
private final Platform platform;
/\*\*
\* 背后是真实卖家
\*/
private final Object factory;
/\*\*
\* 合同约定按照固定量的倍数采购
\*/
private final int purchaseQuantity;
/\*\*
\* 库存
\*/
private int stockBalance;
public PlatformStore(String name, Platform platform, Object factory, int purchaseQuantity) {
this.name = name;
this.platform = platform;
this.factory = factory;
this.purchaseQuantity = purchaseQuantity;
System.out.println(MessageFormat.format("平台的[{0}]商店开业了,请[{1}]工厂做了自己的供应商,他们约定每次按照[{2}]个的倍数采购。", name, name, purchaseQuantity));
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
int quantity = (int) args[0];
if (quantity > stockBalance) {
int needPurchaseQuantity = ((quantity - stockBalance) + (purchaseQuantity - 1)) / purchaseQuantity \* purchaseQuantity;
System.out.println(MessageFormat.format("平台[{0}]库存不足,于是向供应商采购了[{1}]个。", name, needPurchaseQuantity));
args[0] = needPurchaseQuantity;
method.invoke(factory, args);
stockBalance += needPurchaseQuantity;
}
stockBalance -= quantity;
System.out.println(MessageFormat.format("平台卖出了[{0}]个[{1}],库存余[{2}]个。", quantity, name, stockBalance));
return null;
}
}
接下来就是我们的买方,他除了想要买笔记本,也想要买钢笔了。main方法将描绘一个新的故事。
package com.secondgod.proxy;
import java.text.MessageFormat;
/\*\*
\* 打工人
\*
\* @author 二当家的白帽子 https://le-yi.blog.csdn.net/
\*/
public class Worker {
/\*\*
\* 打工人的名字
\*/
private final String name;
public Worker(String name) {
this.name = name;
System.out.println(MessageFormat.format("打工人[{0}],为了得到自己想要的东西拼命赚钱。", name));
}
public void buy(INotebookSeller seller, int quantity) {
System.out.println(MessageFormat.format("打工人[{0}]要买[{1}]个笔记本。", name, quantity));
seller.sell(quantity);
}
public void buy(IPenSeller seller, int quantity) {
System.out.println(MessageFormat.format("打工人[{0}]要买[{1}]个钢笔。", name, quantity));
seller.sell(quantity);
}
private static void newDays() {
System.out.println();
System.out.println("有一天:");
}
public static void main(String[] args) {
// 打工人的故事开始了
newDays();
Platform platform = new Platform("二当家的");
platform.registerStore("笔记本", INotebookSeller.class, new NotebookFactory("大当家的"), 100);
platform.registerStore("钢笔", IPenSeller.class, new PenFactory("大当家的"), 100);
INotebookSeller notebookSeller = platform.findStore(INotebookSeller.class);
IPenSeller penSeller = platform.findStore(IPenSeller.class);
Worker worker = new Worker("小明");
worker.buy(notebookSeller, 10);
worker.buy(penSeller, 10);
}
}
以后,再开别的工厂,买方想再买别的什么东西,平台都不需要修改了。这就是动态代理的魅力,也是平台化的魅力。
回顾动态代理的使用
静态代理是在编码阶段就确定的;而动态代理则是在程序运行时才动态创建。
在程序运行时去动态创建类,显然普通的方式是无法做到的,JDK为我们提供了API,就是在java.lang.reflect包下的Proxy类,我们的例子中使用了他的newProxyInstance静态方法,他的方法签名如下。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上大数据知识点,真正体系化!
由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新
oxy类,我们的例子中使用了他的newProxyInstance静态方法,他的方法签名如下。
[外链图片转存中…(img-FQMotX8s-1714631086291)]
[外链图片转存中…(img-1IUVdmUI-1714631086291)]
[外链图片转存中…(img-Uc1B8tDq-1714631086291)]
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上大数据知识点,真正体系化!
由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新