目錄
一:設計模式
- 概念:設計模式(Design Pattern)是一套被反覆使用、多數人知曉的、經過分類的、代碼設計經驗的總結。
- 目的:爲了代碼可重用性,讓代碼更容易被他人理解、保證代碼可靠性。設計模式使代碼編寫真正工程化;設計模式是軟件工程的基石脈絡,如同大廈的結構一樣。
二:設計原則
設計模式就是因爲實現了設計原則(面向對象),從而達到了代碼複用,增加可維護性的目的。
- 開閉原則(Open Close Principle)
對擴展開發,對修改關閉
在程序需要進行擴展的時候,不能去修改原有的代碼 - 里氏替換原則(Liskov Substitution Principle)
任何基類可以出現的地方,子類一定可以出現
里氏替換原則是對開閉原則的補充。實現開閉原則的關鍵步驟就是抽象化。而基類於子類的繼承關係就是抽象化的具體實現。
- 依賴倒置原則(Dependence Inversion Principle)
面向接口編程,依賴於抽象/接口,而不依賴於具體實現
這個是開閉原則的基礎
- 接口隔離原則(Interface Segregation Principle)
使用多個接口比使用單一接口要好,降低代碼的耦合度 - 迪米特法則(最少知道原則)(Demeter Principle)
一個實體應當儘量少的與其他實體之間發生相互作用,使得系統功能模塊相對獨立。 - 單一職責原則(Single Responsibility Principle)
一個類只做一件事
三:設計模式的分類
總體來說設計模式分爲三大類
- 創建型模式,共五種:單例模式、工廠模式、抽象工廠模式、建造者模式、原型模式。
- 結構型模式,共七種:適配器模式、裝飾器模式、代理模式、外觀模式、橋接模式、組合模式、享元模式。
- 行爲模式,共十一鍾:策略模式、模板方法模式、觀察者模式、迭代子模式、責任鏈模式、命令模式、備忘錄模式、狀態模式、訪問模式、中介者模式、解釋器模式。
本章重點-----結構型模式之代理模式
1. 定義:
代理模式(Proxy Pattern):爲其他對象提供一種代理以控制對這個對象的訪問。
類圖:
RealSubject 具體主題角色
是業務邏輯的具體執行者
ProxySubject代理主題角色
它負者對真實角色的應用,把所有抽象主題類定義的方法限制委託給真實主題角色實現,並且在真實主題角色處理完畢前後做預處理和善後處理工作
2. 示例:
我們以找中介買二手車爲例
1. 靜態代理:
/**
* 主要業務
* @author xiyang.ycj
* @since Nov 21, 2019 18:03:23 PM
*/
public interface IBuyer {
void buy();
}
-----------------------------------
/**
* 客戶
* @author xiyang.ycj
* @since Nov 21, 2019 17:59:01 PM
*/
public class Buyer implements IBuyer{
@Override
public void buy(){
System.out.println("我要買輛車");
}
}
-----------------------------------
/**
* 中介
* @author xiyang.ycj
* @since Nov 21, 2019 18:01:09 PM
*/
public class ProxyBuyer implements IBuyer{
private Buyer buyer;
public ProxyBuyer(Buyer buyer) {
this.buyer = buyer;
}
@Override
public void buy() {
System.out.println("中介--買車記錄---找到車源");
buyer.buy();
System.out.println("中介--買車記錄---交易完成--記錄業績");
}
}
-----------------------------------
public class ProxyClient {
@Test
public void staticProxy(){
// 創建一個買家
Buyer buyer = new Buyer();
// 找到一箇中介
ProxyBuyer proxyBuyer = new ProxyBuyer(buyer);
proxyBuyer.buy();
}
}
-----------------------------------
中介--買車記錄---找到車源
我要買輛車
中介--買車記錄---交易完成--記錄業績
靜態代理:
優點:可以做到在符合開閉原則的情況下對目標進行功能擴展
缺點:我們得爲每一個服務都創建代理類,工作量太大,且一但主要業務發生改變,代理類也得改變
2. JDK動態代理:
/**
* 動態處理器
* @author xiyang.ycj
* @since Nov 21, 2019 18:01:09 PM
*/
public class Dynamic implements InvocationHandler {
private Object target;
public Dynamic(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("中介--買車記錄---找到車源");
Object invoke = method.invoke(this.target, args);
System.out.println("中介--買車記錄---交易完成--記錄業績");
return invoke;
}
}
-----------------------------------
public class ProxyClient {
@Test
public void dynamicProxy(){
// 創建一個買家
IBuyer buyer = new Buyer();
// 找到一箇中介
IBuyer instance = (IBuyer)Proxy.newProxyInstance(Buyer.class.getClassLoader(), new Class[]{IBuyer.class}, new Dynamic(buyer));
instance.buy();
}
}
-----------------------------------
中介--買車記錄---找到車源
我要買輛車
中介--買車記錄---交易完成--記錄業績
注意Proxy.newProxyInstance()方法接收三個參數:
● ClassLoder loder:指定當前目標對象使用得類加載器,獲取加載器得方法是固定得。
● Class<?>[] interfaces:指定目標對象實現得接口的類型,使用泛型方式確認類型。
● InvocationHandler handler:指定動態處理器,執行目標對象的方法時,會觸發事件處理器的方法。
3. CGLIB動態代理:
由於JDK實現動態代理需要實現類通過接口定義業務方法,對於沒有接口的類,就需要CGLIB了.
CGLIB:採用非常底層的字節碼技術,其原理是通過字節碼技術爲一個類創建子類,並在子類中採用方法攔截的技術攔截所有父類方法的調用,順勢織入橫切邏輯。但不能對final修飾的類進行代理(繼承)。
/**
* cglib方法攔截
* @author xiyang.ycj
* @since Nov 21, 2019 18:54:48 PM
*/
public class Cglib implements MethodInterceptor {
/* 創建一個子類 */
public <T> T getInstance(Class<T> clazz){
return (T) Enhancer.create(clazz,this);
}
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("中介--買車記錄---找到車源");
Object invokeSuper = methodProxy.invokeSuper(o, objects);// 調用業務類(父類中)的方法
System.out.println("中介--買車記錄---交易完成--記錄業績");
return invokeSuper;
}
}
-----------------------------------
public class ProxyClient {
@Test
public void cglibProxy(){
Buyer instance = new Cglib().getInstance(Buyer.class);
instance.buy();
}
}
-----------------------------------
中介--買車記錄---找到車源
我要買輛車
中介--買車記錄---交易完成--記錄業績
CGLIB創建的動態代理對象比JDK創建的動態代理對象的性能更高,但是CGLIB創建代理對象時所花費的時間卻比JDK多得多。所以對於單例的對象,因爲無需頻繁創建對象,用CGLIB合適,反之使用JDK方式要更爲合適一些。
3.工廠模式的應用
1. 優點:
- 職責清晰。
真實的角色就是實現實際的業務邏輯,不用關心其他非本職責的事務,通過後期的代理完成一件事務,附帶的結果就是編程簡潔清晰。 - 高擴展性
- 智能化
2. 使用場景
- spring aop
- 權限管理
- 事務