Java 设计模式 代理模式

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://louluan.blog.csdn.net/article/details/18847313

Proxy (代理模式)定义

Purpose (目的)

  • 为另外一个对象提供一个代理或占位符以控制对这个对象的访问。

Structure (结构)

  • Proxy角色
    1. (该角色)持有一个RealSubject 角色的引用,用以访问RealSubject。如果RealSubject和Subject角色的接口是相同的,Proxy角色也可以持有一个Subject的引用(不过这个Subject 还是引用的是RealSubject的实现,即父类引用子类对象 :Subject subject=new RealSubject())。
    2. 应该具有和Subject角色完全一致的接口,这样,Proxy角色可以成为RealSubject 的替代品。
    3. 控制对 真正对象访问,并且可以负责创建和删除真正对象。
    4. 其他功能:
    5. 远程代理负责加密请求和参数,然后将加密的请求发送到不同的地址空间的真正对象。
    6. 为真正的对象提供额外的信息。
    7. 保护性质的代理可以为 访问 realSubject请求提供权限控制。
  • Subject : 定义RealSubject和Proxy实现的公共接口。
  • RealSubject : 定义代理要表示的真正的对象。

Applications(应用)

  • 一个远程的代理对不同的地址空间内的对象提供一个本地表示。
  •  可以根据需求控制创建代价昂贵的对象。
  • 为原对象提供访问权限的控制。

Consequences(结论)

  • 代理模式 引入了非直接访问对象的机制 。这种添加的非直接访问,有以下几种应用:
    1. 一个远程的代理对不同的地址空间内的对象提供一个本地表示
    2. 一个虚拟的代理可以优化功能,比如根据需求创建对象。
    3. 保护性代理允许当访问对象时,做一些额外的内部操作。

代理模式应用示例

想要访问某对象,但是不能直接访问某对象场景--车票代售点

     车站设置代售点的原因,一方面是为人流高峰期缓解车站自身压力,另一方面则是对一些偏远地方,购票很不方便的人提供便利。

      车站的售票业务主要有:卖票、问询、退票,将其抽象出一个接口TicketService,将功能分别定义为:sellTicket(),inquire()和withdraw()。将车站定义为Station类,实现TicketService接口;而代售点定义为StationProxy,实现TicketService接口,并持有一个Station实例的引用,三个角色之间的关系如下图:

相关代码如下:

package com.foo.proxy;
/**
 * 售票服务接口 
 * @author louluan
 */
public interface TicketService {

	//售票
	public void sellTicket();
	
	//问询
	public void inquire();
	
	//退票
	public void withdraw();
	
}
package com.foo.proxy;

/**
 * 售票服务接口实现类,车站
 * @author louluan
 */
public class Station implements TicketService {

	@Override
	public void sellTicket() {
		System.out.println("\n\t售票.....\n");

	}

	@Override
	public void inquire() {
        System.out.println("\n\t问询。。。。\n");
	}

	@Override
	public void withdraw() {
        System.out.println("\n\t退票......\n");
	}

}
package com.foo.proxy;

/**
 * 车票代售点
 * @author louluan
 *
 */
public class StationProxy implements TicketService {

	private Station station;

	public StationProxy(Station station){
		this.station = station;
	}
	
	@Override
	public void sellTicket() {

		// 1.做真正业务前,提示信息
		this.showAlertInfo("××××您正在使用车票代售点进行购票,每张票将会收取5元手续费!××××");
		// 2.调用真实业务逻辑
		station.sellTicket();
		// 3.后处理
		this.takeHandlingFee();
		this.showAlertInfo("××××欢迎您的光临,再见!××××");

	}

	@Override
	public void inquire() {
		// 1做真正业务前,提示信息
		this.showAlertInfo("××××欢迎光临本代售点,问询服务不会收取任何费用,本问询信息仅供参考,具体信息以车站真实数据为准!××××");
		// 2.调用真实逻辑
		station.inquire();
		// 3。后处理
		this.showAlertInfo("××××欢迎您的光临,再见!××××");
	}

