摘要:接口的適配器模式當(dāng)不希望實(shí)現(xiàn)一個接口中所有的方法時,可以創(chuàng)建一個抽象類,實(shí)現(xiàn)所有方法,我們寫別的類的時候,繼承抽象類即可。
總體分為3大類:
創(chuàng)建型模式 (5種):工廠方法、抽象工廠、單例、建造者、原型
結(jié)構(gòu)型模式(7種):適配器、裝飾器、代理、外觀、橋接、組合、享元
行為型模式(11種):策略、模板方法、觀察者、迭代子、責(zé)任鏈、命令、備忘錄、狀態(tài)、訪問者、中介者、解釋器
其它(2種):并發(fā)型、線程池
類的適配器
有一個待適配的Source類擁有一個方法,通過Adapter類將Source的功能擴(kuò)展到Targetable接口里。
public class Source { public void method1(){ System.out.println("this is original method!"); } }
public interface Targetable { /* 與原類中的方法相同 */ void method1(); /* 新類的方法 */ void method2(); }
public class Adapter extends Source implements Targetable { @Override public void method2() { System.out.println("this is the targetable method!"); } }
測試類
public class AdapterTest { public static void main(String[] args) { Targetable target = new Adapter(); target.method1(); target.method2(); } }
對象的適配器
Adapter 類持有 Source 類的實(shí)例,以達(dá)到解決兼容性的問題。
public class Wrapper implements Targetable { private Source source; public Wrapper(Source source) { this.source = source; } @Override public void method1() { source.method1(); } @Override public void method2() { System.out.println("this is the targetable method!"); } }
測試類:
public class AdapterTest { public static void main(String[] args) { Source source = new Source(); Targetable target = new Wrapper(source); target.method1(); target.method2(); } }
接口的適配器
借助一個抽象類實(shí)現(xiàn)接口所有的方法,寫一個類繼承該抽象類并重寫我們需要的方法就行 :
接口
public interface Sourceable { void method1(); void method2(); }
抽象類
public abstract class Wrapper2 implements Sourceable { @Override public void method1() {} @Override public void method2() {} }
public class SourceSub1 extends Wrapper2 { @Override public void method1() { System.out.println("the sourceable interface"s first Sub1!"); } }
public class SourceSub2 extends Wrapper2 { @Override public void method2() { System.out.println("the sourceable interface"s second Sub2!"); } }
測試類:
public class WrapperTest { public static void main(String[] args) { Sourceable source1 = new SourceSub1(); Sourceable source2 = new SourceSub2(); source1.method1(); source1.method2(); source2.method1(); source2.method2(); } }
類的適配器:當(dāng)希望將一個類轉(zhuǎn)換成滿足另一個新接口的類時,可以使用類的適配器模式,創(chuàng)建一個新類,繼承原有的類,實(shí)現(xiàn)新的接口即可。
對象的適配器模式:當(dāng)希望將一個對象轉(zhuǎn)換成滿足另一個新接口的對象時,可以創(chuàng)建一個Wrapper 類,持有原類的一個實(shí)例,在 Wrapper 類的方法中,調(diào)用實(shí)例的方法就行。
接口的適配器模式:當(dāng)不希望實(shí)現(xiàn)一個接口中所有的方法時,可以創(chuàng)建一個抽象類 Wrapper,實(shí)現(xiàn)所有方法,我們寫別的類的時候,繼承抽象類即可。
動態(tài)的給一個對象增加一些新的功能,要求裝飾對象和被裝飾對象實(shí)現(xiàn)同一個接口,裝飾對象持有被裝飾對象的實(shí)例,關(guān)系圖如下:
Source 類是被裝飾類,Decorator 類是一個裝飾類,可以為 Source 類動態(tài)的添加一些功能,
代碼如下 :
public interface Sourceable { void method(); }
public class Source implements Sourceable { @Override public void method() { System.out.println("the orignal method!"); } }
public class Decorator implements Sourceable { private Sourceable source; public Decorator(Sourceable source) { this.source = source; } @Override public void method() { System.out.println("before decorator!"); source.method(); System.out.println("after decorator!"); } }
測試類:
public class DecoratorTest { public static void main(String[] args) { Sourceable source = new Source(); Sourceable obj = new Decorator(source); obj.method(); } }
應(yīng)用場景:
1、需要擴(kuò)展一個類的功能。
2、動態(tài)的為一個對象增加功能,而且還能動態(tài)撤銷。(繼承不能做到這一點(diǎn),繼承的功能是靜態(tài)的,不能動態(tài)增刪。)
缺點(diǎn):產(chǎn)生過多相似的對象,不易排錯!
代理類替原對象進(jìn)行一些操作,比如我們在租房子的時候回去找中介,為什么呢?因?yàn)槟銓υ摰貐^(qū)房屋的信息掌握的不夠全面,希望找一個更熟悉的人去幫你做,此處的代理就是這個意思。
public interface Sourceable { void method(); }
public class Source implements Sourceable { @Override public void method() { System.out.println("thi original method!"); } }
public class Proxy implements Sourceable { private Source source; public Proxy() { super(); this.source = new Source(); } @Override public void method() { before(); source.method(); after(); } private void after() { System.out.println("after proxy!"); } private void before() { System.out.println("before proxy!"); } }
測試類:
public class ProxyTest { public static void main(String[] args) { Sourceable source = new Proxy(); source.method(); } }
應(yīng)用場景:
如果要對原有的方法進(jìn)行改進(jìn),此時有兩種辦法:
1、修改原有的方法來適應(yīng)。這樣違反了“對擴(kuò)展開放,對修改關(guān)閉”的原則。
2、采用一個代理類調(diào)用原有的方法,且對產(chǎn)生的結(jié)果進(jìn)行控制。這種方法就是代理模式。
使用代理模式,可以將功能劃分的更加清晰,有助于后期維護(hù)!
為了解決類與類之間的依賴關(guān)系,像spring一樣可以將類和類之間的關(guān)系配置到配置文件中,而外觀模式就是將他們的關(guān)系放在一個Facade類中,降低了類之間的耦合度:(我們以一個計(jì)算機(jī)的啟動過程為例)
public class CPU { public void startup(){ System.out.println("cpu startup!"); } public void shutdown(){ System.out.println("cpu shutdown!"); } }
public class Memory { public void startup(){ System.out.println("memory startup!"); } public void shutdown(){ System.out.println("memory shutdown!"); } }
public class Disk { public void startup(){ System.out.println("disk startup!"); } public void shutdown(){ System.out.println("disk shutdown!"); } }
public class Computer { private CPU cpu; private Memory memory; private Disk disk; public Computer() { cpu = new CPU(); memory = new Memory(); disk = new Disk(); } public void startup(){ System.out.println("start the computer!"); cpu.startup(); memory.startup(); disk.startup(); System.out.println("start computer finished!"); } public void shutdown(){ System.out.println("begin to close the computer!"); cpu.shutdown(); memory.shutdown(); disk.shutdown(); System.out.println("computer closed!"); } }
public class User { public static void main(String[] args) { Computer computer = new Computer(); computer.startup(); computer.shutdown(); } }五、橋接(Bridge)
把事物和其具體實(shí)現(xiàn)分開,使他們可以各自獨(dú)立的變化。橋接的用意是: 將抽象化與實(shí)現(xiàn)化解耦,使得二者可以獨(dú)立變化,像我們常用的 JDBC 橋 DriverManager 一樣,JDBC進(jìn)行連接數(shù)據(jù)庫的時候,在各個數(shù)據(jù)庫之間進(jìn)行切換,基本不需要動太多的代碼,甚至絲毫不用動,原因就是 JDBC 提供統(tǒng)一接口,每個數(shù)據(jù)庫提供各自的實(shí)現(xiàn),用一個叫做數(shù)據(jù)庫驅(qū)動的程序來橋接就行了 :
先定義接口:
public interface Sourceable { void method(); }
定義兩個實(shí)現(xiàn)類:
public class SourceSub1 implements Sourceable { @Override public void method() { System.out.println("this is the first sub!"); } }
public class SourceSub2 implements Sourceable { @Override public void method() { System.out.println("this is the second sub!"); } }
定義一個橋,持有 Sourceable 的一個實(shí)例:
public abstract class Bridge { private Sourceable source; public void method(){ source.method(); } public Sourceable getSource() { return source; } public void setSource(Sourceable source) { this.source = source; } }
public class MyBridge extends Bridge { @Override public void method() { getSource().method(); } }
測試類:
public class BridgeTest { public static void main(String[] args) { Bridge bridge = new MyBridge(); /*調(diào)用第一個對象*/ Sourceable source1 = new SourceSub1(); bridge.setSource(source1); bridge.method(); /*調(diào)用第二個對象*/ Sourceable source2 = new SourceSub2(); bridge.setSource(source2); bridge.method(); } }
這樣,就通過對 Bridge 類的調(diào)用,實(shí)現(xiàn)了對接口 Sourceable 的實(shí)現(xiàn)類 SourceSub1 和SourceSub2 的調(diào)用。接下來我再畫個圖,大家就應(yīng)該明白了,因?yàn)檫@個圖是我們 JDBC 連接的原理,有數(shù)據(jù)庫學(xué)習(xí)基礎(chǔ)的,一結(jié)合就都懂了。
六、組合(Composite)在處理類似樹形結(jié)構(gòu)的問題時比較方便:
public class TreeNode { private String name; private TreeNode parent; private Vectorchildren = new Vector (); public TreeNode(String name) { this.name = name; } public String getName() { return name; } public void setName(String name) { this.name = name; } public TreeNode getParent() { return parent; } public void setParent(TreeNode parent) { this.parent = parent; } //添加孩子節(jié)點(diǎn) public void add(TreeNode node){ children.add(node); } //刪除孩子節(jié)點(diǎn) public void remove(TreeNode node){ children.remove(node); } //取得孩子節(jié)點(diǎn) public Enumeration getChildren(){ return children.elements(); } }
public class Tree { TreeNode root = null; public Tree(String name){ root = new TreeNode(name); } public static void main(String[] args) { Tree tree = new Tree("A"); TreeNode nodeB = new TreeNode("B"); TreeNode nodeC = new TreeNode("C"); nodeB.add(nodeC); tree.root.add(nodeB); System.out.println("build the tree finished!"); } }
使用場景:將多個對象組合在一起進(jìn)行操作,常用于表示樹形結(jié)構(gòu)中,例如二叉樹,數(shù)等。
七、享元(Flyweight)實(shí)現(xiàn)對象的共享,即共享池,當(dāng)系統(tǒng)中對象多的時候可以減少內(nèi)存的開銷,通常與工廠模式一起使用。
FlyWeightFactory 負(fù)責(zé)創(chuàng)建和管理享元單元,當(dāng)一個客戶端請求時,工廠需要檢查當(dāng)前對象池中是否有符合條件的對象,如果有,就返回已經(jīng)存在的對象,如果沒有,則創(chuàng)建一個新對象,F(xiàn)lyWeight 是超類。一提到共享池,我們很容易聯(lián)想到 Java 里面的 JDBC 連接池,想想每個連接的特點(diǎn),我們不難總結(jié)出:適用于作共享的一些個對象,他們有一些共有的屬性,就拿數(shù)據(jù)庫連接池來說,url、driverClassName、username、password 及 dbname,這些屬性對于每個連接來說都是一樣的,所以就適合用享元模式來處理,建一個工廠類,將上述類似屬性作為內(nèi)部數(shù)據(jù),其它的作為外部數(shù)據(jù),在方法調(diào)用時,當(dāng)做參數(shù)傳進(jìn)來,這樣就節(jié)省了空間,減少了實(shí)例的數(shù)量。
看個例子:
看下數(shù)據(jù)庫連接池的代碼:
public class ConnectionPool { private Vectorpool; /*公有屬性*/ private String url = "jdbc:mysql://localhost:3306/test"; private String username = "root"; private String password = "root"; private String driverClassName = "com.mysql.jdbc.Driver"; private int poolSize = 100; private static ConnectionPool instance = null; Connection conn = null; /*構(gòu)造方法,做一些初始化工作*/ private ConnectionPool() { pool = new Vector (poolSize); for (int i = 0; i < poolSize; i++) { try { Class.forName(driverClassName); conn = DriverManager.getConnection(url, username, password); pool.add(conn); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (SQLException e) { e.printStackTrace(); } } } /* 返回連接到連接池 */ public synchronized void release() { pool.add(conn); } /* 返回連接池中的一個數(shù)據(jù)庫連接 */ public synchronized Connection getConnection() { if (pool.size() > 0) { Connection conn = pool.get(0); pool.remove(conn); return conn; } else { return null; } } }
通過連接池的管理,實(shí)現(xiàn)了數(shù)據(jù)庫連接的共享,不需要每一次都重新創(chuàng)建連接,節(jié)省了數(shù)據(jù)庫
重新創(chuàng)建的開銷,提升了系統(tǒng)的性能!
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/71047.html
摘要:當(dāng)然,除了讓我們顯得更加專業(yè)之外,在自己所學(xué)習(xí)或者工作的項(xiàng)目中,適當(dāng)合理的使用設(shè)計(jì)模式,能夠給項(xiàng)目帶來很大的好處。 簡單說兩句 本文首發(fā)公眾號【一名打字員】 對不住各位老鐵了,年前說好要更幾波JAVA的東西,又偷懶了,沒辦法,在這里用小錘錘偷偷錘了自己幾下。由于工作原因,更新時間不定,各位老鐵有問題可以私聊我哈。 對于初學(xué)者或者是正在向中高級的Java程序猿(打字員)來說,時刻梳理自己...
摘要:設(shè)計(jì)模式的類別設(shè)計(jì)模式一共分為種類型,共種。屬于結(jié)構(gòu)型的設(shè)計(jì)模式適配器模式橋接模式裝飾模式組合模式外觀模式享元模式代理模式。問題描述了應(yīng)該在何時使用設(shè)計(jì)模式。解決方案描述了設(shè)計(jì)的組成成分,它們之間的相互關(guān)系及各自的職責(zé)和協(xié)作方式。 設(shè)計(jì)模式概述 1. 設(shè)計(jì)模式是什么 我們在平時編寫代碼的過程中,會遇到各種各樣的問題,細(xì)想一下很多問題的解決思路大致一樣的,這時候你就可以把解決問題的思路整...
摘要:能夠協(xié)調(diào)調(diào)用者和被調(diào)用者,能夠在一定程度上降低系統(tǒng)的耦合性。特點(diǎn)低耦合性,獨(dú)立性好,安全性應(yīng)用客戶訪問不到或者被訪問者希望隱藏自己,所以通過代理來訪問自己。 我們接著上面的幾種模式繼續(xù)講: 4、組合模式 將對象組合成樹形結(jié)構(gòu)表示部分-整體的層次結(jié)構(gòu)。 特點(diǎn):靈活性強(qiáng) 應(yīng)用:對象的部分-整體的層次結(jié)構(gòu),模糊組合對象和簡單對象處理問題 代碼實(shí)現(xiàn) /** 組合模式* *///繼承模式clas...
摘要:分別為適配器模式,裝飾器模式,代理模式,外觀模式,橋接模式,組合模式,享元模式。設(shè)計(jì)模式五適配器模式適配器模式將某個對象的接生成器和協(xié)程的實(shí)現(xiàn)在這篇文章中,作者針對那些比較難以理解的概念,以一個更為通俗的方式去講明白。。 PHP 源碼注解 PHP 的詳細(xì)源碼注解 PHP 字符串操作整理 一些有關(guān)字符串的常用操作。 Redis 常見七種使用場景 (PHP 實(shí)戰(zhàn)) 這篇文章主要介紹利用 R...
摘要:設(shè)計(jì)模式的分類經(jīng)典應(yīng)用框架中常見的設(shè)計(jì)模式分為三類創(chuàng)建型模式對類的實(shí)例化過程的抽象。對象的結(jié)構(gòu)模式是動態(tài)的。對象的行為模式則使用對象的聚合來分配行為。設(shè)計(jì)模式是個好東西,以后肯定還要進(jìn)一步的學(xué)習(xí),并且在項(xiàng)目中多實(shí)踐,提升自己的設(shè)計(jì)能力。 什么是設(shè)計(jì)模式? Christopher Alexander?說過:每一個模式描述了一個在我們周圍不斷重復(fù)發(fā)生的問題,以及該問題的解決方案的核心。這樣...
摘要:推文設(shè)計(jì)模式適配器模式不兼容結(jié)構(gòu)的協(xié)調(diào)適配器模式四外觀模式老倉庫的角落,我們數(shù)著一麻袋的愛跟快樂初戀的顏色麥芽糖通過外觀角色來交互,降低子系統(tǒng)與客戶端的耦合度。 代理模式 我決定插手你的人生,當(dāng)你的時尚顧問 《陽光宅男》 通過代理對象進(jìn)行交互(或占位),強(qiáng)調(diào)訪問控制(也能增加額外功能,比如:日志);與被代理對象具有相同接口; showImg(https://segmentfault.c...
閱讀 3011·2021-11-16 11:51
閱讀 2634·2021-09-22 15:02
閱讀 3756·2021-08-04 10:21
閱讀 3670·2019-08-30 15:43
閱讀 1977·2019-08-30 11:04
閱讀 3624·2019-08-29 17:14
閱讀 516·2019-08-29 12:16
閱讀 2961·2019-08-28 18:31