摘要:接口的適配器模式當不希望實現一個接口中所有的方法時,可以創建一個抽象類,實現所有方法,我們寫別的類的時候,繼承抽象類即可。
總體分為3大類:
創建型模式 (5種):工廠方法、抽象工廠、單例、建造者、原型
結構型模式(7種):適配器、裝飾器、代理、外觀、橋接、組合、享元
行為型模式(11種):策略、模板方法、觀察者、迭代子、責任鏈、命令、備忘錄、狀態、訪問者、中介者、解釋器
其它(2種):并發型、線程池
類的適配器
有一個待適配的Source類擁有一個方法,通過Adapter類將Source的功能擴展到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 類的實例,以達到解決兼容性的問題。
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(); } }
接口的適配器
借助一個抽象類實現接口所有的方法,寫一個類繼承該抽象類并重寫我們需要的方法就行 :
接口
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(); } }
類的適配器:當希望將一個類轉換成滿足另一個新接口的類時,可以使用類的適配器模式,創建一個新類,繼承原有的類,實現新的接口即可。
對象的適配器模式:當希望將一個對象轉換成滿足另一個新接口的對象時,可以創建一個Wrapper 類,持有原類的一個實例,在 Wrapper 類的方法中,調用實例的方法就行。
接口的適配器模式:當不希望實現一個接口中所有的方法時,可以創建一個抽象類 Wrapper,實現所有方法,我們寫別的類的時候,繼承抽象類即可。
動態的給一個對象增加一些新的功能,要求裝飾對象和被裝飾對象實現同一個接口,裝飾對象持有被裝飾對象的實例,關系圖如下:
Source 類是被裝飾類,Decorator 類是一個裝飾類,可以為 Source 類動態的添加一些功能,
代碼如下 :
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(); } }
應用場景:
1、需要擴展一個類的功能。
2、動態的為一個對象增加功能,而且還能動態撤銷。(繼承不能做到這一點,繼承的功能是靜態的,不能動態增刪。)
缺點:產生過多相似的對象,不易排錯!
代理類替原對象進行一些操作,比如我們在租房子的時候回去找中介,為什么呢?因為你對該地區房屋的信息掌握的不夠全面,希望找一個更熟悉的人去幫你做,此處的代理就是這個意思。
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(); } }
應用場景:
如果要對原有的方法進行改進,此時有兩種辦法:
1、修改原有的方法來適應。這樣違反了“對擴展開放,對修改關閉”的原則。
2、采用一個代理類調用原有的方法,且對產生的結果進行控制。這種方法就是代理模式。
使用代理模式,可以將功能劃分的更加清晰,有助于后期維護!
為了解決類與類之間的依賴關系,像spring一樣可以將類和類之間的關系配置到配置文件中,而外觀模式就是將他們的關系放在一個Facade類中,降低了類之間的耦合度:(我們以一個計算機的啟動過程為例)
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)
把事物和其具體實現分開,使他們可以各自獨立的變化。橋接的用意是: 將抽象化與實現化解耦,使得二者可以獨立變化,像我們常用的 JDBC 橋 DriverManager 一樣,JDBC進行連接數據庫的時候,在各個數據庫之間進行切換,基本不需要動太多的代碼,甚至絲毫不用動,原因就是 JDBC 提供統一接口,每個數據庫提供各自的實現,用一個叫做數據庫驅動的程序來橋接就行了 :
先定義接口:
public interface Sourceable { void method(); }
定義兩個實現類:
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 的一個實例:
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(); /*調用第一個對象*/ Sourceable source1 = new SourceSub1(); bridge.setSource(source1); bridge.method(); /*調用第二個對象*/ Sourceable source2 = new SourceSub2(); bridge.setSource(source2); bridge.method(); } }
這樣,就通過對 Bridge 類的調用,實現了對接口 Sourceable 的實現類 SourceSub1 和SourceSub2 的調用。接下來我再畫個圖,大家就應該明白了,因為這個圖是我們 JDBC 連接的原理,有數據庫學習基礎的,一結合就都懂了。
六、組合(Composite)在處理類似樹形結構的問題時比較方便:
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; } //添加孩子節點 public void add(TreeNode node){ children.add(node); } //刪除孩子節點 public void remove(TreeNode node){ children.remove(node); } //取得孩子節點 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!"); } }
使用場景:將多個對象組合在一起進行操作,常用于表示樹形結構中,例如二叉樹,數等。
七、享元(Flyweight)實現對象的共享,即共享池,當系統中對象多的時候可以減少內存的開銷,通常與工廠模式一起使用。
FlyWeightFactory 負責創建和管理享元單元,當一個客戶端請求時,工廠需要檢查當前對象池中是否有符合條件的對象,如果有,就返回已經存在的對象,如果沒有,則創建一個新對象,FlyWeight 是超類。一提到共享池,我們很容易聯想到 Java 里面的 JDBC 連接池,想想每個連接的特點,我們不難總結出:適用于作共享的一些個對象,他們有一些共有的屬性,就拿數據庫連接池來說,url、driverClassName、username、password 及 dbname,這些屬性對于每個連接來說都是一樣的,所以就適合用享元模式來處理,建一個工廠類,將上述類似屬性作為內部數據,其它的作為外部數據,在方法調用時,當做參數傳進來,這樣就節省了空間,減少了實例的數量。
看個例子:
看下數據庫連接池的代碼:
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; /*構造方法,做一些初始化工作*/ 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); } /* 返回連接池中的一個數據庫連接 */ public synchronized Connection getConnection() { if (pool.size() > 0) { Connection conn = pool.get(0); pool.remove(conn); return conn; } else { return null; } } }
通過連接池的管理,實現了數據庫連接的共享,不需要每一次都重新創建連接,節省了數據庫
重新創建的開銷,提升了系統的性能!
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/71047.html
摘要:當然,除了讓我們顯得更加專業之外,在自己所學習或者工作的項目中,適當合理的使用設計模式,能夠給項目帶來很大的好處。 簡單說兩句 本文首發公眾號【一名打字員】 對不住各位老鐵了,年前說好要更幾波JAVA的東西,又偷懶了,沒辦法,在這里用小錘錘偷偷錘了自己幾下。由于工作原因,更新時間不定,各位老鐵有問題可以私聊我哈。 對于初學者或者是正在向中高級的Java程序猿(打字員)來說,時刻梳理自己...
摘要:設計模式的類別設計模式一共分為種類型,共種。屬于結構型的設計模式適配器模式橋接模式裝飾模式組合模式外觀模式享元模式代理模式。問題描述了應該在何時使用設計模式。解決方案描述了設計的組成成分,它們之間的相互關系及各自的職責和協作方式。 設計模式概述 1. 設計模式是什么 我們在平時編寫代碼的過程中,會遇到各種各樣的問題,細想一下很多問題的解決思路大致一樣的,這時候你就可以把解決問題的思路整...
摘要:能夠協調調用者和被調用者,能夠在一定程度上降低系統的耦合性。特點低耦合性,獨立性好,安全性應用客戶訪問不到或者被訪問者希望隱藏自己,所以通過代理來訪問自己。 我們接著上面的幾種模式繼續講: 4、組合模式 將對象組合成樹形結構表示部分-整體的層次結構。 特點:靈活性強 應用:對象的部分-整體的層次結構,模糊組合對象和簡單對象處理問題 代碼實現 /** 組合模式* *///繼承模式clas...
摘要:設計模式的分類經典應用框架中常見的設計模式分為三類創建型模式對類的實例化過程的抽象。對象的結構模式是動態的。對象的行為模式則使用對象的聚合來分配行為。設計模式是個好東西,以后肯定還要進一步的學習,并且在項目中多實踐,提升自己的設計能力。 什么是設計模式? Christopher Alexander?說過:每一個模式描述了一個在我們周圍不斷重復發生的問題,以及該問題的解決方案的核心。這樣...
摘要:推文設計模式適配器模式不兼容結構的協調適配器模式四外觀模式老倉庫的角落,我們數著一麻袋的愛跟快樂初戀的顏色麥芽糖通過外觀角色來交互,降低子系統與客戶端的耦合度。 代理模式 我決定插手你的人生,當你的時尚顧問 《陽光宅男》 通過代理對象進行交互(或占位),強調訪問控制(也能增加額外功能,比如:日志);與被代理對象具有相同接口; showImg(https://segmentfault.c...
閱讀 2975·2021-11-16 11:51
閱讀 2608·2021-09-22 15:02
閱讀 3723·2021-08-04 10:21
閱讀 3605·2019-08-30 15:43
閱讀 1947·2019-08-30 11:04
閱讀 3599·2019-08-29 17:14
閱讀 490·2019-08-29 12:16
閱讀 2933·2019-08-28 18:31