設計模式之結構性模式(一)
設計模式之結構性模式(一)
一、介面卡模式
二、代理模式
核心作用:從程式的結構上實現鬆耦合,從而可以擴大整體的類結構,解決更大的問題
分類:介面卡模式、代理模式、橋接模式、裝飾模式、組合模式、外觀模式、享元模式
一、介面卡模式
將一個類的介面轉換成客戶希望的另一個介面,可以使原本由於介面不相容而不能一起工作的類可以一起工作
模式中的角色:
目標介面(Target):客戶所期待的介面,目標可以是具體的或抽象的類,也可以是介面
需要適配的類(Adaptee):需要適配的類或適配者的類
介面卡(Adapter):通過包裝一個需要適配的物件,把原介面轉換成目標介面
例項:電腦(Client) 轉換器(Adapter) 鍵盤(Adaptee)
Adaptee
/**
* 被適配的類(相當於鍵盤)
*/
package com.adapter;
public class Adaptee {
//需求
public void request() {
System.out.println("可以完成客戶端請求需要的功能");
}
}
Adapter(類介面卡)
/** * 介面卡(相當於轉接器,USB) */ package com.adapter; public class Adapter extends Adaptee implements Target{ @Override public void handleRequest() { super.request(); } }
Target
//目標介面
package com.adapter;
public interface Target {
//處理需求的方法
public void handleRequest();
}
Adapter2(物件是介面卡)
/** * 介面卡(相當於轉接器) */ package com.adapter; public class Adapter2 implements Target { Adaptee adaptee; public Adapter2(Adaptee adaptee) { super(); this.adaptee = adaptee; } @Override public void handleRequest() { adaptee.request(); } }
Client
/**
* 客戶端類(相當於筆記本,只有USB介面)
*/
package com.adapter;
public class Client {
public void test(Target t) {
t.handleRequest();
}
public static void main(String[] args) {
Client laptop = new Client();//電腦(客戶端)
Adaptee keyboard = new Adaptee();//鍵盤(適配的類)
//Target adapter = new Adapter();//介面卡(轉換器)
Target adapter = new Adapter2(keyboard);//介面卡(轉換器)
laptop.test(adapter);
}
}
結果:
可以完成客戶端請求需要的功能
二、代理模式
核心作用:通過代理,控制對物件的訪問
可以詳細控制訪問某個物件的方法,在呼叫這個方法前做前置處理,呼叫這個方法後做後置處理(AOP的微觀實現)
AOP:Aspect Oriented Progrmming 面向切面程式設計的核心機制
核心角色:
抽象角色:定義代理角色和真實角色的公共對外方法
真實角色:實現抽象角色,定義真實角色所要實現的業務邏輯,供代理角色呼叫(關注真正的業務邏輯)
代理角色:實現抽象角色,是真實角色的代理,通過真實角色的業務邏輯方法來實現抽象方法,並可以附加自己的操作(將統一的流程控制放到代理角色中處理)
應用場景:
安全代理:遮蔽對真實角色的直接訪問
遠端代理:通過代理類處理遠端方法呼叫(RMI)
延時載入:先載入輕量級的代理物件,真正需要再載入真實物件
(比如開發一個大文件檢視軟體,大文件中有大的圖片,有可能一個圖片有100MB,在開啟檔案時,不可能將所有檔案都顯示出來,這樣就可以使用代理模式,當需要檢視圖片時,用proxy來進行大圖片的開啟)
分類:
靜態代理(靜態定義代理類)
動態代理(動態定義代理類)
1)JDK自帶的動態代理
2)javaassist位元組碼操作庫實現
3)CGLIB
4)ASM(底層使用指令,可維護性較差)
靜態代理類
例項:明星 明星代理人
Star
/**
* 明星介面
*/
package com.proxy.staticProxy;
public interface Star {
public void confer();//面談
public void signContract();//籤合同
public void bookTicket();//訂機票
public void sing();//唱歌
public void collectMoney();//收錢
}
RealStar
/**
* 明星本人
*/
package com.proxy.staticProxy;
public class RealStar implements Star {
@Override
public void confer() {
System.out.println("RealStar.confer()");
}
@Override
public void signContract() {
System.out.println("RealStar.signContract()");
}
@Override
public void bookTicket() {
System.out.println("RealStar.bookTicket()");
}
@Override
public void sing() {
System.out.println("RealStar.sing()(明星本人)");
}
@Override
public void collectMoney() {
System.out.println("RealStar.collectMoney()");
}
}
ProxyStar
/**
* 明星代理人
*/
package com.proxy.staticProxy;
public class ProxyStar implements Star {
@Override
public void confer() {
System.out.println("ProxyStar.confer()");
}
@Override
public void signContract() {
System.out.println("ProxyStar.signContract()");
}
@Override
public void bookTicket() {
System.out.println("ProxyStar.bookTicket()");
}
@Override
public void sing() {
System.out.println("RealStar.sing()");
}
@Override
public void collectMoney() {
System.out.println("ProxyStar.collectMoney()");
}
}
Client
/**
* 測試函式
*/
package com.proxy.staticProxy;
public class Client {
public static void main(String[] args) {
Star realStar = new RealStar();
Star proxyStar = new ProxyStar();
proxyStar.confer();
proxyStar.bookTicket();
proxyStar.signContract();
proxyStar.collectMoney();
proxyStar.sing();
}
}
結果
ProxyStar.confer()
ProxyStar.bookTicket()
ProxyStar.signContract()
ProxyStar.collectMoney()
RealStar.sing()//注意
動態代理類
JDK自帶的動態代理
Star
RealStar
StarHandler
package dynasticProxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class StarHandler implements InvocationHandler {//處理器介面
//建立真實的明星
Star realStar = null;
//構造器
public StarHandler(Star realStar) {
super();
this.realStar = realStar;
}
//通過invoke()方法實現對真實角色的代理訪問
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object object = null;
System.out.println("真正的方法執行前");
System.out.println("面談、籤合同、待付款、訂機票");
//如果是sing,就呼叫realStar()方法
if(method.getName().equals("sing")) {
object = method.invoke(realStar, args);
}
System.out.println("真正的方法執行後");
System.out.println("收尾款");
return object;
}
}
Client
package dynasticProxy;
import java.lang.reflect.Proxy;
public class Client {
public static void main(String[] args) {
Star realStar = new RealStar();
StarHandler handler = new StarHandler(realStar);
//每次通過Proxy生成代理類處理物件時,都要指定對應的處理器物件
Star proxy = (Star) Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(),new Class[]{Star.class} ,handler );
proxy.sing();
}
}
結果:
真正的方法執行前
面談、籤合同、待付款、訂機票
RealStar.sing()(明星本人)
真正的方法執行後
收尾款
代理模式開發框架中應用場景:
資料庫連線池關閉處理
mybatis中實現攔截器外掛
Aspect的實現
String中AOP的實現(日誌攔截、宣告式事務處理)
web service
RMI遠端方法呼叫
面向切面程式設計常用術語:
切面:共有功能的實現
通知:切面的具體實現
連線點:程式在執行過程中能夠插入切面的地點
切入點:用於定義應該切入到那些連線點上
目標物件:即將切入切面的物件,即被通知的物件
代理物件L:通知應用到目標物件之後被動態建立的物件
織入:將切面應用到目標物件從而建立一個新的代理物件的過程