1. 程式人生 > >GOF23種設計模式

GOF23種設計模式

代理模式(Proxy pattern)

  1. 核心作用:
    通過代理,控制對物件的訪問,可以詳細控制訪問某個(某類)物件的方法,在呼叫這個方法前做前置處理,呼叫這個方法後做後置處理。
    AOP(Aspect Oriented Programming面向切面程式設計)的核心實現機制。
  2. 核心角色:
    **抽象角色:**定義代理角色和真實角色的公共對外方法。
    **真實角色:**實現抽象角色,定義真實角色所要實現的業務邏輯,供代理角色呼叫。
    關注真正的業務邏輯
    **代理角色:**實現抽象角色,是真實角色的代理,通過真實角色的業務邏輯方法來實現抽象方法,並附加自己的操作。
    將統一的流程控制放到代理角色中處理。
  3. 應用場景:
    安全代理:遮蔽對真實決角色的直接訪問
    遠端代理:通過代理類處理遠端方法呼叫(RMI)
    延遲載入:先載入輕量級的代理物件,真正需要再載入真實物件。
  4. 分類:
    4.1靜態代理:
    在這裡插入圖片描述
    介面類定義Star:
public interface Star {
	/**面試*/
	void confer();
	/**籤合同*/
	void signContract();
	/**訂機票*/
	void bookTicket();
	/**唱歌*/
	void sing();
	/**收沒款*/
	void collectMoney();
}

真實物件RealStar:

public class
RealStar implements Star { @Override public void confer() { System.out.println("RealStar confer()"); } @Override public void signContract() { System.out.println("RealStar signContract()"); } public void bookTicket() { System.out.println("RealStar bookTicket()"); } @Override public
void sing() { System.out.println("RealStar(明星) sing()"); } @Override public void collectMoney() { System.out.println("RealStar collectMoney()"); } }

代理類ProxyStar:

public class ProxyStar implements Star {

	RealStar realStar;
	
	public ProxyStar(RealStar realStar) {
		super();
		this.realStar = realStar;
	}

	@Override
	public void confer() {
		System.out.println("ProxyStar confer");
	}

	@Override
	public void signContract() {
		System.out.println("ProxyStar signContract");
	}

	@Override
	public void bookTicket() {
		System.out.println("ProxyStar bookTicket");
	}

	@Override
	public void sing() {
		realStar.sing();//真實的物件去做
	}

	@Override
	public void collectMoney() {
		System.out.println("ProxyStar collectMoney");
	}

}

測試:

public class Testd {

	public static void main(String[] args) {
		RealStar realStar=new RealStar();
		ProxyStar proxyStar=new ProxyStar(realStar);
		proxyStar.confer();
		proxyStar.signContract();
		proxyStar.sing();
		proxyStar.collectMoney();
	}
}

結論
在這裡插入圖片描述
4.2動態代理:
相比靜態代理優先:抽象角色中(介面)宣告的所以方法都被轉移待呼叫處理器一個集中的方法處理,這樣,我們可以使用更加靈活和統一的處理眾多的方法。
4.2.1 JDK自帶動態代理
java.lang.reflect.InvocationHandler (處理器介面)
可以通過invoke方法實現對真實角色的代理訪問
每次通過Proxy生成代理類物件時都要指定對應的處理器物件

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

public class MyInvocationHandler implements InvocationHandler {
	
	JdkInterface jdk;
	
	public MyInvocationHandler(JdkInterface jdk) {
		this.jdk = jdk;
	}

	//java.lang.reflect.InvocationHandler (處理器介面)
	//可以通過invoke方法實現對真實角色的代理訪問
	//每次通過Proxy生成代理類物件時都要指定對應的處理器物件
	@Override
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		System.out.println("前置處理:目標方法執行之前");//目標方法執行之前處理邏輯與業務
		method.invoke(jdk, args);//執行目標方法
		System.out.println("後置處理:目標方法執行之後");//目標方法執行之後處理邏輯
		return null;
	}

}

介面定義:

public interface JdkInterface {
	void say(String message);
}

實現類:

public class JDKInterfaceImpl implements JdkInterface {

	@Override
	public void say(String message) {
		System.out.println("輸出語句:"+message);
	}
}

測試方法

