java设计模式之代理模式(动态代理)
今天给大家分享的是java设计模式之代理模式中的动态代理模式。如有不足,敬请指正。
我们上次说到静态代理使用一个代理类来管理被代理类对象(源对象)的统一处理,代理类必须要继承或者实现一个基类或者接口!!(很笨重)。每个接口都要实现一个新的代理,每个方法的逻辑处理,还是要重复编写。
那么动态代理:就是可以自由的不指定的使用任何接口来实现代理。所谓的动态就不需要指定代理类的固定接口。
我们本次用模拟通过代理购买火车票来解释动态代理。
图示 |
---|
一、创建实体类Ticket
package com.xkt.pojo;
import java.util.Date;
/**
* @author lzx
*
*/
public class Ticket {
private int id;
private String start; // 发出的
private String destination; // 目的地
private Date startTime; // 出发时间
private float price; // 价格
public Ticket() {
super();
// TODO Auto-generated constructor stub
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getStart() {
return start;
}
public void setStart(String start) {
this.start = start;
}
public String getDestination() {
return destination;
}
public void setDestination(String destination) {
this.destination = destination;
}
public Date getStartTime() {
return startTime;
}
public void setStartTime(Date startTime) {
this.startTime = startTime;
}
public float getPrice() {
return price;
}
public void setPrice(float price) {
this.price = price;
}
@Override
public String toString() {
return "Ticket [id=" + id + ", start=" + start + ", destination=" + destination + ", startTime=" + startTime
+ ", price=" + price + "]";
}
}
二、创建一个公共接口TicketDao
package com.xkt.dao;
import java.util.Date;
import com.xkt.pojo.Ticket;
/**
* @author lzx
*
*/
public interface TicketDao {
/**
* 售票的基础dao
*
* @param start 出发地
* @param destination 目的地
* @param date 出发日期
* @param type 1:火车票 2:机票
* @return
*/
Ticket getTicket(String start,String destination,Date date);
}
三、创建其实现
3.1 TrainTicketDaoImpl
package com.xkt.dao.impl;
import java.util.Date;
import com.xkt.dao.TicketDao;
import com.xkt.pojo.Ticket;
/**
* @author lzx
*
*/
public class TrainTicketDaoImpl implements TicketDao {
@Override
public Ticket getTicket(String start, String destination, Date date) {
Ticket t = new Ticket();
// 模拟查询数据库,获取票信息
t.setId(1);
t.setDestination(destination);
t.setStart(start);
t.setStartTime(date);
t.setPrice(300.0f);
if ("武汉".equals(start) && "广州".equals(destination)) {
t.setPrice(463.0f);
} else if ("北京".equals(start) && "广州".equals(destination)) {
t.setPrice(885.0f);
} else {
t.setPrice(500.0f);
}
System.out.println("---您已购买从 " + start + " 到 " + destination + " 的火车票,请注意发车时间---");
return t;
}
}
3.2 FlightTicketDaoImpl
package com.xkt.dao.impl;
import java.util.Date;
import com.xkt.dao.TicketDao;
import com.xkt.pojo.Ticket;
/**
* @author lzx
*
*/
public class FlightTicketDaoImpl implements TicketDao {
@Override
public Ticket getTicket(String start, String destination, Date date) {
Ticket t = new Ticket();
// 模拟查询数据库,获取票信息
t.setId(1);
t.setDestination(destination);
t.setStart(start);
t.setStartTime(date);
t.setPrice(300.0f);
if ("武汉".equals(start) && "广州".equals(destination)) {
t.setPrice(1000.0f);
} else if ("北京".equals(start) && "广州".equals(destination)) {
t.setPrice(2000.0f);
} else {
t.setPrice(500.0f);
}
System.out.println("---您已购买从 " + start + " 到 " + destination + " 的机票,请注意起飞时间---");
return t;
}
}
四、创建代理类YellowCrow
package com.xkt.proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Date;
import com.xkt.pojo.Ticket;
/**
* @author lzx
*
*/
public class YellowCrow implements InvocationHandler {
// 1、指定代理源(被代理对象)
private Object source;
// 2、创建代理对象,其实就是黄牛本身
public Object createProxy(Object source) {
this.source = source;
// 1、拿到接口
Class<?>[] interfaces = source.getClass().getInterfaces();
// 2、拿到classloader
ClassLoader classLoader = source.getClass().getClassLoader();
// 3、创建代理对象
Object proxyInstance = Proxy.newProxyInstance(classLoader, interfaces, this);
return proxyInstance;
}
// args:执行方法过程中的参数
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
String start = (String) args[0];
String destination = (String) args[1];
Date date = (Date) args[2];
// 通过代理,执行真正购票
Ticket invoke = (Ticket) method.invoke(source, args);
System.out.println("--黄牛加价100--");
invoke.setPrice(invoke.getPrice() + 100);
return invoke;
}
}
五、测试
package com.xkt.test;
import java.util.Date;
import com.xkt.dao.TicketDao;
import com.xkt.dao.impl.FlightTicketDaoImpl;
import com.xkt.dao.impl.TrainTicketDaoImpl;
import com.xkt.pojo.Ticket;
import com.xkt.proxy.YellowCrow;
/**
* @author lzx
*
*/
public class TicketClient {
public static void main(String[] args) {
// 不通过代理购票,自己在12306上抢
TicketDao tDao = new TrainTicketDaoImpl();
/*
* Ticket ticket = tDao.getTicket("武汉", "广州", new Date());
* System.out.println(ticket);
*/
// 自己购票失败,只能找黄牛
YellowCrow crow = new YellowCrow();
TicketDao tDoProxy = (TicketDao) crow.createProxy(tDao);
Ticket ticket2 = tDoProxy.getTicket("武汉", "广州", new Date());
System.out.println(ticket2);
testFlight();
}
private static void testFlight() {
// 1、不通过黄牛,直接去官网购买
TicketDao tDao = new FlightTicketDaoImpl();
/*
* Ticket t1 = tDao.getTicket("武汉", "广州", new Date()); System.out.println(t1);
*/
// 通过黄牛购买
YellowCrow crow = new YellowCrow();
TicketDao createProxy = (TicketDao) crow.createProxy(tDao);
Ticket t2 = createProxy.getTicket("武汉", "广州", new Date());
System.out.println(t2);
}
}
测试结果 |
---|
- 可以看出可以不用创建多个代理对象
- 动态代理模式的好处,就是一个代理类可以代理多个种类型(接口不同)的对象
- 基于动态代理模式可以处理多个类型的类的对象,所以必须要使用到 JDK 的 Proxy 和InvocationHandler 来说实现
- 使用 JDK 自带的 API 实现动态代理,必须要使用接口来原始类的接口接收对象
版权说明:欢迎以任何方式进行转载,但请在转载后注明出处!

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
-
上一篇
一次断电造成ingress"问题"
现象 例如: http://bar.com, 自动重定向到https://bar.com/harbor/sign-in。 即使配置ingress中ssl-redirect:false,其他的ingress,http://foo.com也会重定向到https://foo.com/harbor/sign-in。 解决问题 关闭nginx-ingress的ssl-redirect。关闭后,仍然重定向到https。一头雾水。难道是配置没有生效。 查看nginx-ingress-controller的nginx.conf配置,发现配置已经生效。那为什么还会重定向?这里我卡了很久都没有想明白。 直接把nginx-ingress删了重装,在删了nginx-ingress后,无意间访问ingress地址,还是有响应,那说明不是nginx-ingress的配置问题。 考虑到环境中使用ingress是通过配置主机的HOST文件实现,有可能会有两种情况: ip的80端口是nginx-ingress服务; ip的80端口不是nginx-ingress服务,然后它造成了http重定向到https。 我的故障是由...
-
下一篇
死磕 java原子类之终结篇(面试题)
概览 原子操作是指不会被线程调度机制打断的操作,这种操作一旦开始,就一直运行到结束,中间不会有任何线程上下文切换。 原子操作可以是一个步骤,也可以是多个操作步骤,但是其顺序不可以被打乱,也不可以被切割而只执行其中的一部分,将整个操作视作一个整体是原子性的核心特征。 在java中提供了很多原子类,笔者在此主要把这些原子类分成四大类。 原子更新基本类型或引用类型 如果是基本类型,则替换其值,如果是引用,则替换其引用地址,这些类主要有: (1)AtomicBoolean 原子更新布尔类型,内部使用int类型的value存储1和0表示true和false,底层也是对int类型的原子操作。 (2)AtomicInteger 原子更新int类型。 (3)AtomicLong 原子更新long类型。 (4)AtomicReference 原子更新引用类型,通过泛型指定要操作的类。 (5)AtomicMarkableReference 原子更新引用类型,内部使用Pair承载引用对象及是否被更新过的标记,避免了ABA问题。 (6)AtomicStampedReference 原子更新引用类型,内部使用P...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- SpringBoot2整合Thymeleaf,官方推荐html解决方案
- MySQL数据库在高并发下的优化方案
- SpringBoot2编写第一个Controller,响应你的http请求并返回结果
- SpringBoot2整合MyBatis,连接MySql数据库做增删改查操作
- SpringBoot2配置默认Tomcat设置,开启更多高级功能
- Docker使用Oracle官方镜像安装(12C,18C,19C)
- Docker快速安装Oracle11G,搭建oracle11g学习环境
- Springboot2将连接池hikari替换为druid,体验最强大的数据库连接池
- SpringBoot2初体验,简单认识spring boot2并且搭建基础工程
- CentOS7编译安装Cmake3.16.3,解决mysql等软件编译问题