結構型設計模式
阿新 • • 發佈:2018-12-09
owa package ret public sub intercept pro eth 磁盤 架構型設計模式成員
- 門面模式
- 代理模式
- 裝飾器模式
- 組合模式
- 享元模式
- 橋接模式
- 適配器模式
1. 代理模式
1.1 定義
為其他對象提供一種代理以控制對這個對象的訪問
解決問題:在直接訪問對象時帶來的問題,比如說:要訪問的對象在遠程的機器上。在面向對象系統中,有些對象由於某些原因(比如對象創建開銷很大,或者某些操作需要安全控制,或者需要進程外的訪問),直接訪問會給使用者或者系統結構帶來很多麻煩,我們可以在訪問此對象時加上一個對此對象的訪問層
1.2 分類
1.2.1 靜態代理
- 一個代理類只能對一個業務接口的實現類進行包裝,如果有多個業務接口的話就要定義很多實現類和代理類才行
- 而且,如果代理類對業務方法的預處理、調用後操作都是一樣的(比如:調用前輸出提示、調用後自動關閉連接),則多個代理類就會有很多重復代碼
接口類 package com.zhunongyun.spring.proxy; public interface Image { void display(); void change(String imagePath); } -------------------------------------------------- 接口的實現類 package com.zhunongyun.spring.proxy; public class RealImage implements Image { private String fileName; public RealImage(String fileName){ this.fileName = fileName; loadFromDisk(fileName); } @Override public void display() { System.out.println("顯示圖片: " + fileName); } @Override public void change(String imagePath) { System.out.println("替換圖片: " + imagePath); } private void loadFromDisk(String fileName){ System.out.println("加載圖片: " + fileName); } } ------------------------------------------------------- 代理類 package com.zhunongyun.spring.proxy; public class ProxyImage implements Image{ private RealImage realImage; private String fileName; public ProxyImage(String fileName){ this.fileName = fileName; } @Override public void display() { if(realImage == null){ realImage = new RealImage(fileName); } realImage.display(); } @Override public void change(String imagePath) { if(realImage == null){ realImage = new RealImage(fileName); } realImage.change(imagePath); } } --------------------------------------------------- 測試類 package com.zhunongyun.spring.proxy; public class ProxyPatternDemo { public static void main(String[] args) { Image image = new ProxyImage("test_10mb.jpg"); // 圖像將從磁盤加載 image.display(); System.out.println("---------------------"); // 圖像不需要從磁盤加載 image.display(); } } 輸出結果: 加載圖片: test_10mb.jpg 顯示圖片: test_10mb.jpg --------------------- 顯示圖片: test_10mb.jpg
1.2.2 動態代理
1.2.2.1 JDK 自帶的動態代理
- java.lang.reflect.Proxy: 生成動態代理類和對象
- java.lang.reflect.InvocationHandler(處理器接口):可以通過invoke方法實現對真實角色的代理訪問
每次通過 Proxy 生成的代理類對象都要指定對應的處理器對象
接口類 package com.zhunongyun.spring.proxy.dynamic; public interface Subject { int sellBooks(); String speak(); } --------------------------------------------------------- 接口實現類 package com.zhunongyun.spring.proxy.dynamic; public class RealSubject implements Subject{ @Override public int sellBooks() { System.out.println("賣書"); return 1 ; } @Override public String speak() { System.out.println("說話"); return "張三"; } } ------------------------------------------------------------------ 動態代理類 package com.zhunongyun.study.toalibaba.spring.proxy.dynamic; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; /** * 定義一個處理器 * * @author gnehcgnaw * @date 2018/11/5 19:26 */ public class MyInvocationHandler implements InvocationHandler { /** * 這其實業務實現類對象,用來調用具體的業務方法 */ private Object target; /** * 綁定業務對象並返回一個代理類 */ public Object bind(Object target) { //接收業務實現類對象參數 this.target = target; //通過反射機制,創建一個代理類對象實例並返回。用戶進行方法調用時使用 //創建代理對象時,需要傳遞該業務類的類加載器(用來獲取業務實現類的元數據,在包裝方法是調用真正的業務方法)、接口、handler實現類 return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this); } /** * @param proxy 代理類 * @param method 正在調用的方法 * @param args 方法的參數 * @return * @throws Throwable */ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Object result=null; System.out.println("預處理操作——————"); //調用真正的業務方法 result=method.invoke(target, args); System.out.println("調用後處理——————"); return result; } } ------------------------------------------------------------------- 測試類 package com.zhunongyun.spring.proxy.dynamic; import java.lang.reflect.Proxy; /** * 調用類 * @author gnehcgnaw * @date 2018/11/7 20:26 */ public class Client { public static void main(String[] args) { //真實對象 Subject realSubject = new RealSubject(); MyInvocationHandler myInvocationHandler = new MyInvocationHandler(realSubject); //代理對象 Subject proxyClass = (Subject) Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(), new Class[]{Subject.class}, myInvocationHandler); proxyClass.sellBooks(); proxyClass.speak(); } } ------------------------------------------------------------------------ 輸出結果: 預處理操作—————— 賣書 調用後處理—————— 預處理操作—————— 說話 調用後處理——————
1.2.2.2 CGlib動態代理
操作類
package com.zhunongyun.study.toalibaba.spring.proxy.cglib;
public class BookFacadeImpl {
public void addBook() {
System.out.println("新增圖書...");
}
}
-------------------------------------------
CGlib代理類
package com.zhunongyun.study.toalibaba.spring.proxy.cglib;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
public class BookFacadeCglib implements MethodInterceptor {
/**
* 業務類對象,供代理方法中進行真正的業務方法調用
*/
private Object target;
/**
* 相當於JDK動態代理中的綁定
* @param target
* @return
*/
public Object getInstance(Object target) {
//給業務對象賦值
this.target = target;
//創建加強器,用來創建動態代理類
Enhancer enhancer = new Enhancer();
//為加強器指定要代理的業務類(即:為下面生成的代理類指定父類)
enhancer.setSuperclass(this.target.getClass());
//設置回調:對於代理類上所有方法的調用,都會調用CallBack,而Callback則需要實現intercept()方法進行攔
enhancer.setCallback(this);
// 創建動態代理類對象並返回
return enhancer.create();
}
/**
* 實現回調方法
* @param obj
* @param method
* @param args
* @param proxy
* @return
* @throws Throwable
*/
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println("預處理——————");
//調用業務類(父類中)的方法
proxy.invokeSuper(obj, args);
System.out.println("調用後操作——————");
return null;
}
}
------------------------------------------------
測試類
package com.zhunongyun.study.toalibaba.spring.proxy.cglib;
public class CglibDemo {
public static void main(String[] args) {
BookFacadeImpl bookFacade = new BookFacadeImpl();
BookFacadeCglib cglib = new BookFacadeCglib();
BookFacadeImpl bookCglib = (BookFacadeImpl) cglib.getInstance(bookFacade);
bookCglib.addBook();
}
}
----------------------------------------
輸出結果
預處理——————
新增圖書...
調用後操作——————
1.2.2.3 JDK動態代理與CGlib動態代理
- JDK動態代理是通過接口中的方法名,在動態生成的代理類中調用業務實現類的同名方法
- CGlib動態代理是通過繼承業務類,生成的動態代理類是業務類的子類,通過重寫業務方法進行代理
結構型設計模式