	@Override
	public void withdraw() {
		// 1。真正业务前处理
		this.showAlertInfo("××××欢迎光临本代售点,退票除了扣除票额的20%外,本代理处额外加收2元手续费!××××");
		// 2.调用真正业务逻辑
		station.withdraw();
		// 3.后处理
		this.takeHandlingFee();

	}

	/*
	 * 展示额外信息
	 */
	private void showAlertInfo(String info) {
		System.out.println(info);
	}

	/*
	 * 收取手续费
	 */
	private void takeHandlingFee() {
		System.out.println("收取手续费,打印发票。。。。。");
	}

}
package com.foo.proxy;
/**
 * 客户端角色
 * @author louluan
 */
public class Client {

	public static void main(String[] args) {

		//创建Station
		Station service = new Station();
		//创建代理类
		StationProxy proxy = new StationProxy(service);
		//代售点售票
		proxy.sellTicket();
	}

}

执行结果:

为访问对象增加权限-用户信息检索系统

      公司有一个用户信息检索系统,管理员可以检索用户的基本信息,教育背景,和账户信息。由于业务发展的需要,此系统要跟公司实现信息共享,需要向别的公司提供我们的接口,但是信息共享并不是全部共享,只允许别的公司查询基本信息和教育背景,而有些敏感信息账户信息不允许别的公司调用的,在这里可以设置一个代理,用于控制访问查询信息接口的权限控制,当是外部想要查询账户信息时,给你返回 "********"掩码展示。

定义一个UserInfoService接口,有getBasicInfo(),getEducationalBackground(),getAcccountInfo()分别用于查询基本信息,教育背景,账户信息;

UserInfoServiceImpl类实现UserInfoService接口;

UserInfoServiceProxy类作为代理类,实现UserInfoService接口和持有一个UserInfoServiceImpl引用:

package com.foo.proxy1;

/**
 * 信息查询接口
 */
public interface UserInfoService {

	//基本信息
	public String getBasicInfo();
	//教育背景
	public String getEducationalBackground();
	//账户信息
	public String getAcccountInfo();
}
package com.foo.proxy1;
/**
 * 查询接口实现
 * @author louluan
 */

public class UserInfoServiceImpl implements UserInfoService {

	@Override
	public String getBasicInfo() {
		return "Basic Info....";
	}

	@Override
	public String getEducationalBackground() {
		return "Educational Background.....";
	}

	@Override
	public String getAcccountInfo() {
		return "Account Info.....";
	}

}
package com.foo.proxy1;

/**
 * 信息查询代理控制访问权限
 * @author louluan
 */
public class UserInfoServiceProxy implements UserInfoService {

	private UserInfoService impl;
	private String role;
	public UserInfoServiceProxy(UserInfoService impl,String role)
	{
		this.impl = impl;
		this.role = role;
	}
	@Override
	public String getBasicInfo() {
		return impl.getBasicInfo();
	}

	@Override
	public String getEducationalBackground() {
		return impl.getEducationalBackground();
	}

	@Override
	public String getAcccountInfo() {
		//如果是公司本部,返回
		if("1".equals(role))
		{
			return impl.getAcccountInfo();
		}
		//禁止访问impl方法,返回**** 			
		return "**********";
	}
}
package com.foo.proxy1;

public class Client {

	public static String OUT="0";
	public static String IN="0";
	
	public static void main(String[] args) {
		UserInfoService service = new UserInfoServiceImpl();
		
		UserInfoServiceProxy proxy = new UserInfoServiceProxy(service,OUT);
		//外部公司查询信息
		System.out.println("*****外部公司查询信息*******");
		//获取基本信息:
		String basicInfo = proxy.getBasicInfo();
		System.out.println("基本信息:"+basicInfo);
		//教育背景
		String educationalBackground = proxy.getEducationalBackground();
		System.out.println("教育背景:"+educationalBackground);
		//账户信息
		String accountInfo = proxy.getAcccountInfo();
		System.out.println("账户信息:"+accountInfo);
	}
}

增强原对象的功能---AOP

代理模式最有魅力的地方就在于它实现了AOP(Aspect-Oriented  Programming),即面向切面的编程。(未完待续)

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

扫码关注云+社区

领取腾讯云代金券