import java.lang.reflect.Proxy;
public class TestMy {
	public static void main(String[] args) {
		JdkInterface jdkInterfaceImpl=new JDKInterfaceImpl();
		MyInvocationHandler my=new MyInvocationHandler(jdkInterfaceImpl);
		JdkInterface projdk=	(JdkInterface)Proxy.newProxyInstance(jdkInterfaceImpl.getClass().getClassLoader(), jdkInterfaceImpl.getClass().getInterfaces(), my);
		//Proxy.newProxyInstance(loader, interfaces, h);
		//ClassLoader loader :指定當前目標物件使用類載入器,寫法固定
		//Class<?>[] interfaces:目標物件實現的介面的型別,寫法固定
		//InvocationHandler h :事件處理介面,需傳入一個實現類,一般使用匿名內部類
		projdk.say("目標方法執行");
	}
}

4.2.2 javaassist位元組碼操作庫實現

4.2.3 CGLIB
目標類不能為final,目標物件的方法如果為final/static,那麼就不會被攔截,即不會執行目標物件額外的業務方法。
該類實現了建立子類的方法與代理的方法。getProxy(SuperClass.class)方法通過入參即父類的位元組碼,通過擴充套件父類的class來建立代理物件。intercept()方法攔截所有目標類方法的呼叫,obj表示目標類的例項,method為目標類方法的反射物件,args為方法的動態入參,proxy為代理類例項。proxy.invokeSuper(obj, args)通過代理類呼叫父類中的方法。

定義目標類:

public class Chinese {
	/**目標方法未實現任何的介面*/
	public  void sing() {
		System.out.println("吃麵條");
	}
}

定義CGLIB代理類工場

public class ProxyFactory implements MethodInterceptor {

	//給目標物件建立一個代理物件
	public Object getProxyInstance(Class target) {
		//1.工具類
		Enhancer enhancer=new Enhancer();
		//2.設定父類
		enhancer.setSuperclass(target);
		//3.設定回撥函式
		enhancer.setCallback(this);
		//4.通過位元組碼技術動態建立子類例項(代理物件)
		return enhancer.create();
	}
 
	//實現MethodInterceptor介面方法
	@Override
	public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
		System.out.println("執行目標方法之前:拿起筷子");
		Object object = proxy.invokeSuper(obj, args);//呼叫父類中的方法,執行目標方法
		System.out.println("執行目標方法之後:放下筷子");
		return object;
	}
}

測試方法:

public class CGLIBMain {
	public static void main(String[] args) {
		ProxyFactory proxyFactory= new ProxyFactory();
		//通過生成子類的方式建立代理類
		Chinese proxyInstance = (Chinese)proxyFactory.getProxyInstance(Chinese.class);
		proxyInstance.sing();
		System.out.println();
		System.out.println(proxyInstance);
	}
}

執行結果:
在這裡插入圖片描述

第二種引數寫法

public class ProxyFactory implements MethodInterceptor {
	private Object target;
	public ProxyFactory(Object target) {
		super();
		this.target = target;
	}

	//給目標物件建立一個代理物件
	public Object getProxyInstance() {
		//1.工具類
		Enhancer enhancer=new Enhancer();
		//2.設定父類
		enhancer.setSuperclass(target.getClass());
		//3.設定回撥函式
		enhancer.setCallback(this);
		//4.通過位元組碼技術動態建立子類例項(代理物件)
		return enhancer.create();
	}
 
	//實現MethodInterceptor介面方法
	@Override
	public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
		System.out.println("執行目標方法之前:拿起筷子");
		Object object = method.invoke(target, args);//呼叫父類中的方法,執行目標方法
		System.out.println("執行目標方法之後:放下筷子");
		return object;
	}
}

測試方法:

public class CGLIBMain {
	public static void main(String[] args) {
		Chinese chinese=new Chinese();
		ProxyFactory proxyFactory= new ProxyFactory(chinese);
		//通過生成子類的方式建立代理類
		Chinese proxyInstance = (Chinese)proxyFactory.getProxyInstance();
		
		proxyInstance.sing();
		System.out.println();
		System.out.println(proxyInstance);
	}
}

測試結果

在這裡插入圖片描述

4.2.4 ASM(底層使用指令,可維護性較差)