---
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 設計模式` `反射`