java設計模式之代理模式(動態代理)
阿新 • • 發佈:2019-05-14
今天給大家分享的是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 實現動態代理,必須要使用介面來原始類的介面接收物件
版權說明:歡迎以任何方式進行轉載,但請在轉