大话设计模式之代理模式

代理模式: 为其他对象提供一种代理,并以控制对这个对象的访问。

运用代理模式,为简单的计算器添加数字的验证,防止输入数字以外的东西。


静态代理模式:
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为非数字,请重新输入


动态代理模式相对来说比较难了解,因为它运用了反射机制。但是想象现实生活中,还是挺容易理解的,例如,工作中介,相当于代理模式中的代理对象,它可以为不同人找不同的工作,我们可以没有见过咱们生活中每个人都有一个工作中介代理对象吧。所以这里可以理解为功能代理对象,即为所有类代理可以实现同一种功能,例如上边的捕捉时间。

下面是一些其他代理模式

  1. 远程代理,为一个对象在不同的地址空间提供局部代表。这样可以隐藏一个对象存在于不同地址空间的事实。
  2. 虚拟代理,根据需要创建开销很大的对象。通过它来存放实例化需要很长时间的真实对象。例如,网页中在图片出来以前现出来文字。
  3. 安全代理,用来控制真实对象访问时的权限。
  4. 智能代理,是指当调用真实的对象时,代理处理另外一些事。

总而言之,这次的学习,有感觉软件和我们生活是息息相关的,善于发现生活的点点滴滴,从软件中联想生活会理解的更深,学习的更好!!!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值