Overview of Content
如有引用參考請詳註出處,感謝
在這篇文章中,我們將深入探討 代理模式(Proxy Pattern
)的實現與解說,特別關注動態代理的分析。
首先,我們會提供整體內容的概述,並深入了解代理模式的概念。接著,我們將解釋代理模式的定義,並透過UML結構呈現其模型。在設計方面,我們會詳細討論代理模式的優缺點,使讀者能全面了解其應用範疇。
在實際實做部分,我們將深入探討代理模式的兩種基本實現方式,分別是普通代理和強制代理。
隨後,我們轉向動態代理,介紹 InvocationHandler 介面以及動態代理的 UML 結構。透過實際程式碼,我們將展示動態代理的兩種實現方式,包括實體類和匿名類。最後,我們將解析 Proxy 生成的動態代理類,深入分析其結構,包括 IO 輸出 Proxy 類以及對動態代理的進一步分析。透過這篇文章,讀者將深入理解代理模式的實際應用,尤其是動態代理的原理與實現。
Proxy 概述
代理可做到加強源類,也可隔離,JDK 有提供接口,並且代理類分為兩種 1. 靜態代理、2. 動態代理
動態代理使會用到 Java 反射,動態代理使用的地方也很多,像是 Android Retrofit 就有使用到,一般我們在 Hook 資料時也常使用到
Proxy 定義 & Proxy UML
● Proxy 定義:為其他物件提供代理來訪問目標物件
● Proxy UML、角色關係
類 | 關係 |
---|---|
Subject (抽象、接口) | 定義一個對外的抽象方法 |
RealSubject | 實際實現業務者 |
Proxy | 代理 RealSubject 對象,內部持有一個 Subject 對象,將所有實做委託給真實對象(RealSubject) |
Proxy 設計:優缺點
A. Proxy 設計 靜態代理
● 優點:Proxy 的類建構、連接於編譯期間,所以運行速度較快
● 缺點:不符合開閉原則,維護代價較高,會為了增加功能而不斷新增修改代理類
● 當代理類(Proxy)需要代理多個不同接口時就必須修改,維護成本會提高
B. Proxy 設計 動態代理:使用反射需要時才創建
● 優點:透過 JDK 自動生成代碼,在運行時加強代碼
● 缺點:Proxy 類建構、連接於運行期間,所以速度較慢
Proxy 實現
Proxy 普通代理
● 普通代理的意思:使用者不必知道真實類是誰,而是透過代理類來訪問對象(這符合迪米特原則,不用讓外部了解代理的相關類)
以下範例,代理書本購買
A. Subject
抽象:AlienShop 定義對外暴露的方法
interface AlienShop {
fun buyBook(name: String)
fun getBook(): String
}
B. RealSubject
類:RealShop 實做購買書籍的邏輯
class RealShop : AlienShop {
override fun buyBook(name: String) {
println("$name book the Book")
}
override fun getBook(): String {
return "平行世界"
}
}
C. Proxy
類:在代理類中可以加強原來的方法,但是到實際要執行時,仍是執行 RealSubject 的方法
class ProxyShop : AlienShop {
private val realShop = RealShop() // 可在內部自己創建
override fun buyBook(name: String) {
println("-----Proxy help $name buy Book") // 代理加強
realShop.buyBook(name)
}
override fun getBook(): String {
println("-----Proxy help get Book ") // 代理加強
return realShop.getBook()
}
}
● User 使用代理設計
fun main() {
val shop : AlienShop = ProxyShop().also {
it.buyBook("Kyle")
println(it.getBook())
}
}
Proxy 強制代理
● 強制代理:強制代理是代理設計中比較特別的概念,作為強制代理設計的使用者,你 可以直接接觸到實做類,你可以選擇是否直接訪問該類的方法,或是透過該類指定的代理類你才能代理
A. Subject
抽象:該抽象重點是增加了一個 getProxy
方法,返回了一個 Subject 抽象,這個方法就是強制代理的重點之一
當然,如果想想要實作「強制的特性」,那就不要對外暴露可操作的方法介面,可以透過 介面隔離原則 來區分內外介面
interface IPlayGame {
fun play()
fun getProxy() : IPlayGame
}
B. RealSubject
類:實做 IPlayGame 接口,對於 getProxy
則定義一個指定的代理類!
class AlienPlay : IPlayGame {
private var proxy : IPlayGame? = null
override fun play() {
proxy.let {
if (it == null) { // it 是 kotlin 的語法糖提供,它表的也是呼叫者(也就是 proxy)
println("Call proxy to play")
return // 在這邊你甚至可以做拋出 Exception 的行為!強制使用者一定要用代理
}
println("Playing game now ~")
}
}
override fun getProxy(): IPlayGame {
// 創建指定代理類
proxy = AppleProxyPlay(this)
return proxy!!
}
}
C. Proxy
類:代理類同樣使用 RealSubject 的實做;這裡的 getProxy
則返回自身
當然這裡的代理類還是可以返回其他的代理,不一定要返回
this
class AppleProxyPlay constructor(private val real: IPlayGame) : IPlayGame {
override fun play() {
println("Proxy start play")
real.play()
println("Proxy finish play")
}
override fun getProxy(): IPlayGame {
return this
}
}
● User 使用強制代理
fun main() {
AlienPlay().run {
// 沒透過代理類不能訪問
play()
// 必須透過代理類才能訪問!
getProxy().play()
}
}
Java 動態代理
動態代理與靜態代理最大的差別在於,動態代理載運行時才指定代理對象(指定代理接口)
● 動態代理內部原理:
Java 動態代理在源碼中是使用了 反射的技巧
● 應用場景侷限:
由於 Java Proxy 類是 class 並非
interface
,而 Java 是單繼承 (每個代理類都繼承了 Proxy 類,等等可以看到),即 只能對介面創建代理,不對類創建代理類
InvocationHandler 介面 & 動態代理 UML
● InvocationHandler
是一個介面(接口),它的功能相當於一個 Hook Callback,在調用真正方法前會先調遇到這個方法 (分析碼可以看見),代理類一定要實現這個介面(接口)
● 動態代理 UML
動態代理透過自動生成的 Proxy 類,並使用生成的 Proxy 類來訪問真正時做類 (概念如同靜態,但它的彈性較大,許多框架都會使用到這個設計概念)
動態代理:實體類
● 直接看動態代理的範例
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class mainClass {
public static void main(String []args) {
// 創建真實實做類
Shop book = new RealBookShop();
CommonProxyShop commonProxyShop = new CommonProxyShop(); // 創建代理類
commonProxyShop.setShop(book); // 設定代理類
// 取得代理類
BookShop s1 = (BookShop) commonProxyShop.getProxy();
System.out.println(s1.getBook());
// 創建真實實做類
Shop tool = new RealToolShop();
CommonProxyShop commonProxyShop2 = new CommonProxyShop(); // 創建代理類
commonProxyShop2.setShop(tool);
// 取得代理類
ToolShop t1 = (ToolShop) commonProxyShop2.getProxy();
System.out.println(t1.getTool());
}
}
// 代理類
class CommonProxyShop implements InvocationHandler {
private Object object;
void setShop(Shop object) {
this.object = object;
}
// 獲取代理類 Proxy
Proxy getProxy() {
return (Proxy) Proxy.newProxyInstance(
object.getClass().getClassLoader(), // 類加載器
object.getClass().getInterfaces(), // 該類所有接口
this); // InvocationHandler 實現
}
// 動態創建的 Proxy 類會呼叫此接口 (InvocationHandler)
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("CommonProxyShop ask shop");
// 第一個參數,是真正要被執行的類
Object o = method.invoke(object, args);
System.out.println("Shop reply CommonProxyShop");
return o;
}
}
// 創建一個接口,在自動生成的 Proxy 類中,會繼承該類
interface Shop { }
interface BookShop extends Shop {
String getBook();
}
// 真實實做類
class RealBookShop implements BookShop{
@Override
public String getBook() {
return null;
}
}
interface ToolShop extends Shop {
String getTool();
}
class RealToolShop implements ToolShop{
@Override
public String getTool() {
return null;
}
--實做--
動態代理:匿名類
● 其實跟上面的是相同的,只是把 InvocationHandler 改為匿名類 (順便多了個範例)
注意反射時帶入的物件要帶入 目標代理對象,不要寫成代理自身
public class dynamicProxy {
public static void main(String[] str) {
final Pan pan = new Pan(); // 被代理者
/* Java 自己生成代理類
* 引數
* 1. 被代理者的類加載器
* 2. 代理 interface
* 3. 注入接口 InvocationHandler (Hook interface)
*/
Object o = Proxy.newProxyInstance(pan.getClass().getClassLoader(),
// 不可代理類 String.class! 因為生成的類繼承 Proxy
// 而 Java 是單繼承,這也就是為何只能實現接口代理
// 下面會介紹
new Class[]{Hello.class, World.class},
new InvocationHandler() {
@Override
public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
System.out.println("----------------get Invoke-------------------");
System.out.println("Method Name: " + method.getName());
// 這個 o 是 Proxy,不能自己代理自己 !! 否則會造成遞迴
//return method.invoke(o, objects);
// invoke 要被代理的物件 (也就是真正實作類 pan)
return method.invoke(pan, objects);
}
}
);
Hello hello = (Hello) o;
hello.talk("Hello");
World world = (World) o;
System.out.println(world.say());
}
}
// 真正實作類
class Pan implements Hello, World{
@Override
public void talk(String s) {
System.out.println("talk: " + s);
}
@Override
public String say() {
return "World";
}
}
interface Hello {
void talk(String s);
}
interface World {
String say();
}
--實作--
解析 Proxy 生成動態代理類
IO 輸出 Proxy 類
● 在這裡我們要查看自動生成的程式,會使用到 IO 流輸出檔案 (將自動生成的程式輸出,這樣我們才可以看到~ )
在代理內找到的方法可以做用在不同的 class 實例中 (該 class 必須要此方法)
Function | 功能 |
---|---|
ProxyGenerator.generateProxyClass | 自動在 內存 產生代理類 |
// 動態代理範例
public class dynamicProxy {
public static void main(String[] str) {
final Pan pan = new Pan(); // 被代理者
/* Java 自己生成代理類
* 引數
* 1. 類加載器
* 2. 代理 interface
* 3. 注入接口 InvocationHandler
*/
Object o = Proxy.newProxyInstance(pan.getClass().getClassLoader(),
new Class[]{Hello.class, World.class}, // 不可代理類 String.class! 因為生成的類繼承 Proxy
new InvocationHandler() {
@Override
public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
System.out.println("----------------get Invoke-------------------");
System.out.println("Method Name: " + method.getName());
//return method.invoke(o, objects); // 不能自己代理自己
return method.invoke(pan, objects);
}
}
);
// 使用代理 o,來呼叫到 Hello interface
Hello hello = (Hello) o;
hello.talk("Hello");
World world = (World) o;
System.out.println(world.say());
// 使用 IO 輸出自動生成的程式
try {
proxy();
} catch (Exception e) {
e.printStackTrace();
}
}
private static void proxy() throws Exception {
// 產生的 Class name
String name = "$Proxy0";
byte[] bytes = ProxyGenerator.generateProxyClass(name, new Class[]{Hello.class, World.class});
// IO 輸出的檔案名稱
FileOutputStream fos = new FileOutputStream("ProcessSource/" + name + ".class");
fos.write(bytes);
fos.close();
}
}
class Pan implements Hello, World{
@Override
public void talk(String s) {
System.out.println("talk: " + s);
}
@Override
public String say() {
return "World";
}
}
interface Hello {
void talk(String s);
}
interface World {
String say();
透過 ProxyGenerator#generateProxyClass
生成的程式
// 自動生成程式
public final class $Proxy0 extends Proxy implements Hello, World {
private static Method m1;
private static Method m2;
private static Method m3;
private static Method m4;
private static Method m0;
public $Proxy0(InvocationHandler var1) throws {
super(var1);
}
// object 方法
public final boolean equals(Object var1) throws {
try {
return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
} catch (RuntimeException | Error var3) {
throw var3;
} catch (Throwable var4) {
throw new UndeclaredThrowableException(var4);
}
}
// object 方法
public final String toString() throws {
try {
return (String)super.h.invoke(this, m2, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
// Hello 方法
public final void talk(String var1) throws {
try {
super.h.invoke(this, m3, new Object[]{var1});
} catch (RuntimeException | Error var3) {
throw var3;
} catch (Throwable var4) {
throw new UndeclaredThrowableException(var4);
}
}
// World 方法
public final String say() throws {
try {
return (String)super.h.invoke(this, m4, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
// object 方法
public final int hashCode() throws {
try {
return (Integer)super.h.invoke(this, m0, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
static {
//"1. "
try {
m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
m2 = Class.forName("java.lang.Object").getMethod("toString");
m3 = Class.forName("Hello").getMethod("talk", Class.forName("java.lang.String"));
m4 = Class.forName("World").getMethod("say");
m0 = Class.forName("java.lang.Object").getMethod("hashCode");
} catch (NoSuchMethodException var2) {
throw new NoSuchMethodError(var2.getMessage());
} catch (ClassNotFoundException var3) {
throw new NoClassDefFoundError(var3.getMessage());
}
}
}
A. 使用反射 getMethod (要看反射請點擊連結) 取得 Interface 中的 Function,並把 Method 存在內存中
B. 觀察它是如何調用 InvocationHandler 方法,可以看到我們在調用方法時都會調用 super.h.invoke (就是我們注入的 InvocationHandler 接口) (這樣就可以觀察到它每個參數的意思)
// 自動生成程式
public final void talk(String var1) throws {
try {
super.h.invoke(this, m3, new Object[]{var1});
} catch (RuntimeException | Error var3) {
throw var3;
} catch (Throwable var4) {
throw new UndeclaredThrowableException(var4);
}
}
public final String say() throws {
try {
// 沒有參數可以傳 null
return (String)super.h.invoke(this, m4, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
C. 最後透過匿名內部類,做出方法調用的真正類 invoke(Object),並以與做加強
Object o = Proxy.newProxyInstance(pan.getClass().getClassLoader(),
new Class[]{Hello.class, World.class}, // 不可代理類 String.class! 因為生成的類繼承 Proxy
new InvocationHandler() {
@Override
public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
System.out.println("----------------get Invoke-------------------");
System.out.println("Method Name: " + method.getName());
//return method.invoke(o, objects); // 不能自己代理自己
return method.invoke(pan, objects);
}
}
);
D. InvocationHandler 的返回是返回需要的參數 (它會強制轉型)
public final String say() throws {
try {
return (String)super.h.invoke(this, m4, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
分析動態代理:輸出 Proxy 類
● 在動態代理中並沒有發現到被代理類有繼承 Proxy,只有代理類實現 InvocationHandler 接口,先分析被代理類是如何實現的
// 1. 呼叫 Proxy 建構
Proxy getProxy() {
return (Proxy) Proxy.newProxyInstance(object.getClass().getClassLoader(), object.getClass().getInterfaces(), this);
}
// 2. Proxy 類
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException
{
Objects.requireNonNull(h);
final Class<?>[] intfs = interfaces.clone();
/*
* Look up or generate the designated proxy class.
*/
"1: "
Class<?> cl = getProxyClass0(loader, intfs);
try {
// 創建內存的實例
final Constructor<?> cons = cl.getConstructor(constructorParams);
final InvocationHandler ih = h;
if (!Modifier.isPublic(cl.getModifiers())) {
// 檢查方法訪問權限
cons.setAccessible(true);
}
"4: "return cons.newInstance(new Object[]{h});
} ...
}
// 分析第 1 點 getProxyClass0
private static Class<?> getProxyClass0(ClassLoader loader,
Class<?>... interfaces) {
if (interfaces.length > 65535) {
// 限制接口上限
throw new IllegalArgumentException("interface limit exceeded");
}
"2. "
return proxyClassCache.get(loader, interfaces);
}
// 分析第 2 點的 WeakCache 類的 get
public V get(K key, P parameter) {
Objects.requireNonNull(parameter);
expungeStaleEntries();
Object cacheKey = CacheKey.valueOf(key, refQueue);
...
"3. "
Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter));
Supplier<V> supplier = valuesMap.get(subKey);
Factory factory = null;
while (true) {
...
}
}
// 析第 3 點的 apply 是 BiFunction接口的方法,此接口由 Proxy.ProxyClassFactory 實現
public Class<?> apply(ClassLoader var1, Class<?>[] var2) {
...版本判別,處理兼容..
"4: "
long var19 = nextUniqueNumber.getAndIncrement();
String var23 = var16 + "$Proxy" + var19;
byte[] var22 = ProxyGenerator.generateProxyClass(var23, var2, var17);
try {
return Proxy.defineClass0(var1, var23, var22, 0, var22.length);
} catch (ClassFormatError var14) {
throw new IllegalArgumentException(var14.toString());
}
}
1. 分析如何取到 Class 對象
2. proxyClassCache 是 WeakCache 對象,是個泛型類
private static final WeakCache<ClassLoader, Class<?>[], Class<?>> proxyClassCache =
new WeakCache<>(new KeyFactory(), new ProxyClassFactory());
3. subKeyFactory 是 BiFunction 接口,是個泛型接口
private final BiFunction<K, P, ?> subKeyFactory
4. 利用原子操作(CAS) 創建類名,並透過 ProxyGenerator.generateProxyClass 創建 Class 再回返二進制文本,最後使用 defineClass0 (native類) 創建 Class
請注意類名,
$Proxy0
and$Proxy1
5. 利用反射的建構函數創建 Java 對象

UML
● 經過輸出流輸出了,ProxyGenerator 的數組(Java 反編譯 Class 流程)
import java.io.*;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.*;
import sun.misc.ProxyGenerator;
public class startCoding {
public static void main(String[] args) {
... 同上
ProxyClassUnit.makeOutputClass(s1.getClass().getName(), s1.getClass());
ProxyClassUnit.makeOutputClass(t1.getClass().getName(), t1.getClass());
}
}
... 同上
class ProxyClassUnit {
// ProxyGenerator.generateProxyClass(final String var0, Class<?>[] var1, int var2);
static void makeOutputClass(String name, Class<?> clz) {
byte[] clzBinary = ProxyGenerator.generateProxyClass(name, new Class[] {clz});
String paths = clz.getResource(".").getPath();
System.out.println("Path : " + name);
System.out.println("Name : " + paths);
try {
// 輸出至目錄下
OutputStream o = new FileOutputStream(paths + name + ".class");
BufferedOutputStream bos = new BufferedOutputStream(o);
bos.write(clzBinary);
bos.flush();
bos.close();
o.close();
} catch(Exception e) {
e.printStackTrace();
}
}
}
// s1 輸出檔案
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
public final class $Proxy0 extends Proxy implements $Proxy0 {
private static Method m1;
private static Method m5;
private static Method m3;
private static Method m2;
private static Method m6;
private static Method m11;
private static Method m13;
private static Method m0;
private static Method m8;
private static Method m12;
private static Method m7;
private static Method m10;
private static Method m4;
private static Method m9;
public $Proxy0(InvocationHandler paramInvocationHandler) {
super(paramInvocationHandler);
}
public final boolean equals(Object paramObject) {
try {
return ((Boolean)this.h.invoke(this, m1, new Object[] { paramObject })).booleanValue();
} catch (Error|RuntimeException error) {
throw null;
} catch (Throwable throwable) {
throw new UndeclaredThrowableException(throwable);
}
}
public final InvocationHandler getInvocationHandler(Object paramObject) throws IllegalArgumentException {
try {
return (InvocationHandler)this.h.invoke(this, m5, new Object[] { paramObject });
} catch (Error|RuntimeException error) {
throw null;
} catch (Throwable throwable) {
throw new UndeclaredThrowableException(throwable);
}
}
public final String getBook() {
try {
return (String)this.h.invoke(this, m3, null);
} catch (Error|RuntimeException error) {
throw null;
} catch (Throwable throwable) {
throw new UndeclaredThrowableException(throwable);
}
}
public final String toString() {
try {
return (String)this.h.invoke(this, m2, null);
} catch (Error|RuntimeException error) {
throw null;
} catch (Throwable throwable) {
throw new UndeclaredThrowableException(throwable);
}
}
public final Class getProxyClass(ClassLoader paramClassLoader, Class[] paramArrayOfClass) throws IllegalArgumentException {
try {
return (Class)this.h.invoke(this, m6, new Object[] { paramClassLoader, paramArrayOfClass });
} catch (Error|RuntimeException error) {
throw null;
} catch (Throwable throwable) {
throw new UndeclaredThrowableException(throwable);
}
}
public final Class getClass() {
try {
return (Class)this.h.invoke(this, m11, null);
} catch (Error|RuntimeException error) {
throw null;
} catch (Throwable throwable) {
throw new UndeclaredThrowableException(throwable);
}
}
public final void notifyAll() {
try {
this.h.invoke(this, m13, null);
return;
} catch (Error|RuntimeException error) {
throw null;
} catch (Throwable throwable) {
throw new UndeclaredThrowableException(throwable);
}
}
public final int hashCode() {
try {
return ((Integer)this.h.invoke(this, m0, null)).intValue();
} catch (Error|RuntimeException error) {
throw null;
} catch (Throwable throwable) {
throw new UndeclaredThrowableException(throwable);
}
}
public final void wait() throws InterruptedException {
try {
this.h.invoke(this, m8, null);
return;
} catch (Error|RuntimeException|InterruptedException error) {
throw null;
} catch (Throwable throwable) {
throw new UndeclaredThrowableException(throwable);
}
}
public final void notify() {
try {
this.h.invoke(this, m12, null);
return;
} catch (Error|RuntimeException error) {
throw null;
} catch (Throwable throwable) {
throw new UndeclaredThrowableException(throwable);
}
}
public final Object newProxyInstance(ClassLoader paramClassLoader, Class[] paramArrayOfClass, InvocationHandler paramInvocationHandler) throws IllegalArgumentException {
try {
return this.h.invoke(this, m7, new Object[] { paramClassLoader, paramArrayOfClass, paramInvocationHandler });
} catch (Error|RuntimeException error) {
throw null;
} catch (Throwable throwable) {
throw new UndeclaredThrowableException(throwable);
}
}
public final void wait(long paramLong) throws InterruptedException {
try {
this.h.invoke(this, m10, new Object[] { Long.valueOf(paramLong) });
return;
} catch (Error|RuntimeException|InterruptedException error) {
throw null;
} catch (Throwable throwable) {
throw new UndeclaredThrowableException(throwable);
}
}
public final boolean isProxyClass(Class paramClass) {
try {
return ((Boolean)this.h.invoke(this, m4, new Object[] { paramClass })).booleanValue();
} catch (Error|RuntimeException error) {
throw null;
} catch (Throwable throwable) {
throw new UndeclaredThrowableException(throwable);
}
}
public final void wait(long paramLong, int paramInt) throws InterruptedException {
try {
this.h.invoke(this, m9, new Object[] { Long.valueOf(paramLong), Integer.valueOf(paramInt) });
return;
} catch (Error|RuntimeException|InterruptedException error) {
throw null;
} catch (Throwable throwable) {
throw new UndeclaredThrowableException(throwable);
}
}
static {
try {
m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") });
m5 = Class.forName("$Proxy0").getMethod("getInvocationHandler", new Class[] { Class.forName("java.lang.Object") });
m3 = Class.forName("$Proxy0").getMethod("getBook", new Class[0]);
m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
m6 = Class.forName("$Proxy0").getMethod("getProxyClass", new Class[] { Class.forName("java.lang.ClassLoader"), Class.forName("[Ljava.lang.Class;") });
m11 = Class.forName("$Proxy0").getMethod("getClass", new Class[0]);
m13 = Class.forName("$Proxy0").getMethod("notifyAll", new Class[0]);
m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
m8 = Class.forName("$Proxy0").getMethod("wait", new Class[0]);
m12 = Class.forName("$Proxy0").getMethod("notify", new Class[0]);
m7 = Class.forName("$Proxy0").getMethod("newProxyInstance", new Class[] { Class.forName("java.lang.ClassLoader"), Class.forName("[Ljava.lang.Class;"), Class.forName("java.lang.reflect.InvocationHandler") });
m10 = Class.forName("$Proxy0").getMethod("wait", new Class[] { long.class });
m4 = Class.forName("$Proxy0").getMethod("isProxyClass", new Class[] { Class.forName("java.lang.Class") });
m9 = Class.forName("$Proxy0").getMethod("wait", new Class[] { long.class, int.class });
return;
} catch (NoSuchMethodException noSuchMethodException) {
throw new NoSuchMethodError(noSuchMethodException.getMessage());
} catch (ClassNotFoundException classNotFoundException) {
throw new NoClassDefFoundError(classNotFoundException.getMessage());
}
}
}
● 以上是 Proxy0 繼承了 Proxy 類並實作了 BookShop and Object 接口
getBook 這個方法的實現是透過調用 this.h,這個 h 是Proxy 中的 InvocationHandler,而這個 InvocationHandler 是由 CommonProxyShop 這個 class
結論 : 由代理類創造的動態代理 Proxy 類傳入的 InvocationHandler
會由 Proxy 類調用,接著讓使用者自己實現其方法
--實作--
更多的物件導向設計
物件導向的設計基礎如下,如果是初學者或是不熟悉的各位,建議可以從這些基礎開始認識,打好基底才能走個更穩(在學習的時候也需要不斷回頭看)!
創建模式:Creation Patterns
● 創建模式 PK
● 創建模式 - Creation Patterns
:
創建模式用於「物件的創建」,它關注於如何更靈活、更有效地創建物件。這些模式可以隱藏創建物件的細節,並提供創建物件的機制,例如單例模式、工廠模式… 等等,詳細解說請點擊以下連結
● Singleton 單例模式 | 解說實現 | Android Framework Context Service
● Abstract Factory 設計模式 | 實現解說 | Android MediaPlayer
● Factory 工廠方法模式 | 解說實現 | Java 集合設計
● Builder 建構者模式 | 實現與解說 | Android Framwrok Dialog 視窗
● Clone 原型模式 | 解說實現 | Android Framework Intent
行為模式:Behavioral Patterns
● 行為模式 PK
● 行為模式 - Behavioral Patterns
:
行為模式關注物件之間的「通信」和「職責分配」。它們描述了一系列物件如何協作,以完成特定任務。這些模式專注於改進物件之間的通信,從而提高系統的靈活性。例如,策略模式、觀察者模式… 等等,詳細解說請點擊以下連結
● Stragety 策略模式 | 解說實現 | Android Framework 動畫
● Interpreter 解譯器模式 | 解說實現 | Android Framework PackageManagerService
● Chain 責任鏈模式 | 解說實現 | Android Framework View 事件傳遞
● Specification 規格模式 | 解說實現 | Query 語句實做
● Command 命令、Servant 雇工模式 | 實現與解說 | 物件導向設計
● Memo 備忘錄模式 | 實現與解說 | Android Framwrok Activity 保存
● Visitor 設計模式 | 實現與解說 | 物件導向設計
● Template 設計模式 | 實現與解說 | 物件導向設計
● Mediator 模式設計 | 實現與解說 | 物件導向設計
● Composite 組合模式 | 實現與解說 | 物件導向設計
● Observer 觀察者模式 | JDK Observer | Android Framework Listview
結構模式:Structural Patterns
● 結構模式 PK
● 結構模式 - Structural Patterns
:
結構模式專注於「物件之間的組成」,以形成更大的結構。這些模式可以幫助你確保當系統進行擴展或修改時,不會破壞其整體結構。例如,外觀模式、代理模式… 等等,詳細解說請點擊以下連結
● Decorate 裝飾模式 | 解說實現 | 物件導向設計
● Iterator 迭代設計 | 解說實現 | 物件導向設計