学习任务:

视频学习

通过案例理解代理的好处

代理模式实现

代理这个词并不陌生,软件开发中的代理与生活中的代理意义差不多,它是一个中介的角色,它有什么作用呢?下边通过一个例子说明。

下边是一个成绩管理的服务类,在成绩非法时会抛出异常,如下代码:

package com.pbteach.javase.oop.proxy;

/**
 * 	成绩录入接口
 * @author 攀博课堂(www.pbteach.com)
 *
 */
public interface IScoreService {
	
	/**
	 * 
	 * 录入成绩.
	 * @param scoreList 变长参数,多个成绩
	 * @return 成绩之和
	 * @author 攀博课堂
	 * @version v1.0
	 */
	public float inputScore(float... scoreList);
}



package com.pbteach.javase.oop.proxy;

/**
	 * 
	 * 录入成绩.
	 * @param scoreList 变长参数,多个成绩
	 * @return 成绩之和
	 * @author 攀博课堂
	 * @version v1.0
	 */
	public float inputScore(float... scoreList) {
			if(scoreList == null) {
				throw new RuntimeException("请输入成绩") ;
			}
			for (int i = 0; i < scoreList.length; i++) {
				float score = scoreList[i];
				  //判断该考试成绩是否在指定(0-100)的范围内,如果不在该范围内,那么就抛出异常
		        if(score < 0 || score > 100) {
		            throw new RuntimeException("成绩有误(0-100之间)") ;
		        }
			}
			//如果成绩合法就可以存储成绩
	        //...
			//求和
			float sum = 0;
			for (int i = 0; i < scoreList.length; i++) {
				sum +=scoreList[i];
			}
	        return sum;
	}

下边代码是调用ScoreService的inputScore()方法:

package com.pbteach.javase.oop.proxy.model;

import java.util.Scanner;

/**
 * 代理模式测试
 * @author 攀博课堂(www.pbteach.com)
 *
 */
public class ProxyDemo1  {
	
	//调用ScoreService的方法
	public static void test1() {
		ScoreService scoreService = new ScoreService();
		// 键盘录入一个考试成绩
        Scanner scanner = new Scanner(System.in) ;
        System.out.println("请您输入三科的考试成绩:");
        try {
			float score1 = scanner.nextFloat();
			float score2 = scanner.nextFloat();
			float score3 = scanner.nextFloat();
			//保存成绩
			float sum = scoreService.inputScore(score1,score2,score3);
			System.out.println("总分="+sum);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	public static void main(String[] args) {
		test1();
	}
	
}

输出:

请您输入三科的考试成绩:
11
22
33
总分=66.0

上边代码中ScoreService抛出了异常,在使用ScoreService的地方需要捕获异常,项目中类似ScoreService的类有好多,并且使用这些Service类的地方也有好多,在每个使用类中都要去try/catch捕获异常则非常麻烦。

image-20210222094458783

如果能在统一的一个地方去捕获异常那就解决了上边说的问题,这个任务可以由代理实现,如下图:

image-20210222110318034

代理在软件开发中是一种设计模式,用代理对象代替目标对象,在代理对象中可以增强目标对象的功能。如上图调用方通过代理调用ScoreService中的方法,在代理类中就可以添加统一的try/catch异常处理的功能。

第一步:创建代理类并实现目标对象的接口

代理类要代替目标类那么它必须拥有目标类的接口,这样代理类才能提供目标类相同的功能。

下边创建代理类,实现IScoreService接口,如下代码:

package com.pbteach.javase.oop.proxy;

/**
 * ScoreService的代理类
 * @author 攀博课堂
 * @version v1.0
 */
public class ScoreServiceProxy implements IScoreService {

	
	public float inputScore(float... scoreList) {
		// TODO Auto-generated method stub
		
	}

}

第二步:实现代理类

如何在代理类中实现目标类的接口呢?

1)调用目标类对象

代理类只是一个中介,代理类需要调用目标类对象执行接口方法,所以代理类提供set方法负责将目标类对象设置到代理类对象中。

2)捕获异常

在调用目标类方法时进行异常捕获,实现了在统一个地方捕获异常的需求。

代理类的代码如下:

package com.pbteach.javase.oop.proxy;

/**
 * ScoreService的代理类
 * @author 攀博课堂
 * @version v1.0
 */
public class ScoreServiceProxy implements IScoreService {

	//目标对象
		private IScoreService scoreService;
		//通过set方法将目标对象设置到代理对象中
		public void setScoreService(IScoreService scoreService) {
			this.scoreService = scoreService;
		}

		@Override
		public float inputScore(float... scoreList) {
			//这里统一捕获异常
			try {
				//在这里可以添加代码,比如记录日志
				System.out.println("执行前记录日志...");
				return scoreService.inputScore(scoreList);
			} catch (Exception e) {
				System.out.println("在代理类中统一捕获异常");
				e.printStackTrace();
			}
			return 0;
		}
}

有了代理类,在使用目标类的地方就可以通过代理对象调用目标类对象。代码如下:

package com.pbteach.javase.oop.proxy.model;

import java.util.Scanner;

/**
 * 代理模式测试
 * @author 攀博课堂(www.pbteach.com)
 *
 */
public class ProxyDemo1  {
	
	//调用ScoreServiceProxy的方法,正常流程
	public static void test2() {
		//创建代理对象
		ScoreServiceProxy scoreService = new ScoreServiceProxy();
		//向代理对象设置目标对象
		scoreService.setScoreService(new ScoreService());
		//正常测试
		//通过代理对象调用目标对象的方法
		//这里由于传入了小于0的数在代理类中捕获异常
		float sum = scoreService.inputScore(11,22,33);
		System.out.println("总分:"+sum);
	}
	public static void main(String[] args) {
		test2();
	}
	
}

输出:

执行前记录日志...
总分:66.0

异常测试:

//调用ScoreServiceProxy的方法,异常流程
	public static void test3() {
		//创建代理对象
		ScoreServiceProxy scoreService = new ScoreServiceProxy();
		//向代理对象设置目标对象
		scoreService.setScoreService(new ScoreService());
		//异常测试
		//通过代理对象调用目标对象的方法
		//这里由于传入了小于0的数在代理类中捕获异常
		float sum = scoreService.inputScore(-1);
		System.out.println("总分:"+sum);
	}

输出:

执行前记录日志...
在代理类中统一捕获异常
java.lang.RuntimeException: 成绩有误(0-100之间)
	at com.pbteach.javase.oop.proxy.ScoreService.inputScore(ScoreService.java:26)
	at com.pbteach.javase.oop.proxy.ScoreServiceProxy.inputScore(ScoreServiceProxy.java:23)
	at com.pbteach.javase.oop.proxy.ProxyDemo1.test3(ProxyDemo1.java:50)
	at com.pbteach.javase.oop.proxy.ProxyDemo1.main(ProxyDemo1.java:55)
总分:0.0

提问-攀博课堂
我要提问 不会就问,有效沟通
关注公众号,加入微信群交流提问。 攀博课堂官方公众号
问答列表,查看本知识点所有问题