1、設(shè)計(jì)模式有哪些盹憎?
23種設(shè)計(jì)模式
總體分為三大類
創(chuàng)建型設(shè)計(jì)模式筛峭,共5種
簡單工廠、工廠方法模式陪每,抽象工廠模式影晓,單例模式,建造者模式檩禾,原型模式
結(jié)構(gòu)型模式挂签,共7種
適配器模式,裝飾器模式盼产、代理模式饵婆、外觀模式、橋接模式戏售、組合模式侨核、享元模式
行為型模式,共11種
策略模式灌灾,模板方法搓译,觀察者模式,迭代模式锋喜,責(zé)任鏈模式些己,命令模式,備忘錄模式跑芳,狀態(tài)模式轴总,訪問者模式,中介者模式博个,解釋器模式
2、設(shè)計(jì)模式定義
1功偿、 設(shè)計(jì)模式按照類型劃分
- 創(chuàng)建型設(shè)計(jì)模式:用來解耦對象的實(shí)例化過程盆佣。
- 結(jié)構(gòu)型設(shè)計(jì)模式:將類和對象按照一定規(guī)則組合成一個(gè)更加強(qiáng)大的結(jié)構(gòu)體。
- 行為型設(shè)計(jì)模式:定義類和對象的交互行為械荷。
2共耍、 設(shè)計(jì)模式簡單定義
3、文字版
1)創(chuàng)建型設(shè)計(jì)模式
- 單例模式:確保一個(gè)類只有一個(gè)實(shí)例吨瞎,提供一個(gè)全局訪問點(diǎn)
- 建造者模式:封裝一個(gè)復(fù)雜對象過程痹兜,按照步驟構(gòu)建對象
- 原型模式:通過復(fù)制現(xiàn)有實(shí)例創(chuàng)建新實(shí)例
- 簡單工廠模式:一個(gè)工廠類根據(jù)傳入?yún)?shù)決定創(chuàng)建哪一種產(chǎn)品實(shí)例
- 工廠方法模式:定義一個(gè)用于創(chuàng)建對象的接口,讓子類決定實(shí)例化那個(gè)類
- 抽象工廠模式:創(chuàng)建相關(guān)依賴對象家族颤诀,而無須指定具體類
2)結(jié)構(gòu)型設(shè)計(jì)模式
- 適配器模式:將一個(gè)類的方法或者接口轉(zhuǎn)換成客戶希望另一個(gè)接口
- 組合模式:將對象組成成樹形結(jié)構(gòu)以表示“整體-部分”的層次結(jié)構(gòu)
- 裝飾模式:動態(tài)的給對象添加新的功能
- 外觀模式:對外提供一個(gè)統(tǒng)一方法字旭,用來訪問子系統(tǒng)中一群接口
- 橋接模式:將抽象部分與實(shí)現(xiàn)部分分離对湃,使他們都可以獨(dú)立進(jìn)行變化
- 享元模式:通過共享技術(shù)來有效支持大量細(xì)粒度的對象
- 代理模式:為其他對象提供一種代理以控制對這個(gè)對象的訪問
3)行為型設(shè)計(jì)模式
- 模板模式:定義一個(gè)算法結(jié)構(gòu),而將一些步驟延遲到子類實(shí)現(xiàn)
- 解釋器模式:定義一個(gè)語言遗淳,定義它的文法的一種表示拍柒,并定義一個(gè)解釋器
- 策略模式:定義一系列算法,把它們封裝起來屈暗,并且使它們可以互相替換
- 狀態(tài)模式:允許一個(gè)對象在其內(nèi)部狀態(tài)改變時(shí)改變它的行為
- 觀察者模式:對象間一對多依賴關(guān)系拆讯,一個(gè)對象改變,依賴于它對象得到通知并更新
- 備忘錄模式:在不破壞封裝前提下养叛,保存對象內(nèi)部狀態(tài)
- 中介者模式:用一個(gè)中介對象來封裝一系列對象交互
- 命令模式:將命令請求封裝成一個(gè)對象种呐,可以將不同請求來進(jìn)行參數(shù)化
- 訪問者模式:在不改變數(shù)據(jù)結(jié)構(gòu)的前提下,增加作用于一組元素對象新功能
- 責(zé)任鏈模式:將請求的發(fā)送者和接受者解耦弃甥,使得多個(gè)對象都有處理這個(gè)請求的機(jī)會
- 迭代器模式:一種遍歷訪問容器對象中各個(gè)元素的方法陕贮,不暴露該對象內(nèi)部結(jié)構(gòu)
3、動態(tài)代理和靜態(tài)代理區(qū)別
區(qū)別在于代理類生成時(shí)間不同潘飘,根據(jù)程序運(yùn)行時(shí)代理類是否存在
應(yīng)用場景:retrofit使用動態(tài)代理提升擴(kuò)展性
4肮之、動態(tài)代理寫法
參考 https://github.com/yinlingchaoliu/23-design-pattern.git
公共部分
//接口
public interface ILawsuit {
//提交申請
void submit();
//舉證
void burden();
//辯護(hù)
void defend();
//訴訟完成
void finish();
}
public class XiaoMin implements ILawsuit {
@Override
public void submit() {
//小民申請仲裁
System.out.println( "老板年底拖欠工資,特此申請仲裁卜录!" );
}
@Override
public void burden() {
//小民提交證據(jù)
System.out.println( "這是合同書和過去一年的銀行工資流水戈擒!" );
}
@Override
public void defend() {
//鐵證如山
System.out.println( "證據(jù)確鑿,不需要再說什么艰毒!" );
}
@Override
public void finish() {
//結(jié)果
System.out.println( "訴訟成功筐高,判決老板即日起七天內(nèi)結(jié)算工資!" );
}
}
靜態(tài)代理
/**
* 代理類
*/
public class Lawyer implements ILawsuit {
private ILawsuit mLawsuit;
public Lawyer(ILawsuit mLawsuit) {
this.mLawsuit = mLawsuit;
}
@Override
public void submit() {
mLawsuit.submit();
}
@Override
public void burden() {
mLawsuit.burden();
}
@Override
public void defend() {
mLawsuit.defend();
}
@Override
public void finish() {
mLawsuit.finish();
}
}
測試類
public class TestMain {
public static void main(String[] args) {
ILawsuit xiaomin = new XiaoMin();
//靜態(tài)代理
ILawsuit lawyer = new Lawyer( xiaomin );
lawyer.submit();
lawyer.burden();
lawyer.defend();
lawyer.finish();
}
}
動態(tài)代理 第一種寫法
/**
*
* 動態(tài)代理
*
*/
public class DynamicProxy implements InvocationHandler {
private Object obj;
public DynamicProxy(Object obj) {
this.obj = obj;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object result = method.invoke( obj,args );
return result;
}
}
public class TestMain {
public static void main(String[] args) {
ILawsuit xiaomin = new XiaoMin();
//動態(tài)代理
DynamicProxy proxy = new DynamicProxy( xiaomin );
//獲取小民的classLoader
ClassLoader loader = xiaomin.getClass().getClassLoader();
//動態(tài)代理一個(gè)代理律師
ILawsuit lawyer = (ILawsuit) Proxy.newProxyInstance( loader, new Class[]{ILawsuit.class}, proxy );
lawyer.submit();
lawyer.burden();
lawyer.defend();
lawyer.finish();
}
}
動態(tài)代理第二種通用式寫法
public class DynamicProxy {
//需要特別指定泛型類
public static <T> T create(Class<T> serivce, final Object newInstance) {
InvocationHandler proxy = new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
return method.invoke( newInstance, args );
}
};
ClassLoader loader = serivce.getClassLoader();
return (T) Proxy.newProxyInstance( loader, new Class[]{serivce}, proxy );
}
}
/**
* 需要那個(gè)接口 泛型指向那個(gè)
* T必須為接口類
* @param newInstance
* @param <T>
* @return
*/
public static <T> T create(final Object newInstance) {
InvocationHandler proxy = new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
return method.invoke( newInstance, args );
}
};
//獲得接口列表
Class[] ifaces = newInstance.getClass().getInterfaces();
//獲取實(shí)體類classLoader
ClassLoader loader = newInstance.getClass().getClassLoader();
//獲得動態(tài)代理實(shí)例
return (T) Proxy.newProxyInstance( loader, ifaces, proxy );
}
//retrofit寫法
/**
* 沒有真正實(shí)體類
* 可以用invoke方法反射
* @param service
* @param <T>
* @return
*/
public static <T> T create(Class<T> service) {
ClassLoader loader = service.getClassLoader();
InvocationHandler proxy = new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//這里填寫回調(diào)丑瞧,沒有newInstance retrofit用法
return null;
}
};
return (T) Proxy.newProxyInstance( loader, new Class[]{service}, proxy );
}
}
測試類
public static void main(String args[]){
//第一種方式:指定接口
ILawsuit lawsuit = DynamicProxy.create( ILawsuit.class, new XiaoMin() );
lawsuit.submit();
lawsuit.burden();
//第二種方式:采用接口轉(zhuǎn)換
ILawsuit mlawsuit = DynamicProxy.create( new XiaoMin() );
mlawsuit.defend();
IArgue argue = DynamicProxy.create( new XiaoMin() );
argue.argue();
//轉(zhuǎn)換時(shí) 必須用接口才行
ILawsuit judge = (ILawsuit)argue;
judge.finish();
}
5柑土、簡單工廠、工廠方法绊汹、抽象工廠稽屏、建造者模式區(qū)別
簡單工廠:一個(gè)工廠方法創(chuàng)建不同類型對象
工廠方法:一個(gè)具體工廠類負(fù)責(zé)創(chuàng)建一個(gè)具體對象類型
抽象工廠:一個(gè)具體工廠類負(fù)責(zé)創(chuàng)建一系列相關(guān)對象
建造者模式:對象的構(gòu)建與表現(xiàn)分離,更注重對象創(chuàng)建過程
6西乖、裝飾模式與代理模式區(qū)別狐榔、與橋接者模式相比
1、裝飾模式以客戶端透明方式擴(kuò)展對象的功能获雕,是繼承關(guān)系替代方案薄腻。
代理模式是給一個(gè)對象提供代理對象,并由代理對象來控制原有對象引用
2届案、裝飾模式應(yīng)該為所裝飾對象增強(qiáng)功能庵楷,代理模式對所代理對象施加控制,但不對對象功能本身增加
3、橋接模式主要為應(yīng)對某個(gè)類多個(gè)變化維度增加場景尽纽,通過橋接把多個(gè)變化隔離開
7咐蚯、外觀模式和中介模式區(qū)別
外觀模式重點(diǎn)對外封裝統(tǒng)一高層接口,便于用戶使用蜓斧。
中介模式避免多個(gè)互相協(xié)作對象直接易用仓蛆。他們之間通過一個(gè)中介對象進(jìn)行,從而得到他們耦合松散挎春,易于應(yīng)對變化
8看疙、策略模式和狀態(tài)模式區(qū)別
類型結(jié)構(gòu)一致,本質(zhì)不同直奋,策略模式重在整個(gè)算法的替換能庆,也就是策略替換,而狀態(tài)模式則是通過狀態(tài)來改變行為
9脚线、適配器模式搁胆、裝飾者模式、外觀模式異同
相同之處邮绿,在用戶類與被調(diào)用類之間加了一個(gè)中間層
不同之處
代理對象表示一個(gè)單一對象
外觀對象表示一個(gè)子系統(tǒng)
適配器和外觀是對現(xiàn)存系統(tǒng)封裝
外觀定義新接口渠旁,簡化接口
適配器則是復(fù)用原有接口,側(cè)重于接口轉(zhuǎn)換
10船逮、重構(gòu)之代碼壞味道
記住壞味道顾腊,在文集《重構(gòu) 改善代碼設(shè)計(jì)》-代碼壞味道中
記住一個(gè)原則:事不過三,三則重構(gòu)
常見壞味道要點(diǎn):
1挖胃、代碼重復(fù)
2杂靶、方法過長
3、類功能過多
4酱鸭、過長參數(shù)列表
5吗垮、冗余類
6、需要過多注釋