代理模式: 为其他对象提供一种代理,并以控制对这个对象的访问。
运用代理模式,为简单的计算器添加数字的验证,防止输入数字以外的东西。
静态代理模式:
Operation.java 体类和代理类共用接口
public interface Operation {
public BigDecimal operationAdd(String numberA, String numberB);
public BigDecimal operationDivide(String numberA, String numberB);
public BigDecimal operationMultiply(String numberA, String numberB);
public BigDecimal operationSubtract(String numberA, String numberB);
}
Operation.java 真实的计算功能类
public class RealOperation implements Operation {
@Override
public BigDecimal operationAdd(BigDecimal numberA, BigDecimal numberB) {
BigDecimal result = null;
result = numberA.add(numberB);
return result;
}
@Override
public BigDecimal operationDivide(BigDecimal numberA, BigDecimal numberB) {
BigDecimal result = null;
result = numberA.divide(numberB);
return result;
}
@Override
public BigDecimal operationMultiply(BigDecimal numberA, BigDecimal numberB) {
BigDecimal result = null;
result = numberA.multiply(numberB);
return result;
}
@Override
public BigDecimal operationSubtract(BigDecimal numberA, BigDecimal numberB) {
BigDecimal result = null;
result = numberA.subtract(numberB);
return result;
}
}
这个时候如果我们输入一些非数字的字符,可能会出现异常,这个时候需要添加一些数字验证,防止异常,有人会说,我直接改这个实现类不就好了吗?但是这样就违背了开放封闭原则。所以这个时候我们就需要添加代理,让代理帮我们做验证的工作,实体类实现计算的功能。
ProxyOperation.java 代理类
public class ProxyOperation implements Operation {
private RealOperation real;
public ProxyOperation (RealOperation real) {
this.real = real;
}
@Override
public BigDecimal operationAdd(String numberA, String numberB) {
Pattern pattern = Pattern.compile("[0-9]*");
Matcher isNumA = pattern.matcher(numberA);
if( !isNumA.matches() ){
System.out.println(numberA + "为非数字,请重新输入");
return null;
}
Matcher isNumB = pattern.matcher(numberB);
if( !isNumB.matches() ){
System.out.println(numberB + "为非数字,请重新输入");
return null;
}
BigDecimal result = real.operationAdd(numberA, numberB);
return result;
}
@Override
public BigDecimal operationDivide(String numberA, String numberB) {
Pattern pattern = Pattern.compile("[0-9]*");
Matcher isNumA = pattern.matcher(numberA);
if( !isNumA.matches() ){
System.out.println(numberA + "为非数字,请重新输入");
return null;
}
Matcher isNumB = pattern.matcher(numberB);
if( !isNumB.matches() ){
System.out.println(numberB + "为非数字,请重新输入");
return null;
}
BigDecimal result = real.operationAdd(numberA, numberB);
return result;
}
@Override
public BigDecimal operationMultiply(String numberA, String numberB) {
Pattern pattern = Pattern.compile("[0-9]*");
Matcher isNumA = pattern.matcher(numberA);
if( !isNumA.matches() ){
System.out.println(numberA + "为非数字,请重新输入");
return null;
}
Matcher isNumB = pattern.matcher(numberB);
if( !isNumB.matches() ){
System.out.println(numberB + "为非数字,请重新输入");
return null;
}
BigDecimal result = real.operationAdd(numberA, numberB);
return result;
}
@Override
public BigDecimal operationSubtract(String numberA, String numberB) {
Pattern pattern = Pattern.compile("[0-9]*");
Matcher isNumA = pattern.matcher(numberA);
if( !isNumA.matches() ){
System.out.println(numberA + "为非数字,请重新输入");
return null;
}
Matcher isNumB = pattern.matcher(numberB);
if( !isNumB.matches() ){
System.out.println(numberB + "为非数字,请重新输入");
return null;
}
BigDecimal result = real.operationAdd(numberA, numberB);
return result;
}
}
下面开始测试,首先测试没有代理的情况
public class Main {
public static void main(String[] args) {
RealOperation realOperation = new RealOperation();
// ProxyOperation proxyOperation = new ProxyOperation(realOperation);
realOperation.operationAdd("12", "15");
realOperation.operationDivide("12", "15");
realOperation.operationMultiply("aa", "2");
realOperation.operationSubtract("2", "b");
}
}
可以看到控制台抛出了异常
Exception in thread "main" java.lang.NumberFormatException
at java.math.BigDecimal.<init>(BigDecimal.java:494)
at java.math.BigDecimal.<init>(BigDecimal.java:383)
at java.math.BigDecimal.<init>(BigDecimal.java:806)
**at proxy.RealOperation.operationMultiply(RealOperation.java:29)**
at proxy.Main.main(Main.java:13)
下面在用代理检测非数字。
public static void main(String[] args) {
RealOperation realOperation = new RealOperation();
ProxyOperation proxyOperation = new ProxyOperation(realOperation);
proxyOperation.operationAdd("12", "15");
proxyOperation.operationDivide("12", "15");
proxyOperation.operationMultiply("aa", "2");
proxyOperation.operationSubtract("2", "b");
}
}
aa为非数字,请重新输入
b为非数字,请重新输入
可以看到,代理类把非数字已经check到了,这样在控制台就没有了异常信息。
----------
好,通过代理模式,非常简单的实现了对非数字的捕获,但是,假如客户突然要求我们对所有的类方法的非数字进行捕获,那该怎么办呢?总不能每一个类,都写一个代理类,那样太麻烦了吧!怎么呢???
动态代理
通过反射机制,利用JDK提供的Proxy类,在程序运行的时候在内存中根据目标对象来创建代理对象,避免了类爆炸的出现。代理方法只写一此,使代码得到了复用。
DynamicProxy.java 动态代理类,此类需要实现InvocationHandler接口 ,当代理对象调用代理方法的时候,注册在调用处理器中的invoke方法会自动调用。
public class DynamicProxy implements InvocationHandler {
// 目标对象,通过反射机制获得
private Object target;
public DynamicProxy(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Pattern pattern = Pattern.compile("[0-9]*");
Matcher isNumA = pattern.matcher(args[0].toString());
if( !isNumA.matches() ){
System.out.println(args[0].toString() + "为非数字,请重新输入");
return null;
}
Matcher isNumB = pattern.matcher(args[1].toString());
if( !isNumB.matches() ){
System.out.println(args[1].toString() + "为非数字,请重新输入");
return null;
}
Object returnValue = method.invoke(target, args);
return returnValue;
}
}
下面写测试类
public class Test {
public static void main(String[] args) {
Operation target = new RealOperation();
// 创建代理对象:通过JDK内置的动态代理类java.lang.reflect.Proxy完成代理对象的动态创建
Operation proxy = (Operation)Proxy.newProxyInstance(target.getClass().getClassLoader(), new Class[]{Operation.class}, new DynamicProxy(target));
proxy.operationAdd("aa", "12");
proxy.operationDivide("bb", "12");
proxy.operationMultiply("cc", "12");
proxy.operationSubtract("dd", "12");
}
}
测试结果:
aa为非数字,请重新输入
bb为非数字,请重新输入
cc为非数字,请重新输入
dd为非数字,请重新输入
动态代理模式相对来说比较难了解,因为它运用了反射机制。但是想象现实生活中,还是挺容易理解的,例如,工作中介,相当于代理模式中的代理对象,它可以为不同人找不同的工作,我们可以没有见过咱们生活中每个人都有一个工作中介代理对象吧。所以这里可以理解为功能代理对象,即为所有类代理可以实现同一种功能,例如上边的捕捉时间。
下面是一些其他代理模式
- 远程代理,为一个对象在不同的地址空间提供局部代表。这样可以隐藏一个对象存在于不同地址空间的事实。
- 虚拟代理,根据需要创建开销很大的对象。通过它来存放实例化需要很长时间的真实对象。例如,网页中在图片出来以前现出来文字。
- 安全代理,用来控制真实对象访问时的权限。
- 智能代理,是指当调用真实的对象时,代理处理另外一些事。
总而言之,这次的学习,有感觉软件和我们生活是息息相关的,善于发现生活的点点滴滴,从软件中联想生活会理解的更深,学习的更好!!!!