--- title: 'Proxy 代理模式' disqus: kyleAlien --- Proxy 代理模式 === ## Overview of Content 如有引用參考請詳註出處,感謝 :smile: > 動態代理使會用到 [**Java 反射**](https://hackmd.io/@tGUW53vxShaIEpRyCmVZbg/rk-ZVRvz8),動態代理使用的地方也很多,像是 **Android Retrofit 就有使用到,一般我們在 Hook 資料時也常使用到** :::success * 如果喜歡讀更好看一點的網頁版本,可以到我新做的網站 [**DevTech Ascendancy Hub**](https://devtechascendancy.com/) 本篇文章對應的是 [**Proxy 代理模式 | 解說實現 | 分析動態代理**](https://devtechascendancy.com/object-oriented_design_proxy_dynamic-proxy/) ::: [TOC] ## Proxy 概述 代理可做到加強源類,也可隔離,JDK 有提供接口,並且代理類分為兩種 ^1.^ 靜態代理、^2.^ 動態代理 ### Proxy 定義 & Proxy UML * Proxy 定義:為其他物件提供代理來訪問目標物件 * Proxy UML、角色關係 | 類 | 關係 | | - | - | | Subject (抽象、接口) | 定義一個對外的抽象方法 | | RealSubject | 實際實現業務者 | | Proxy | 代理 RealSubject 對象,**內部持有一個 Subject 對象,將所有實做委託給真實對象(RealSubject)** | > ![](https://i.imgur.com/qoqFvQt.png) ### Proxy 設計 - 優缺點 1. **Proxy 設計 ==靜態代理==** * 優點:運行速度較快 * 缺點:**不符合開閉原則**,維護代價較高,會為了增加功能而不斷新增修改代理類 :::info * 當代理類(Proxy)需要代理多個不同接口時就必須修改,維護成本會提高 ::: 2. **Proxy 設計 ==動態代理==**:使用反射需要時才創建 * 優點:透過 JDK 自動生成代碼,在運行時加強代碼 * 缺點:速度較慢 ## Proxy 實現 ### Proxy - 普通代理 * **普通代理的意思**:使用者不必知道真實類是誰,而是透過代理類來訪問對象(這符合迪米特原則,不用讓外部了解代理的相關類) > 以下範例,代理書本購買 1. **`Subject` 抽象**:AlienShop 定義對外暴露的方法 ```kotlin= interface AlienShop { fun buyBook(name: String) fun getBook(): String } ``` 2. **`RealSubject` 類**:RealShop 實做購買書籍的邏輯 ```kotlin= class RealShop : AlienShop { override fun buyBook(name: String) { println("$name book the Book") } override fun getBook(): String { return "平行世界" } } ``` 3. **`Proxy` 類**:在代理類中可以加強原來的方法,但是到實際要執行時,仍是執行 RealSubject 的方法 ```kotlin= 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 使用代理設計 ```kotlin= fun main() { val shop : AlienShop = ProxyShop().also { it.buyBook("Kyle") println(it.getBook()) } } ``` > ![](https://i.imgur.com/Uk7aTHm.png) ### Proxy - 強制代理 * **強制代理**:強制代理是代理設計中比較特別的概念,作為強制代理設計的使用者,**你 ++可以直接接觸到實做類++,你可以選擇是否直接訪問該類的方法,++或是透過該類指定的代理類你才能代理++** 1. **`Subject` 抽象**:該抽象重點是增加了一個 `getProxy` 方法,返回了一個 Subject 抽象,這個方法就是強制代理的重點之一 > 當然,如果想想要實作「強制的特性」,那就不要對外暴露可操作的方法介面,可以透過 [**介面隔離原則**](https://devtechascendancy.com/object-oriented-design-principles_2/#%E4%BB%8B%E9%9D%A2%E9%9A%94%E9%9B%A2%E5%8E%9F%E5%89%87_%E2%80%93_Interface_Segregation) 來區分內外介面 ```kotlin= interface IPlayGame { fun play() fun getProxy() : IPlayGame } ``` 2. **`RealSubject` 類**:實做 IPlayGame 接口,對於 `getProxy` 則定義一個指定的代理類! ```kotlin= class AlienPlay : IPlayGame { private var proxy : IPlayGame? = null override fun play() { proxy.let { if (it == null) { println("Call proxy to play") return } println("Playing game now ~") } } override fun getProxy(): IPlayGame { // 創建指定代理類 proxy = AppleProxyPlay(this) return proxy!! } } ``` 3. **`Proxy` 類**:代理類同樣使用 RealSubject 的實做;這裡的 `getProxy` 則返回自身 :::info 當然這裡的代理類還是可以返回其他的代理,不一定要返回 `this` ::: ```kotlin= 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 使用強制代理 ```kotlin= fun main() { AlienPlay().run { // 沒透過代理類不能訪問 play() // 必須透過代理類才能訪問! getProxy().play() } } ``` > ![](https://i.imgur.com/nQPh7Uz.png) ## 動態代理 動態代理與靜態代理最大的差別在於,**++動態代理載運行時才指定代理對象++(指定代理接口)** :::info * **動態代理內部原理**: **Java 動態代理在源碼中是使用了 ++反射的技巧++** :::warning * **應用場景侷限**: 由於 Proxy 類是 class 並非 `interface`,而 Java 是單繼承 (每個代理類都繼承了 Proxy 類,等等可以看到),即 **==++只能對接口創建代理++==,不對類創建代理類** ::: ::: ### InvocationHandler 介面 & 動態代理 UML * **`InvocationHandler` 是一個介面(接口),它的功能相當於一個 Hook Callback,在調用真正方法前會先調遇到這個方法** (分析碼可以看見),代理類一定要實現這個介面(接口) > ![](https://i.imgur.com/ALA12b5.png) * **動態代理 UML** 動態代理透過自動生成的 Proxy 類,並使用生成的 Proxy 類來訪問真正時做類 (概念如同靜態,但它的彈性較大,許多框架都會使用到這個設計概念) > ![](https://i.imgur.com/Vytr7xR.png) ### 動態代理 - 實體類 * 直接看動態代理的範例 ```java= 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; } ``` **--實做--** > ![](https://i.imgur.com/IaNAX4O.png) ### 動態代理 - 匿名類 * 其實跟上面的是相同的,只是把 InvocationHandler 改為匿名類 (順便多了個範例) :slightly_smiling_face: :::danger 注意反射時帶入的物件要帶入 **目標代理對象**,不要寫成代理自身 ::: ```java= 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(); } ``` **--實作--** > ![](https://i.imgur.com/h6a1m0O.png) ## 解析 Proxy 生成動態代理類 ### IO 輸出 Proxy 類 * 在這裡我們要查看自動生成的程式,會使用到 IO 流輸出檔案 (將自動生成的程式輸出,這樣我們才可以看到~ ) * **在++代理內找到的方法可以做用在不同的 class 實例++中 (該 class 必須要此方法)** | Function | 功能 | | -------- | -------- | | ProxyGenerator.generateProxyClass | 自動在 ==**內存**== 產生代理類 | ```java= // 動態代理範例 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(); ``` :::spoiler 自動產生 Code 結果 * 透過 ProxyGenerator#`generateProxyClass` 生成的程式 ```java= // 自動生成程式 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()); } } } ``` ::: 1. 使用[**反射 getMethod**](https://hackmd.io/cuMlqQZ4QcujENqlkA1Zrw?both#呼叫方法---getMethod) (要看反射請點擊連結) 取得 Interface 中的 Function,並把 Method 存在內存中 2. 觀察它是如何調用 InvocationHandler 方法,可以看到**我們在調用方法時都會調用 ==super.h.invoke== (就是我們注入的 InvocationHandler 接口)** (這樣就可以觀察到它每個參數的意思) ```java= // 自動生成程式 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); } ``` 3. 最後透過匿名內部類,做出方法調用的真正類 invoke(Object),並以與做加強 ```java= 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); } } ); ``` 4. InvocationHandler 的返回是返回需要的參數 (它會強制轉型) ```java= 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 接口,先分析被代理類是如何實現的 ```java= // 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 對象,是個泛型類 ```java= private static final WeakCache<ClassLoader, Class<?>[], Class<?>> proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory()); ``` > ![](https://i.imgur.com/GLuJ07a.png) 3. subKeyFactory 是 BiFunction 接口,是個泛型接口 ```java= private final BiFunction<K, P, ?> subKeyFactory ``` > ![](https://i.imgur.com/UazdLwa.png) 4. 利用原子操作(CAS) 創建類名,並透過 ProxyGenerator.generateProxyClass 創建 Class 再回返二進制文本,最後使用 defineClass0 (native類) 創建 Class > 請**注意類名,$Proxy0 and $Proxy1** > ![](https://i.imgur.com/XdLWk7w.png) 5. 利用反射的建構函數創建 Java 對象 ```sequence User -> CommonProxyShop: getProxy():Proxy CommonProxyShop -> Proxy: newProxyInstance():Object Proxy -> Proxy:getProxyClass0:Class<?> Proxy -> WeakCache(泛):get():V WeakCache(泛) -> BiFunction(泛):apply:R ``` ```sequence BiFunction(泛) -> ProxyClassFactory: apply ProxyClassFactory -> ProxyGenerator: generateProxyClass():byte[] ProxyClassFactory -> ProxyClassFactory: defineClass0:Class<?> ProxyClassFactory -> Proxy: Proxy -> CommonProxyShop:newInstance:Object ``` > UML > ![](https://i.imgur.com/frKqBKF.png) * 經過輸出流輸出了,ProxyGenerator 的數組([**Java 反編譯 Class 流程**](http://java-decompiler.github.io/)) ```java= 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 > > ![](https://i.imgur.com/gfhzobt.png) > > > 結論 : 由代理類創造的動態代理 Proxy 類傳入的 InvocationHandler 會由 Proxy 類調用,接著讓使用者自己實現其方法 > **--實作--** > ![](https://i.imgur.com/CENbG5F.png) ## 更多的物件導向設計 物件導向的設計基礎如下,如果是初學者或是不熟悉的各位,建議可以從這些基礎開始認識,打好基底才能走個更穩(在學習的時候也需要不斷回頭看)! :::info * [**設計建模 2 大概念- UML 分類、使用**](https://devtechascendancy.com/introduction-to-uml-and-diagrams/) * [**物件導向設計原則 – 6 大原則(一)**](https://devtechascendancy.com/object-oriented-design-principles_1/) * [**物件導向設計原則 – 6 大原則(二)**](https://devtechascendancy.com/object-oriented-design-principles_2/) ::: ### 創建模式 - Creation Patterns * [**創建模式 PK**](https://devtechascendancy.com/pk-design-patterns-factory-builder-best/) * **創建模式 - `Creation Patterns`**: 創建模式用於「**物件的創建**」,它關注於如何更靈活、更有效地創建對象。這些模式可以隱藏創建對象的細節,並提供創建對象的機制,例如單例模式、工廠模式… 等等,詳細解說請點擊以下連結 :::success * [**Singleton 單例模式 | 解說實現 | Android Framework Context Service**](https://devtechascendancy.com/object-oriented_design_singleton/) * [**Abstract Factory 設計模式 | 實現解說 | Android MediaPlayer**](https://devtechascendancy.com/object-oriented_design_abstract-factory/) * [**Factory 工廠方法模式 | 解說實現 | Java 集合設計**](https://devtechascendancy.com/object-oriented_design_factory_framework/) * [**Builder 建構者模式 | 實現與解說 | Android Framwrok Dialog 視窗**](https://devtechascendancy.com/object-oriented_design_builder_dialog/) * [**Clone 原型模式 | 解說實現 | Android Framework Intent**](https://devtechascendancy.com/object-oriented_design_clone_framework/) * [**Object Pool 設計模式 | 實現與解說 | 利用 JVM**](https://devtechascendancy.com/object-oriented_design_object-pool/) * [**Flyweight 享元模式 | 實現與解說 | 物件導向設計**](https://devtechascendancy.com/object-oriented_design_flyweight/) ::: ### 行為模式 - Behavioral Patterns * [**行為模式 PK**](https://devtechascendancy.com/pk-design-patterns-cmd-strat-state-obs-chain/) * **行為模式 - `Behavioral Patterns`**: 行為模式關注物件之間的「**通信**」和「**職責分配**」。它們描述了一系列對象如何協作,以完成特定任務。這些模式專注於改進物件之間的通信,從而提高系統的靈活性。例如,策略模式、觀察者模式… 等等,詳細解說請點擊以下連結 :::warning * [**Stragety 策略模式 | 解說實現 | Android Framework 動畫**](https://devtechascendancy.com/object-oriented_design_stragety_framework/) * [**Interpreter 解譯器模式 | 解說實現 | Android Framework PackageManagerService**](https://devtechascendancy.com/object-oriented_design_interpreter_framework/) * [**Chain 責任鏈模式 | 解說實現 | Android Framework View 事件傳遞**](https://devtechascendancy.com/object-oriented_design_chain_framework/) * [**State 狀態模式 | 實現解說 | 物件導向設計**](https://devtechascendancy.com/object-oriented_design_state/) * [**Specification 規格模式 | 解說實現 | Query 語句實做**](https://devtechascendancy.com/object-oriented_design_specification-query/) * [**Command 命令、Servant 雇工模式 | 實現與解說 | 物件導向設計**](https://devtechascendancy.com/object-oriented_design_command_servant/) * [**Memo 備忘錄模式 | 實現與解說 | Android Framwrok Activity 保存**](https://devtechascendancy.com/object-oriented_design_memo_framework/) * [**Visitor 設計模式 | 實現與解說 | 物件導向設計**](https://devtechascendancy.com/object-oriented_design_visitor_dispatch/) * [**Template 設計模式 | 實現與解說 | 物件導向設計**](https://devtechascendancy.com/object-oriented_design_template/) * [**Mediator 模式設計 | 實現與解說 | 物件導向設計**](https://devtechascendancy.com/object-oriented_programming_mediator/) * [**Composite 組合模式 | 實現與解說 | 物件導向設計**](https://devtechascendancy.com/object-oriented_programming_composite/) ::: ### 結構模式 - Structural Patterns * [**結構模式 PK**](https://devtechascendancy.com/pk-design-patterns-proxy-decorate-adapter/) * **結構模式 - `Structural Patterns`**: 結構模式專注於「物件之間的組成」,以形成更大的結構。這些模式可以幫助你確保當系統進行擴展或修改時,不會破壞其整體結構。例如,外觀模式、代理模式… 等等,詳細解說請點擊以下連結 :::danger * [**Bridge 橋接模式 | 解說實現 | 物件導向設計**](https://devtechascendancy.com/object-oriented_design_bridge/) * [**Decorate 裝飾模式 | 解說實現 | 物件導向設計**](https://devtechascendancy.com/object-oriented_design_decorate/) * [**Proxy 代理模式 | 解說實現 | 分析動態代理**](https://devtechascendancy.com/object-oriented_design_proxy_dynamic-proxy/) * [**Iterator 迭代設計 | 解說實現 | 物件導向設計**](https://devtechascendancy.com/object-oriented_design_iterator/) * [**Facade 外觀、門面模式 | 解說實現 | 物件導向設計**](https://devtechascendancy.com/object-oriented_design_facade/) * [**Adapter 設計模式 | 解說實現 | 物件導向設計**](https://devtechascendancy.com/object-oriented_design_adapter/) ::: ## Appendix & FAQ :::info ::: ###### tags: `Java 設計模式` `反射`