一、代理模式
1、舉例
海外代購
2、代理基本結構圖
3、靜態代理
1、真實類實現一個接口,代理類也實現這個接口。
2、代理類通過真實對象調用真實類的方法。
4、靜態代理和動態代理的區別
1、靜態代理在編譯時就已經實現了,編譯完成后代理類是一個實際的class文件。
2、動態代理是在運行時動態生成的,即編譯完成后沒有實際的class文件,而是在運行時動態生成類字節碼,再加載到JVM中。
5、JDK動態代理實現
核心:構造代理對象,按JDK要求獲取參數,讓JDK生成代理對象。
// 生成代理對象 - 核心 Dinner proxy = (Dinner) Proxy.newProxyInstance(classLoader, interfaces, h);
package allwe.testProxy;/*** 定義一個晚餐接口*/
public interface Dinner {void eat(String foodName);void drink(String juiceName);
}
package allwe.testProxy;import lombok.Data;/*** 定義人 - 實現晚餐接口*/
@Data
public class Person implements Dinner {private String name;public Person(String name) {this.name = name;}@Overridepublic void eat(String foodName) {System.out.println(this.name + "吃" + foodName);}@Overridepublic void drink(String juiceName) {System.out.println(this.name + "喝" + juiceName);}
}
package allwe.testProxy;import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;/*** 我的調用處理器 - 設定增強規則*/
public class MyInvocationHandler implements InvocationHandler {private final Dinner dinner;public MyInvocationHandler(Dinner dinner) {this.dinner = dinner;}/*** 定義增強規則** Object proxy 代理對象* Method method 被代理的方法* Object[] args 被代理方法運行時的實參*/@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {if (method.getName().equals("eat")) {System.out.println("前置增強===================飯前洗手");// 運行eat方法method.invoke(dinner, args);System.out.println("后置增強===================飯后洗碗");} else if (method.getName().equals("drink")) {System.out.println("前置增強===================打開瓶蓋");// 運行eat方法method.invoke(dinner, args);System.out.println("后置增強===================關上瓶蓋");} else {return method.invoke(dinner, args);}return null;}
}
package allwe.testProxy;import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;/*** 動態代理實現*/
public class TestProxy {// 通過Proxy動態代理獲取一個代理對象,在代理對象中,對某個方法增強public static void main(String[] args) {// 創建一個人 - 張三Dinner dinner = new Person("張三");// 被代理對象的類加載器ClassLoader classLoader = dinner.getClass().getClassLoader();// 被代理對象所實現的所有接口Class<?>[] interfaces = dinner.getClass().getInterfaces();// 執行處理器對象 - 專門用于定義增強的規則的InvocationHandler h = new MyInvocationHandler(dinner);// 生成代理對象 - 核心Dinner proxy = (Dinner) Proxy.newProxyInstance(classLoader, interfaces, h);// 使用代理對象調用Dinner接口的方法proxy.eat("饅頭");proxy.drink("可樂");}
}
6、Cglib動態代理實現
核心:構造代理對象,按CGLIB要求獲取參數,讓CGLIB生成代理對象。
// 1.創建一個Enhancer對象 Enhancer enhancer = new Enhancer(); // 2.設置真實對象的類 enhancer.setSuperclass(personClass); // 3.設置增強邏輯 enhancer.setCallback(methodInterceptor); // 4.創建代理對象 Person personProxy = (Person) enhancer.create();
package allwe.testCGLib;import lombok.Data;/*** 定義人*/
@Data
public class Person {private String name;// Cglib使用這個構造器創建真實對象public Person() {this.name = "張三";}public void eat(String foodName){System.out.println(this.name + "吃" + foodName);}
}
package allwe.testCGLib;import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;import java.lang.reflect.Method;/*** 我的方法攔截器 - 定義方法攔截規則*/
public class MyMethodInterceptor implements MethodInterceptor {/*** Object o 生成之后的代理對象* Method method 父類中原本要執行的方法* Object[] objects 方法在被調用時接收的實參* MethodProxy methodProxy 子類中重寫的 父類方法*/@Overridepublic Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {System.out.println("==========前置增強==========");// 執行子類對象方法 --> son.super.method(args)Object res = methodProxy.invokeSuper(o, objects);System.out.println("==========后置增強==========");return res;}
}
package allwe.testCGLib;import org.junit.jupiter.api.Test;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;public class TestCglib {@Testpublic void testCglib() {// 獲取被代理的類Class<? extends Person> personClass = Person.class;// 定義增強規則MethodInterceptor methodInterceptor = new MyMethodInterceptor();// 獲取一個Person的代理對象// 1.創建一個Enhancer對象Enhancer enhancer = new Enhancer();// 2.設置真實對象的類enhancer.setSuperclass(personClass);// 3.設置增強邏輯enhancer.setCallback(methodInterceptor);// 4.創建代理對象Person personProxy = (Person) enhancer.create();// 使用代理對象執行方法personProxy.eat("米飯");}
}
二、橋接模式
1、定義
在軟件開發中,橋接模式將兩個獨立變化的維度進行了解耦,不是將兩者耦合在一起,形成多繼承的結構。
2、舉例
毛筆和蠟筆,大中小號,12種顏色。
3、結構:實體與行為分離
4、核心
首先要識別出一個類所具有的兩個獨特的變化維度,將它們設計為兩個獨立的繼承等級結構,為兩個維度都提供抽象層,并建立抽象