java基础之设计模式
1 設(shè)置模式之單例設(shè)計(jì)模式
概念:保證一個類僅有一個實(shí)例,并提供一個訪問它的全局訪問點(diǎn)。
(1)餓漢式:
/*** @Description 餓漢式* @author refuel* @version v1.0*/ public class TestSingleton{public static void main(String[] args) {Singleton sing = Singleton.getInstance(); sing.show();} } class Singleton { //1、將構(gòu)造器私有化private Singleton() {}//2、定義創(chuàng)建一個私有對象 private static Singleton Sing = new Singleton();//3、定義公共靜態(tài)方法返回該類類型的對象 public static Singleton getInstance() {return Sing;} }(2)飽漢式,線程不安全
/*** @Description 飽漢式,線程不安全* @author refuel* @version v1.0*/ public class TestSingleton{public static void main(String[] args) {Singleton sing = Singleton.getInstance(); sing.show();} } class Singleton { //1、將構(gòu)造器私有化private Singleton() {}//2、定義創(chuàng)建一個私有對象 private static Singleton Sing;//3、定義公共靜態(tài)方法返回該類類型的對象 public static Singleton getSingleton() {if(Sing == null) {Sing = new Singleton();}return Sing;} }?
2?設(shè)置模式之工廠模式
2.1 簡單工廠
簡單工廠模式其實(shí)不是一個設(shè)計(jì)模式,反而比較像一種編程習(xí)慣。主要我們定義一個非常簡單的類主要負(fù)責(zé)幫我們生產(chǎn)不同的產(chǎn)品。例子如下:
/*** @Description 簡單工廠* @author refuel* @version v1.0*/ public class SimpleFactory {//④使用工廠方法,通過傳遞類型信息來獲取實(shí)體類的對象public static void main(String[] args) {Factory1 w = new Factory1();//獲取Student1Work的對象,并調(diào)用他的doWork方法Product1 product = w.getExamples("Student1Work");product.show();//獲取Teacher1Work的對象,并調(diào)用他的doWork方法Product1 product1 = w.getExamples("Teacher1Work");product1.show();//獲取Worker1Work的對象,并調(diào)用他的doWork方法Product1 product2 = w.getExamples("Worker1Work");product2.show();}}//①創(chuàng)建一個 Product接口 interface Product1{void show(); } // ②實(shí)現(xiàn)Product 接口的實(shí)體類 class Student1 implements Product1 {@Overridepublic void show() {System.out.println("學(xué)生學(xué)習(xí)");} } class Teacher1 implements Product1 {@Overridepublic void show() {System.out.println("老師教書育人");} } class Worker1 implements Product1 {@Overridepublic void show() {System.out.println("工人建高樓大廈");} } //③定義工廠類 生成基于給定信息的實(shí)體類的對象 class Factory1 {//使用getExamples方法獲取工作性質(zhì)類型的對象public Product1 getExamples(String workType) {if(workType ==null) {return null;}if(workType.equalsIgnoreCase("Student1Work")) {return new Student1();}else if(workType.equalsIgnoreCase("Teacher1Work")) {return new Teacher1();}else if(workType.equalsIgnoreCase("Worker1Work")) {return new Worker1();}return null;} }2.2 工廠方法模式
簡單工廠模式有一個缺點(diǎn)是不同的產(chǎn)品需要不同的額外參數(shù)的時候,是不支持的,而且如果使用時傳遞的type、Class出錯,將不能得到正確的對象,容錯率不高。而多方法的工廠模式為不同產(chǎn)品,提供不同的生產(chǎn)方法,使用時 需要哪種產(chǎn)品就調(diào)用該種產(chǎn)品的方法,使用方便、容錯率高。
工廠方法模式概念:定義一個用于創(chuàng)建對象的接口,但是讓子類決定將哪一個類實(shí)例化。工廠父類負(fù)責(zé)定義創(chuàng)建產(chǎn)品對象的公共接口,而工廠子類則負(fù)責(zé)生成具體的產(chǎn)品對象,目的是將產(chǎn)品類的實(shí)例化操作延遲到工廠子類中完成,即通過工廠子類來確定究竟應(yīng)該實(shí)例化哪一個具體產(chǎn)品類
何時使用:主要解決接口選擇的問題,我們明確地計(jì)劃不同條件下創(chuàng)建不同實(shí)例時。
/*** @Description 工廠模式* @author refuel* @version v1.0*/ public class FactoryPattern {public static void main(String[] args) {Factory2 s = new StudentFactory2();s.getExamples().show();Factory2 t = new TeacherFactory2();t.getExamples().show();Factory2 w = new WorkerFactory2();w.getExamples().show();}}//①創(chuàng)建一個 Product接口 interface Product2{void show(); } // ②實(shí)現(xiàn)Product 接口的實(shí)體類 class Student2 implements Product2 {@Overridepublic void show() {System.out.println("學(xué)生學(xué)習(xí)");} } class Teacher2 implements Product2 {@Overridepublic void show() {System.out.println("老師教書育人");} } class Worker2 implements Product2 {@Overridepublic void show() {System.out.println("工人建高樓大廈");} } //③定義一個工廠接口 interface Factory2 {Product2 getExamples(); } //④定義一個學(xué)生工廠接口 class StudentFactory2 implements Factory2 {public Product2 getExamples() {return new Student2();} } //⑤定義一個老師工廠接口 class TeacherFactory2 implements Factory2 {public Product2 getExamples() {return new Teacher2();} } //⑥定義一個工人工廠接口 class WorkerFactory2 implements Factory2 {public Product2 getExamples() {return new Worker2();} }2.3 抽象工廠模式
為創(chuàng)建一組相關(guān)或相互依賴的對象提供一個接口,而且無需指定他們的具體類。
抽象工廠模式,他用來創(chuàng)建一組相關(guān)或者相互依賴的對象。他與工廠方法模式的區(qū)別就在于,工廠方法模式針對的是一個產(chǎn)品等級結(jié)構(gòu);而抽象工廠模式則是針對的多個產(chǎn)品等級結(jié)構(gòu)。通常一個產(chǎn)品結(jié)構(gòu),表現(xiàn)為一個接口或者抽象類,也就是說,工廠方法模式提供的所有產(chǎn)品都是衍生自同一個接口或抽象類,而抽象工廠模式所提供的產(chǎn)品則是衍生自不同的接口或抽象類。
/*** @Description 抽象工廠模式* @author refuel* @version v1.0*/ public class AbstractFactoryPattern {public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException {AbstractFactory sbstractFactory = SuperFactory.getFactory("com.refuel.factory.StudentFactory");Product SmallStudent = sbstractFactory.getExamples("com.refuel.factory.SmallStudent");SmallStudent.show();}}//最高級抽象產(chǎn)品,用于抽象工廠的建造方法的返回值 abstract class Product{abstract void show(); } //學(xué)生產(chǎn)品類 abstract class StudentProduct extends Product{} //小學(xué)生產(chǎn)品 class SmallStudent extends StudentProduct{public void show() {System.out.println("小學(xué)生");} }//中學(xué)生產(chǎn)品 class MiddleStudent extends StudentProduct{public void show() {System.out.println("小學(xué)生");} } //老師產(chǎn)品類 abstract class TeacherProduct extends Product{} //數(shù)學(xué)老師產(chǎn)品 class MathTeacher extends TeacherProduct{public void show() {System.out.println("數(shù)學(xué)老師");} }//歷史老師產(chǎn)品 class HistoryTeacher extends TeacherProduct{public void show() {System.out.println("歷史老師");} }//超級工廠類 class SuperFactory {public static AbstractFactory getFactory(String type) throws ClassNotFoundException, InstantiationException, IllegalAccessException {Class cl = Class.forName(type);System.out.println("創(chuàng)建工廠" + type);return (AbstractFactory) cl.newInstance();} } //抽象工廠類 abstract class AbstractFactory {protected abstract Product getExamples(String type) throws ClassNotFoundException, InstantiationException, IllegalAccessException; }//學(xué)生工廠類,覆蓋所有學(xué)生的生產(chǎn)方法 class StudentFactory extends AbstractFactory{public Product getExamples(String type) throws ClassNotFoundException, InstantiationException, IllegalAccessException {Class cl = Class.forName(type);return (StudentProduct)cl.newInstance();} } //老師工廠類,覆蓋所有老師的生產(chǎn)方法 class TeacherFactory extends AbstractFactory{public Product getExamples(String type) throws ClassNotFoundException, InstantiationException, IllegalAccessException {Class cl = Class.forName(type);return (TeacherProduct)cl.newInstance();} }2.4 簡單工廠模式,工廠模式與抽象工廠模式的比較
簡單工廠模式:(1)優(yōu)點(diǎn):工廠類中包含了必要的邏輯判斷,根據(jù)客戶端的選擇條件動態(tài)實(shí)例化相關(guān)的類,對于客戶端來說,去除了與具體產(chǎn)品的依賴。(2)缺點(diǎn):沒有遵守開放—封閉原則(開放接口,封閉修改)。如果將來需要添加一個產(chǎn)品,那么,在簡單工廠模式中,就必須在簡單工廠類中添加相應(yīng)的判斷語句,這對程序的擴(kuò)展本身就不利。
工廠模式:(1)優(yōu)點(diǎn):?1、一個調(diào)用者想創(chuàng)建一個對象,只要知道其名稱就可以了。 2、擴(kuò)展性高,如果想增加一個產(chǎn)品,只要擴(kuò)展一個工廠類就可以。 3、屏蔽產(chǎn)品的具體實(shí)現(xiàn),調(diào)用者只關(guān)心產(chǎn)品的接口。(2)缺點(diǎn):每次增加一個產(chǎn)品時,都需要增加一個具體類和對象實(shí)現(xiàn)工廠,使得系統(tǒng)中類的個數(shù)成倍增加,在一定程度上增加了系統(tǒng)的復(fù)雜度,同時也增加了系統(tǒng)具體類的依賴。這并不是什么好事。
抽象工廠模式:(1)優(yōu)點(diǎn):能夠從多個產(chǎn)品族的多個產(chǎn)品中,簡潔的獲取想要的具體產(chǎn)品。解決了工廠模式中的不符合開閉原則的問題(增加新的產(chǎn)品時候,不修改工廠,而是增加工廠)。(2)缺點(diǎn):產(chǎn)品族擴(kuò)展比較困難,要增加一個系列的某一產(chǎn)品,要增加具體的產(chǎn)品類,還要增加對應(yīng)的工廠類(或者修改對應(yīng)產(chǎn)品族的工廠類)。產(chǎn)品族難擴(kuò)展,產(chǎn)品等級易擴(kuò)展。】
?
3 代理模式
提供了對目標(biāo)對象另外的訪問方式;即通過代理對象訪問目標(biāo)對象.這樣做的好處是:可以在目標(biāo)對象實(shí)現(xiàn)的基礎(chǔ)上,增強(qiáng)額外的功能操作,即擴(kuò)展目標(biāo)對象的功能。如果需改別人寫好的代碼時,可以通過代理的方式來擴(kuò)展該方法。
3.1 靜態(tài)代理
靜態(tài)代理在使用時,需要定義接口或者父類,被代理對象與代理對象一起實(shí)現(xiàn)相同的接口或者是繼承相同父類。
/*** @Description 靜態(tài)代理* @author refuel* @version v1.0*/ public class TestProxy {public static void main(String[] args) {//客戶租房子,找代理ProcyObject proxy = new ProcyObject(new SubjectImpl());proxy.action();} } //接口 interface Subject{void action(); } //中介(代理) class ProcyObject implements Subject {//中介和業(yè)主有關(guān)系,所以定義關(guān)聯(lián)關(guān)系SubjectImpl subject = null;public ProcyObject(SubjectImpl subject) {this.subject = subject;}@Overridepublic void action() {//調(diào)用業(yè)主的方法,自己沒有subject.action();}} //業(yè)主 class SubjectImpl implements Subject{@Overridepublic void action() {System.out.println("業(yè)主的房子");}}?
3.2 動態(tài)代理
動態(tài)代理也叫做:JDK代理,接口代理。代理對象不需要實(shí)現(xiàn)接口,但是目標(biāo)對象一定要實(shí)現(xiàn)接口。代理對象的生成,是利用JDK的API,動態(tài)的在內(nèi)存中構(gòu)建代理對象(需要我們指定創(chuàng)建代理對象/目標(biāo)對象實(shí)現(xiàn)的接口的類型)。
代理類所在包:java.lang.reflect.Proxy,JDK代理使用newProxyInstance方法。
/*** @Description 動態(tài)代理* @author refuel* @version v1.0*/ public class DynamicProxy {public static void main(String[] args) {//目標(biāo)對象Subject1 s = new SubjectImpl1();//給目標(biāo)對象創(chuàng)建代理對象,內(nèi)存中動態(tài)生成的代理對象Subject1 proxy = (Subject1)new ProxyFactory(s).getProxyInstance();proxy.action();} }interface Subject1 {void action(); }/*** @Description 業(yè)主類* @author refuel* @version v1.0*/ class SubjectImpl1 implements Subject1 {@Overridepublic void action() {System.out.println("業(yè)主的房子");}}/*** @Description 代理工廠類* @author refuel* @version v1.0*/ class ProxyFactory {// 中介和業(yè)主有關(guān)系,所以定義關(guān)聯(lián)關(guān)系,來維護(hù)一個目標(biāo)對象Object subject = null;public ProxyFactory(Object subject) {this.subject = subject;}// 給目標(biāo)對象生成一個代理對象public Object getProxyInstance() {// ClassLoader loader:指定當(dāng)前對象使用類加載器,獲取類加載器的方法是固定的// Class<?>[] interfaces:目標(biāo)對象實(shí)現(xiàn)的接口類型,使用泛型方式確認(rèn)// InvocationHandler h:事件處理,執(zhí)行目標(biāo)對象時,會觸發(fā)事件處理器的方法,會把當(dāng)前執(zhí)行的目標(biāo)對象作為的方法作為參數(shù)傳入return Proxy.newProxyInstance(subject.getClass().getClassLoader(), subject.getClass().getInterfaces(),new InvocationHandler() {@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println("開始事務(wù)");// 執(zhí)行目標(biāo)對象方法Object invokeValue = method.invoke(subject, args);System.out.println("提交事務(wù)");return invokeValue;}});} }?
3.3 Cglib代理
Cglib代理,也叫作子類代理,它是在內(nèi)存中構(gòu)建一個子類對象從而實(shí)現(xiàn)對目標(biāo)對象功能的擴(kuò)展。靜態(tài)代理和動態(tài)代理模式都是要求目標(biāo)對象實(shí)現(xiàn)一個接口,但是有時候目標(biāo)對象只是一個單獨(dú)的對象,并沒有實(shí)現(xiàn)任何的接口,這個時候就可以使用以目標(biāo)對象子類的方式類實(shí)現(xiàn)代理,這種方法就叫做:Cglib代理。
/*** @Description Cglib類* @author refuel* @version v1.0*/ public class CglibProxy {public static void main(String[] args) {//目標(biāo)對象SubjectImpl2 target = new SubjectImpl2();//代理對象SubjectImpl2 proxy = (SubjectImpl2)new ProxyFactory(target).getProxyInstance();//執(zhí)行代理對象的方法proxy.action();} } /*** @Description 業(yè)主類,目標(biāo)對象,沒有實(shí)現(xiàn)任何接口* @author refuel* @version v1.0*/ class SubjectImpl2 {public void action() {System.out.println("業(yè)主的房子");} } /*** @Description Cglib子類代理工廠,對SubjectImpl2在內(nèi)存中動態(tài)創(chuàng)建一個子類對象* @author refuel* @version v1.0*/ class ProxyFactory implements MethodInterceptor{// 中介和代理有關(guān)系,所以定義關(guān)聯(lián)關(guān)系,來維護(hù)一個目標(biāo)對象Object subject = null;public ProxyFactory(Object subject) {this.subject = subject;}// 給目標(biāo)對象創(chuàng)建一個代理對象public Object getProxyInstance() {//1.工具類Enhancer en = new Enhancer();//2.設(shè)置父類en.setSuperclass(subject.getClass());//3.設(shè)置回調(diào)函數(shù)en.setCallback(this);//4.創(chuàng)建子類(代理對象)return en.create();}@Overridepublic Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {System.out.println("開始");//執(zhí)行目標(biāo)對象的方法Object returnValue = method.invoke(subject, args);System.out.println("提交");return returnValue;}}2.4 靜態(tài)代理,動態(tài)代理,Cglib代理的比較
靜態(tài)代理:(1)優(yōu)點(diǎn):可以做到在不修改目標(biāo)對象的功能前提下,對目標(biāo)功能擴(kuò)展.。(2)缺點(diǎn):因?yàn)槟繕?biāo)對象要與代理對象實(shí)現(xiàn)一樣的接口,所以會產(chǎn)生很多的代理類,導(dǎo)致類太多。接口增加方法,目標(biāo)對象與代理對象都要進(jìn)行維護(hù)。
動態(tài)代理:(1)優(yōu)點(diǎn):由于java封裝了newProxyInstance這個方法的實(shí)現(xiàn)細(xì)節(jié),所以使用起來非常方便。(2)缺點(diǎn):靜態(tài)代理和JDK代理有一個共同的缺點(diǎn),就是目標(biāo)對象必須實(shí)現(xiàn)一個或多個接口
Cglib代理:(1)優(yōu)點(diǎn):目標(biāo)對象與代理對象都不用實(shí)現(xiàn)接口。(2)缺點(diǎn):因?yàn)闆]有使用接口,所以系統(tǒng)的耦合性沒有使用JDK的動態(tài)代理好。
在Spring的AOP編程中,如果加入容器的目標(biāo)對象有實(shí)現(xiàn)接口,用JDK代理,如果目標(biāo)對象沒有實(shí)現(xiàn)接口,用Cglib代理
?
4 策略模式(Strategy Pattern)
4.1 什么是策略模式
針對一組算法,將每一種算法(策略類)都封裝到具有共同接口的獨(dú)立類中,從而他們可以相互替換,可以在不影響客戶端的情況下發(fā)生改變,從而改變不同的功能。
一個類的行為或其算法可以在運(yùn)行時更改。這種類型的設(shè)計(jì)模式屬于行為型模式。
特點(diǎn):封裝變化的概念;面向接口編程(編程中使用接口而不是使用具體的實(shí)現(xiàn)類)。
組成部分:(1)抽象策略角色:是抽象的角色,一般使用接口或抽象類實(shí)現(xiàn),如Comparator接口;
(2)具體策略角色:包裝了具體的算法和行為,如一組實(shí)現(xiàn)了Comparator接口的實(shí)現(xiàn)類;
(3)環(huán)境角色:內(nèi)部有一個抽象角色的引用,給客戶端調(diào)用,如TreeSet類,內(nèi)部一定有一個策略類的一個成員變量,這樣在創(chuàng)建TreeSet對象的時候可以接收向它傳遞的具體的策略類。
4.2 為什么使用策略模式
在有多種算法相似的情況下,使用 if...else 所帶來的復(fù)雜和難以維護(hù)。算法可以自由切換,擴(kuò)展良好;不過策略類會增多,還要對外暴露。
4.3 什么情況下可以使用
(1)如果一個系統(tǒng)中有很多的類,他們之間的區(qū)別是他們的行為不同,就可以用策略模式讓一個對象在那么多的行為中選擇一種;
(2)一個系統(tǒng)需要動態(tài)的在幾種算法中實(shí)現(xiàn)一種。
如果一個系統(tǒng)的策略多于四個,就需要考慮使用混合模式,解決策略類膨脹的問題。
4.4 案例
實(shí)現(xiàn)List集合增刪查的功能
編寫步驟:(1)定義抽象策略角色(定義一個策略對象的公共接口);(2)編寫具體策略角色(實(shí)現(xiàn)抽象策略角色這個公共接口);(3)定義環(huán)境變量(內(nèi)部一定要持有一個策略類的引用)。
(1)?定義抽象策略角色:
/*** @Description 定義抽象策略角色* @author refuel* @version v1.0*/ public interface AbstarctStrategy<T> {//實(shí)現(xiàn)對List集合的操作public Boolean handle(List<T> list,T t); }(2)編寫具體策略角色
/*** @Description 定義增加策略* @author refuel* @version v1.0*/ public class AddStrategy<T> implements AbstarctStrategy<T> {//實(shí)現(xiàn)handle方法,完成增加元素操作@Overridepublic Boolean handle(List<T> list, T t) {return list.add(t);}}/*** @Description 定義刪除策略* @author refuel* @version v1.0*/ public class RemoveStrategy<T> implements AbstarctStrategy<T> {//實(shí)現(xiàn)handle方法,完成刪除元素操作@Overridepublic Boolean handle(List<T> list, T t) {return list.remove(t);}}/*** @Description 定義查詢策略* @author refuel* @version v1.0*/ public class QueryStrategy<T> implements AbstarctStrategy<T> {//實(shí)現(xiàn)handle方法,完成查看元素是否存在操作@Overridepublic Boolean handle(List<T> list, T t) {return list.contains(t);}}(3)定義環(huán)境變量
/*** @Description 環(huán)境角色* @author refuel* @version v1.0*/ public class Environment<T> {//策略類的引用private AbstarctStrategy<T> strategy;public Environment(AbstarctStrategy<T> strategy) {this.strategy = strategy;}public Boolean handleList(List<T> list,T t) {return strategy.handle(list, t);} }(4)測試
/*** @Description 測試類* @author refuel* @version v1.0*/ public class Test {public static void main(String[] args) {Environment<Integer> en = new Environment<>(new AddStrategy<Integer>());List<Integer> arrList = Arrays.asList(10,20,30,40,50);List<Integer> list = new ArrayList<>(arrList);en.handleList(list, 60);for (Integer i : list) {System.out.print(i + " "); //運(yùn)行結(jié)果 10 20 30 40 50 60 }} }?
?
總結(jié)
以上是生活随笔為你收集整理的java基础之设计模式的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: linux历史追溯
- 下一篇: PowerBI,自定义编辑同一页面中不同