首次建設(shè)網(wǎng)站流程圖品牌營(yíng)銷策略有哪些方法
java設(shè)計(jì)模式
- java設(shè)計(jì)模式類型
- 常用設(shè)計(jì)模式
- 單例模式
- 單例模式的兩種創(chuàng)建方式
- 餓漢式單例
- 懶漢式單例
- 工廠模式
- 簡(jiǎn)單工廠模式
- 工廠方法模式
- 抽象工廠模式
- 原型模式
- 代理模式
- 代理模式結(jié)構(gòu)
- 靜態(tài)代理
- 動(dòng)態(tài)代理
- jdk代理
- Cglib代理
java設(shè)計(jì)模式類型
根據(jù)完成的工作類型設(shè)計(jì)模式分為創(chuàng)建型模式、結(jié)構(gòu)型模式和行為型模式。
創(chuàng)建型模式:是用來創(chuàng)建對(duì)象的模式,特點(diǎn)是將對(duì)象的創(chuàng)建和使用分離。有單例、原型、工廠方法、抽象工廠、建造者5中創(chuàng)建型模型
結(jié)構(gòu)型創(chuàng)建模式:是用來將類或?qū)ο蟀茨撤N布局組成更大的結(jié)構(gòu),有代理、橋接、組合等7種結(jié)構(gòu)性模式
行為型模式:是用來將類或?qū)ο笾g怎樣相互協(xié)作共同完成單個(gè)對(duì)象都無法單獨(dú)完成的任務(wù),以及怎樣分配職責(zé)。。提供了模板方法、策略、命令、職責(zé)鏈、狀態(tài)、觀察者、中介者、迭代器、訪問者、備忘錄、解釋器 11 種行為型模式。
常用設(shè)計(jì)模式
單例模式
為了節(jié)省資源、保證數(shù)據(jù)內(nèi)容的一致性,某些類只能創(chuàng)建一個(gè)實(shí)例,這就是單例模式
單例模式的特點(diǎn):只有一個(gè)實(shí)例對(duì)象、該單例對(duì)象必須由單例類創(chuàng)建、單例類提供一個(gè)訪問方法可以讓外部類進(jìn)行獲取。
單例模式的兩種創(chuàng)建方式
餓漢式單例
類一旦加載就會(huì)創(chuàng)建一個(gè)實(shí)例,不會(huì)存在線程安全問題
private static Demo demo=new Demo();private Demo(){}public Demo getInstance(){return demo;}
懶漢式單例
類加載時(shí)沒有創(chuàng)建單例對(duì)象,只有第一次調(diào)用getInstance方法時(shí)才會(huì)去創(chuàng)建這個(gè)單例
private static Demo demo;private Demo(){}public Demo getInstance(){if(demo==null){demo=new Demo();}return demo;}
這種方式存在線程安全問題,當(dāng)多個(gè)線程同時(shí)訪問時(shí),會(huì)出現(xiàn)創(chuàng)建多個(gè)對(duì)象的情況。
優(yōu)化:
//這種方式雖然安全,但是效率低
public synchronized Demo getInstance(){if(demo==null){demo=new Demo();}return demo;}
//這種方式是線程安全的,效率也高,但是在執(zhí)行過程中,可能會(huì)出現(xiàn)代碼重排序的問題
public Demo getInstance(){//這里使用雙重判斷,第一個(gè)判斷語句,是為了判斷當(dāng)線程進(jìn)來時(shí)是demo是否被創(chuàng)建。if(demo==null){synchronized (Demo.class){//這個(gè)判斷語句主要是判斷對(duì)象未創(chuàng)建時(shí)第一次進(jìn)來的請(qǐng)求進(jìn)入時(shí)的判斷。if(demo==null){demo=new Demo(); } } }return demo;}
//最終優(yōu)化 使用volatile和雙重檢索
private static volatile Demo demo;public Demo getInstance(){if(demo==null){synchronized (Demo.class){if(demo==null){demo=new Demo();}}}return demo;}
Jdk 中的源碼 Runtime 類就是一個(gè)單例類,利用 Runtime 類可以啟動(dòng)新的進(jìn)程或進(jìn)行相關(guān)運(yùn)行時(shí)環(huán)境的操作。比如,取得內(nèi)存空間以及釋放垃圾空間。
工廠模式
工廠負(fù)責(zé)批量創(chuàng)建對(duì)象,使用對(duì)象時(shí),只需要找到相對(duì)應(yīng)的工廠
簡(jiǎn)單工廠模式
不符合開閉原則,適合長(zhǎng)聘子類少的、創(chuàng)建操作簡(jiǎn)單的情況
該模式包含的角色:
工廠角色:負(fù)責(zé)創(chuàng)建所有實(shí)例的內(nèi)部邏輯,提供靜態(tài)方法,可以被外界調(diào)用,創(chuàng)建產(chǎn)品對(duì)象。
抽象產(chǎn)品角色:是所有對(duì)象的父類,可以時(shí)接口或抽象類
具體產(chǎn)品角色:是簡(jiǎn)單工廠模式的創(chuàng)建目標(biāo)。
優(yōu)點(diǎn):實(shí)現(xiàn)的對(duì)象創(chuàng)建和調(diào)用的分離。
缺點(diǎn):違背了開閉原則,產(chǎn)品子類過多會(huì)導(dǎo)致工廠類非常龐大,違背了高內(nèi)聚原則‘
//汽車類 抽象產(chǎn)品角色
public interface Car {void run();}
//奧迪類 具體產(chǎn)品角色
public class Aodi implements Car{@Overridepublic void run() {System.out.println("奧迪汽車行駛");}
}
//寶馬類 具體產(chǎn)品角色
public class Bmw implements Car{@Overridepublic void run() {System.out.println("寶馬汽車行駛");}}
// 汽車工廠 工廠角色
public class CarFactory {public static Car createCar(String name){if(name.equals("aodi")){Aodi aodi = new Aodi();//aodi.return aodi;}if(name.equals("bmw")){return new Bmw();}return null;}
}
工廠方法模式
在簡(jiǎn)單工廠模式的基礎(chǔ)上對(duì)工廠也進(jìn)行了抽象,解決了違背開閉原則的問題
該模式中包含的角色及其職責(zé).
抽象工廠角色:工廠方法模式的核心,與應(yīng)用程序無關(guān)。任何在模式中創(chuàng)建的對(duì)
象的工廠類必須實(shí)現(xiàn)這個(gè)接口。
具體工廠角色:這是實(shí)現(xiàn)抽象工廠接口的具體工廠類,包含與應(yīng)用程序密切相關(guān)
的邏輯,并且受到應(yīng)用程序調(diào)用以創(chuàng)建產(chǎn)品對(duì)象。
抽象產(chǎn)品角色:工廠方法模式所創(chuàng)建的對(duì)象的父類型,也就是產(chǎn)品對(duì)象的共同父
類或共同擁有的接口。
具體產(chǎn)品角色:這個(gè)角色實(shí)現(xiàn)了抽象產(chǎn)品角色所定義的接口。某具體產(chǎn)品有專門
的具體工廠創(chuàng)建,它們之間往往——對(duì)應(yīng)。
//抽象工廠類
public interface CarFactory {Car createCar();}
//具體工廠角色
public class AodiFactory implements CarFactory{@Overridepublic Car createCar() {return new AodiCar();}
}
public class BCFactroy implements CarFactory{@Overridepublic Car createCar() {return new BC();}}
//抽象產(chǎn)品角色
public interface Car {void run();
}
//具體產(chǎn)品角色
public class AodiCar implements Car{@Overridepublic void run() {System.out.println("奧迪汽車行駛");}
}
public class BC implements Car{@Overridepublic void run() {System.out.println("奔馳");}
}
抽象工廠模式
抽象工廠模式中,一個(gè)具體的工廠負(fù)責(zé)創(chuàng)建一系列相互關(guān)聯(lián)的產(chǎn)品。
//抽象工廠類
public interface AbstractFactory {Car getCar();Phone getPhone();}
//具體工廠角色
public class AodiFactory implements AbstractFactory{@Overridepublic Car getCar() {return new AodiCar();}@Overridepublic Phone getPhone() {return new AodiPhone();}
}
//抽象產(chǎn)品角色
public interface Phone {void call();
}
public interface Car {void run();
}
//具體產(chǎn)品角色
public class AodiCar implements Car{@Overridepublic void run() {System.out.println("奧迪汽車行駛");}
}
public class AodiPhone implements Phone{@Overridepublic void call() {System.out.println("奧迪手機(jī)打電話");}
}
優(yōu)點(diǎn):獲取具體系列產(chǎn)品只需要通過具體系列工廠獲取,無序關(guān)心創(chuàng)建的細(xì)節(jié)。
原型模式
原型模式是指創(chuàng)建一個(gè)對(duì)象,并且通過這個(gè)對(duì)象作為原型來創(chuàng)建新的對(duì)象,相當(dāng)于復(fù)制多個(gè)具有相同信息的對(duì)象。
實(shí)現(xiàn)方式:使用對(duì)象克隆的方式創(chuàng)建新的對(duì)象。
代理模式
代理模式就是給對(duì)象提供一個(gè)代理,通過代理對(duì)象來對(duì)原對(duì)象進(jìn)行控制。是的客戶不能直接和對(duì)象進(jìn)行交互,只能通過代理對(duì)象來進(jìn)行操作。
案例:買火車票不一定要去火車站買,可以通過 12306 網(wǎng)站或者去火車票代售點(diǎn)
優(yōu)點(diǎn):保護(hù)目標(biāo)對(duì)象、代理對(duì)象可以擴(kuò)展目標(biāo)對(duì)象的功能,代理模式將客戶端與目標(biāo)分離,降低系統(tǒng)的耦合度。
代理模式結(jié)構(gòu)
1.抽象主題類:使用接口和抽象類聲明真實(shí)主題類和代理對(duì)象的業(yè)務(wù)方法
2.真實(shí)主題類:實(shí)現(xiàn)抽象主題中的業(yè)務(wù),是目標(biāo)對(duì)象是最終要引用的對(duì)象。
3.代理類:提供與真實(shí)主題相同的結(jié)構(gòu),引用了真實(shí)主題,它可以訪問、控制和擴(kuò)展真實(shí)主題的功能
1.png)]
代理分為兩種:動(dòng)態(tài)代理和靜態(tài)代理
靜態(tài)代理
靜態(tài)代理的特點(diǎn)。代理類接受一個(gè)抽象主題接口,實(shí)現(xiàn)任何該接口的對(duì)象,都可以通過代理類進(jìn)行代理。
優(yōu)點(diǎn):可以對(duì)目標(biāo)對(duì)象進(jìn)行功能擴(kuò)展
缺點(diǎn):一個(gè)代理類只能代理一個(gè)接口,必須現(xiàn)有接口再有代理,接口發(fā)生改變,代理類也要修改
以買票為例
//抽象主題 買票
public interface Ticket {void buy();
}
//真實(shí)主題 目標(biāo)對(duì)象類
public class TrainTicket implements Ticket {@Overridepublic void buy() {System.out.println("買火車票");}
}
public class PlaneTicket implements Ticket {@Overridepublic void buy() {System.out.println("買飛機(jī)票");}
}
//代理類
public class MeiTuan implements Point {Ticket ticket;public MeiTuan(Ticket ticket) {this.ticket= ticket;}@Overridepublic void buy() {System.out.println("添加額外功能");ticket.buy();}
}
//測(cè)試類
public class Test {public static void main(String[] args) {//具體對(duì)象Ticket trainTicket = new TrainTicket();Ticket planeTicket = new PlaneTicket();//創(chuàng)建用戶代理對(duì)象Ticket ticket = new Ticket(trainTicket);ticket.buy();Ticket ticket1 = new Ticket(planeTicket);ticket1.buy();}
}
動(dòng)態(tài)代理
在動(dòng)態(tài)代理中不需要手動(dòng)的創(chuàng)建類,只需要編寫一個(gè)動(dòng)態(tài)的處理器,代理對(duì)象在運(yùn)行時(shí)動(dòng)態(tài)的來創(chuàng)建。
動(dòng)態(tài)代理分為jdk動(dòng)態(tài)代理和cglid動(dòng)態(tài)代理
jdk代理
jdk動(dòng)態(tài)代理是通過反射來實(shí)現(xiàn)的,借助java自帶的java.lang.reflect.Proxy生成。
實(shí)現(xiàn)步驟:
1.編寫一個(gè)委托類的接口
2.實(shí)現(xiàn)一個(gè)委托類
3.創(chuàng)建一個(gè)動(dòng)態(tài)代理類,實(shí)現(xiàn)現(xiàn) InvocationHandler 接口,并重寫該 invoke
方法。
4.在測(cè)試類中,生成動(dòng)態(tài)代理的對(duì)象。
實(shí)現(xiàn)步驟的前兩步和靜態(tài)代理沒有區(qū)別。
/*動(dòng)態(tài)代理類代理類不需要實(shí)現(xiàn)與目標(biāo)類相同的接口,這樣就可以代理任意的目標(biāo)類但是是有要求的,目標(biāo)類必需實(shí)現(xiàn)接口,此種方式是動(dòng)態(tài)代理的實(shí)現(xiàn)方式之一: jdk代理 是一種純反射機(jī)制實(shí)現(xiàn)(動(dòng)態(tài)獲取目標(biāo)類接口方法)*/
public class DynamicProxy implements InvocationHandler {Object object;//真實(shí)對(duì)象,接收任何的目標(biāo)類對(duì)象public DynamicProxy(Object object) {this.object = object;}/*在代理類中調(diào)用目標(biāo)類中的具體方法,動(dòng)態(tài)的將代理動(dòng)態(tài)對(duì)象,目標(biāo)類中要調(diào)用的方法,及方法中的參數(shù)傳遞過來Method method 就是動(dòng)態(tài)獲取的真正要執(zhí)行的方法*/@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println("之前開啟事務(wù)");method.invoke(object);System.out.println("之后提交事務(wù)");return proxy;}//真正意義上,運(yùn)行時(shí)生成代理對(duì)象的方法public Object getProxy(){return Proxy.newProxyInstance(object.getClass().getClassLoader(),object.getClass().getInterfaces(),this);}}
//測(cè)試類
public class Test {public static void main(String[] args) {TrainTicket trainTicket = new TrainTicket();DynamicProxy dtproxy = new DynamicProxy(trainTicket);//自己創(chuàng)建的代理類對(duì)象//這才是真正的創(chuàng)建動(dòng)態(tài)代理對(duì)象Ticket ticket = (Train)dtproxy.getProxy();userDao.saveUser();//使用代理對(duì)象調(diào)用接口中的方法,獲取當(dāng)前調(diào)用的方法,最終調(diào)用invoke方法}
}
jdk動(dòng)態(tài)代理,減少了對(duì)接口業(yè)務(wù)的依賴,降低了耦合度,但是jdk動(dòng)態(tài)代理有一個(gè)缺點(diǎn)就是他必須要?jiǎng)?chuàng)建一個(gè)代理接口。
Cglib代理
Cglib代理解決了jdk動(dòng)態(tài)代理的缺點(diǎn)。CGLIB(Code Generator Library)是一個(gè)強(qiáng)大的、高性能的代碼生成庫。CGLib 采用了非常底層的字節(jié)碼技術(shù),其原理是通過字節(jié)碼技術(shù)為一個(gè)類創(chuàng)建子類,并在子類中采用方法攔截的技術(shù)攔截所有父類方法的調(diào)用,順勢(shì)織入橫切邏輯。
Cglib 子類代理實(shí)現(xiàn)方法:
1.需要引入 cglib 的 jar 文件,但是 Spring 的核心包中已經(jīng)包括了 Cglib 功能,所以直接引入 spring-core-xxx.jar 即可
2.引入功能包后,就可以在內(nèi)存中動(dòng)態(tài)構(gòu)建子類
3.代理的類不能為 final,否則報(bào)錯(cuò)
4.目標(biāo)對(duì)象的方法如果為 final/static,那么就不會(huì)被攔截,即不會(huì)執(zhí)行目標(biāo)對(duì)象額外的業(yè)務(wù)方法.
CGLIB 創(chuàng)建的動(dòng)態(tài)代理對(duì)象比JDK 創(chuàng)建的動(dòng)態(tài)代理對(duì)象的性能更高,但是 CGLIB創(chuàng)建代理對(duì)象時(shí)所花費(fèi)的時(shí)間卻比 JDK 多得多。所以對(duì)于單例的對(duì)象,因?yàn)闊o需頻繁創(chuàng)建對(duì)象,用 CGLIB 合適,反之使用 JDK 方式要更為合適一些。同時(shí)由于 CGLib 由于是采用動(dòng)態(tài)創(chuàng)建子類的方法,對(duì)于 final 修飾的方法無法進(jìn)行代理。
/** 動(dòng)態(tài)代理類*/
public class CGLibProxy implements MethodInterceptor {private Enhancer enhancer = new Enhancer();public Object getProxy(Class<?> clazz){ enhancer.setSuperclass(clazz); enhancer.setCallback(this); return enhancer.create(); } /** 攔截所有目標(biāo)類方法的調(diào)用 * 參數(shù): * obj 目標(biāo)實(shí)例對(duì)象 * method 目標(biāo)方法的反射對(duì)象 * args 方法的參數(shù) * proxy 代理類的實(shí)例 */ public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {//代理類調(diào)用父類的方法 System.out.println("開始事務(wù)"); Object obj1 = proxy.invokeSuper(obj, args); System.out.println("關(guān)閉事務(wù)"); return obj1; }
}
//具體主題
public class UserDaoImpl{public void save() {System.out.println("UserDaoImpl:save()");}
}
//測(cè)試類
public class Test {public static void main(String[] args) {CGLibProxy proxy = new CGLibProxy(); UserDaoImpl userDaoImpl = (UserDaoImpl) proxy.getProxy(UserDaoImpl.class);userDaoImpl.save();}
}