java設計模式之代理模式(動態代理)

  今天給你們分享的是java設計模式之代理模式中的動態代理模式。若有不足,敬請指正。java


  咱們上次說到靜態代理使用一個代理類來管理被代理類對象(源對象)的統一處理,代理類必需要繼承或者實現一個基類或者接口!!(很笨重)。每一個接口都要實現一個新的代理,每一個方法的邏輯處理,仍是要重複編寫。數據庫

  那麼動態代理:就是能夠自由的不指定的使用任何接口來實現代理。所謂的動態就不須要指定代理類的固定接口。設計模式


  咱們本次用模擬經過代理購買火車票來解釋動態代理。ide

圖示

1、建立實體類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 + "]";
	}
}

2、建立一個公共接口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、建立其實現

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;

	}

}

4、建立代理類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 {

	// 一、指定代理源(被代理對象)
	private Object source;

	// 二、建立代理對象,其實就是黃牛自己
	public Object createProxy(Object source) {
		this.source = source;

		// 一、拿到接口
		Class<?>[] interfaces = source.getClass().getInterfaces();

		// 二、拿到classloader
		ClassLoader classLoader = source.getClass().getClassLoader();

		// 三、建立代理對象
		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;
	}

}

5、測試

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() {

		// 一、不經過黃牛,直接去官網購買
		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);
	}
}
測試結果
  1. 能夠看出能夠不用建立多個代理對象
  2. 動態代理模式的好處,就是一個代理類能夠代理多個種類型(接口不一樣)的對象
  3. 基於動態代理模式能夠處理多個類型的類的對象,因此必需要使用到 JDK 的 Proxy 和InvocationHandler 來講實現
  4. 使用 JDK 自帶的 API 實現動態代理,必需要使用接口來原始類的接口接收對象

版權說明:歡迎以任何方式進行轉載,但請在轉載後註明出處!測試

相關文章
相關標籤/搜索