一、設計模式的分類
1.1 三大類
創建型模式 ,共五種:單例模式、抽象工廠模式、工廠方法模式、建造者模式、原型模式。 結構型模式 ,共七種:適配器模式、裝飾器模式、代理模式、外觀模式、橋接模式、組合模式、享元模式。 行為型模式 ,共十一種:策略模式、模板方法模式、觀察者模式、迭代子模式、責任鏈模式、命令模式、備忘錄模式、狀態模式、訪問者模式、中介者模式、解釋器模式。
1.2 簡述
1.2.1 創建型
Singleton,單例模式:保證一個類只有一個實例,并提供一個訪問它的全局訪問點 Abstract Factory,抽象工廠:提供一個創建一系列相關或相互依賴對象的接口,而無須指定它們的具體類。 Factory Method,工廠方法:定義一個用于創建對象的接口,讓子類決定實例化哪一個類,Factory Method使一個類的實例化延遲到了子類。 Builder,建造模式:將一個復雜對象的構建與他的表示相分離,使得同樣的構建過程可以創建不同的表示。 Prototype,原型模式:用原型實例指定創建對象的種類,并且通過拷貝這些原型來創建新的對象。
1.2.2 行為型
Iterator,迭代器模式:提供一個方法順序訪問一個聚合對象的各個元素,而又不需要暴露該對象的內部表示。 Observer,觀察者模式:定義對象間一對多的依賴關系,當一個對象的狀態發生改變時,所有依賴于它的對象都得到通知自動更新。 Template Method,模板方法:定義一個操作中的算法的骨架,而將一些步驟延遲到子類中,TemplateMethod使得子類可以不改變一個算法的結構即可以重定義該算法得某些特定步驟。 Command,命令模式:將一個請求封裝為一個對象,從而使你可以用不同的請求對客戶進行參數化,對請求排隊和記錄請求日志,以及支持可撤銷的操作。 State,狀態模式:允許對象在其內部狀態改變時改變他的行為。對象看起來似乎改變了他的類。 Strategy,策略模式:定義一系列的算法,把他們一個個封裝起來,并使他們可以互相替換,本模式使得算法可以獨立于使用它們的客戶。 Chain of Responsibility,職責鏈模式:使多個對象都有機會處理請求,從而避免請求的送發者和接收者之間的耦合關系 Mediator,中介者模式:用一個中介對象封裝一些列的對象交互。 Visitor,訪問者模式:表示一個作用于某對象結構中的各元素的操作,它使你可以在不改變各元素類的前提下定義作用于這個元素的新操作。 Interpreter,解釋器模式:給定一個語言,定義他的文法的一個表示,并定義一個解釋器,這個解釋器使用該表示來解釋語言中的句子。 Memento,備忘錄模式:在不破壞對象的前提下,捕獲一個對象的內部狀態,并在該對象之外保存這個狀態。
1.2.3 結構型
Composite,組合模式:將對象組合成樹形結構以表示部分整體的關系,Composite使得用戶對單個對象和組合對象的使用具有一致性。 Facade,外觀模式:為子系統中的一組接口提供一致的界面,Facade提供了一高層接口,這個接口使得子系統更容易使用。 Proxy,代理模式:為其他對象提供一種代理以控制對這個對象的訪問 Adapter,適配器模式:將一類的接口轉換成客戶希望的另外一個接口,Adapter模式使得原本由于接口不兼容而不能一起工作那些類可以一起工作。 Decrator,裝飾模式:動態地給一個對象增加一些額外的職責,就增加的功能來說,Decorator模式相比生成子類更加靈活。 Bridge,橋模式:將抽象部分與它的實現部分相分離,使他們可以獨立的變化。 Flyweight,享元模式
1.3 設計模式的六大原則
1.3.1 開閉原則(Open Close Principle)
開閉原則就是說對擴展開放,對修改關閉。 在程序需要進行拓展的時候,不能去修改原有的代碼。 程序得有強擴展性,易于維護和升級。 所以需要使用接口和抽象類。
1.3.2 里氏代換原則(Liskov Substitution Principle)
面向對象設計的基本原則之一; 任何基類可以出現的地方,子類一定可以出現; LSP 是繼承復用的基石,只有當衍生類可以替換掉基類,軟件單位的功能不受到影響時,基類才能真正被復用,而衍生類也能夠在基類的基礎上增加新的行為; LSP 是對“開-閉”原則的補充。實現“開-閉”原則的關鍵步驟就是抽象化。而基類與子類的繼承關系就是抽象化的具體實現,所以里氏代換原則是對實現抽象化的具體步驟的規范。
1.3.3 依賴倒轉原則(Dependence Inversion Principle)
這個是開閉原則的基礎,具體內容:真對接口編程,依賴于抽象而不依賴于具體。
1.3.4 接口隔離原則(Interface Segregation Principle)
使用多個隔離的接口,比使用單個接口要好; 降低類之間的耦合度
1.3.5 迪米特法則(最少知道原則)(Demeter Principle)
一個實體應當盡量少的與其他實體之間發生相互作用,使得系統功能模塊相對獨立。
1.3.6 合成復用原則(Composite Reuse Principle)
原則是盡量使用合成/聚合的方式,而不是使用繼承。
二、23 種設計模式的詳解
2.1 工廠方法模式(Factory Method)
2.1.1 普通工廠模式
就是建立一個工廠類,對實現了同一接口的一些類進行實例的創建。
創建思路:
一個接口 實現接口的一些類 一個工廠類:用來創建類實例
例子
比如,我們想讓一張紙打印出符合特定模板的內容,
創建過程 :
一個接口——初始模板 實現接口的一些類——改進模板 一個工廠類:用來創建類實例——打印機 比如,一臺打印機是用來打印的工廠,我們設定一個初始模板,然后根據這個模板發展出改進模板。
public interface Template { void Print ( ) ;
}
public class HelloTemplate implements Template { @Override public void Print ( ) { System . out
. println ( "this is HelloTemplate!" ) ; }
}
public class WorldTemplate implements Template { @Override public void Print ( ) { System . out
. println ( "this is WorldTemplate!" ) ; }
}
public class Printer { public Template produce ( String type
) { if ( "Hello" . equals ( type
) ) { return new HelloTemplate ( ) ; } else if ( "World" . equals ( type
) ) { return new WorldTemplate ( ) ; } else { System . out
. println ( "請輸入正確的類型!" ) ; return null ; } }
}
public class FactoryTest { public static void main ( String [ ] args
) { Printer printer
= new Printer ( ) ; Template tmp1
= printer
. produce ( "Hello" ) ; Template tmp2
= printer
. produce ( "World" ) ; tmp1. Print( ) ; tmp2. Print( ) ; }
}
2.1.2 多個工廠方法模式
原來通過傳入字符串的方式來決定返回哪個類的方法,是不合理的,因為如果傳入的字符串有誤,不能正確創建對象,這樣會不利于擴展新類。 所以這里改變對工廠類進行了改變。
public class Printer { public Template produceHello ( ) { return new HelloTemplate ( ) ; } public Template produceWorld ( ) { return new WorldTemplate ( ) ; }
}
修改后的調用方式如下
public class FactoryTest { public static void main ( String [ ] args
) { Printer printer
= new Printer ( ) ; Template tmp1
= printer
. produceHello ( ) ; Template tmp2
= printer
. produceWorld ( ) ; tmp1. Print( ) ; tmp2. Print( ) ; }
}
2.1.3 靜態工廠方法模式
將多個工廠方法模式里的方法置為靜態的,就不需要創建實例,直接調用即可。 大多數情況下,我們會選用此模式。
public class Printer { public static Template produceHello ( ) { return new HelloTemplate ( ) ; } public static Template produceWorld ( ) { return new WorldTemplate ( ) ; }
}
直接調用
public class FactoryTest { public static void main ( String [ ] args
) { Template template1
= Printer . produceHello ( ) ; Template template2
= Printer . produceWorld ( ) ; template1. Print( ) ; template2. Print( ) ; }
}
2.2 抽象工廠模式(Abstract Factory)
工廠方法模式有一個問題就是,類的創建依賴工廠類,也就是說,如果想要拓展程序,必須對工廠類進行修改,這違背了閉包原則。 所以想法是,創建多個工廠類,這樣一旦需要增加新的功能,直接增加新的工廠類就可以了,不需要修改之前的代碼。
創建思路:
一個接口 實現接口的n個類 一個工廠接口 實現工廠接口的n個工廠類:其中分別對應調用了實現接口的n個類
例子
比如,我們想讓制造多個種類的車輛。
創建過程 :
一個接口:車輛模板 實現接口的n個類:不同種類 一個工廠接口:車輛制造廠 實現工廠接口的n個工廠類:其中分別對應調用了實現接口的n個類:不同種類車輛的制造廠
public interface Car { public void run ( ) ;
}
public class Pickup implements Car { @Override public void run ( ) { System . out
. println ( "Pickup run." ) ; }
}
public class Roadster implements Car { @Override public void run ( ) { System . out
. println ( "Roadster run." ) ; }
}
public interface Factory { public Car make ( ) ;
}
public class PickupFactory implements Factory { @Override public Car make ( ) { System . out
. println ( "Make a Pickup." ) ; return new Pickup ( ) ; }
}
public class RoadsterFactory implements Factory { @Override public Car make ( ) { System . out
. println ( "Make a Roadster." ) ; return new Roadster ( ) ; }
}
public class FactoryTest { public static void main ( String [ ] args
) { Factory pickupFactory
= new PickupFactory ( ) ; Car pickup
= pickupFactory
. make ( ) ; pickup
. run ( ) ; Factory roadsterFactory
= new RoadsterFactory ( ) ; Car roadster
= roadsterFactory
. make ( ) ; roadster
. run ( ) ; }
}
2.3 單例模式(Singleton)
在 Java 應用中,單例對象能保證在一個 JVM中,該對象只有一個實例存在。
1、某些類創建比較頻繁,對于一些大型的對象,這是一筆很大的系統開銷。 2、省去了 new 操作符,降低了系統內存的使用頻率,減輕 GC 壓力。 3、有的類要求只能創建一次。
創建思路
私有構造方法,防止被實例化 使用一個內部類來維護單例——private static 獲取實例的方法——返回instance 保證對象在序列化前后保持一致的方法——返回獲取實例的方法
public class Singleton { private Singleton ( ) { } private static class SingletonFactory { private static Singleton instance
= new Singleton ( ) ; } public static Singleton getInstance ( ) { return SingletonFactory . instance
; } public Object readResolve ( ) { return getInstance ( ) ; }
}
為何這個創建方法是線程安全的?
單例模式使用內部類來維護單例的實現,JVM 內部的機制能夠保證當一個類 被加載的時候,這個類的加載過程是線程互斥的。 這樣當我們第一次調用 getInstance 的時候,JVM 能夠幫我們保證instance 只被創建一次,并且會保證把賦值給 instance 的內存初始化完畢。 同時該方法也只會在第一次調用的時候使用互斥機制,這樣就解決了低性能問題。
2.4 建造者模式(Builder)
建造者模式將各種產品集中起來進行管理,用來創建復合對象 所謂復合對象就是指某個類具有不同的屬性 建造者模式 = 抽象工廠模式 + 最后的Test。
不通過工廠來造車,而是通過一個類中的多個流水線(方法),批量造不同種類的車
創建思路
一個接口:車輛模板 實現接口的n個類:不同種類 批量生產各種車的Builder類
public class Builder { private List < Car > list
= new ArrayList < Car > ( ) ; public void producePickup ( int count
) { for ( int i
= 0 ; i
< count
; i
++ ) { list
. add ( new Pickup ( ) ) ; } } public void produceRoadster ( int count
) { for ( int i
= 0 ; i
< count
; i
++ ) { list
. add ( new Roadster ( ) ) ; } }
}
public class BuilderTest { public static void main ( String [ ] args
) { Builder builder
= new Builder ( ) ; builder
. producePickup ( 10 ) ; builder
. produceRoadster ( 5 ) ; }
}
2.5 原型模式(Prototype)
該模式的思想就是將一個對象作為原型,對其進行復制、克隆,產生一個和原對象類似的新對象。
創建思路
創建一個類 該類實現Cloneable接口 創建clone()方法,返回Object類,拋出CloneNotSupportedException 異常 在方法中Prototype proto = (Prototype) super.clone(); 并return proto;
public class Prototype implements Cloneable { public Object clone ( ) throws CloneNotSupportedException { Prototype proto
= ( Prototype ) super . clone ( ) ; return proto
; }
}
淺復制 (不徹底):將一個對象復制后,基本數據類型的變量都會重新創建,而引用類型,指向的還是原對象所指向的。
深復制 (完全徹底):將一個對象復制后,不論是基本數據類型還有引用類型,都是重新創建的。
public class Prototype implements Cloneable , Serializable { private static final long serialVersionUID
= 1L ; private String string
; private SerializableObject obj
; public Object clone ( ) throws CloneNotSupportedException { Prototype proto
= ( Prototype ) super . clone ( ) ; return proto
; } public Object deepClone ( ) throws IOException , ClassNotFoundException { ByteArrayOutputStream bos
= new ByteArrayOutputStream ( ) ; ObjectOutputStream oos
= new ObjectOutputStream ( bos
) ; oos
. writeObject ( this ) ; ByteArrayInputStream bis
= new ByteArrayInputStream ( bos
. toByteArray ( ) ) ; ObjectInputStream ois
= new ObjectInputStream ( bis
) ; return ois
. readObject ( ) ; } public String getString ( ) { return string
; } public void setString ( String string
) { this . string
= string
; } public SerializableObject getObj ( ) { return obj
; } public void setObj ( SerializableObject obj
) { this . obj
= obj
; } }
class SerializableObject implements Serializable { private static final long serialVersionUID
= 1L ;
}
2.6 適配器模式(Adapter)
2.6.1 類的適配器模式
核心思想:
創建一個 Source 類,擁有一個待適配的方法methodWaited; 目標接口 Targetable; 創建 Adapter 類,通過繼承 Source,實現 Targetable,將 Source 的方法methodWaited擴展到 Adapter 里
場景: 可知:不同的插座適用于不同的設備 如果:我們只有一種類型的設備卻找不到其適用的插座 需求:就需要找到一個可以將現有插座和現有設備連接起來的目標轉換器。
核心思路:
現有插座:Socket類,擁有一個待適配的方法PowerSupply 目標轉換器:目標接口 Switch; 現有插頭:Device 類,通過繼承 Socket,實現 Switch,將 Socket 的方法PowerSupply 擴展到 Device 里
public class Socket { public void PowerSupply ( ) { System . out
. println ( "Charging......" ) ; }
}
public interface Switch { public void PowerSupply ( ) ; public void OpenUp ( ) ;
}
public class Device extends Socket implements Switch { @Override public void OpenUp ( ) { System . out
. println ( "Starting up......" ) ; }
}
public class Test { public static void main ( String [ ] args
) { Device device
= new Device ( ) ; device. OpenUp( ) ; device. PowerSupply( ) ; }
}
應用場景: 當希望將一個類轉換成滿足另一個新接口的類時,可以使用類的適配器模式,創建一個新類,繼承原有的類,實現新的接口即可。
2.6.2 對象的適配器模式
基本思路 將 Adapter 類作修改,這次不繼承Source 類,而是持有 Source 類的實例,以達到解決兼容性的問題。
核心思想:
創建一個 Source 類,擁有一個待適配的方法methodWaited; 目標接口 Targetable; 創建 Adapter 類,通過實現 Targetable,持有 Source 類的實例,將 Source 的方法methodWaited擴展到 Adapter 里
場景: 可知:不同的插座適用于不同的設備 如果:我們只有一種類型的設備卻找不到其適用的插座 需求:就需要找到一個可以將現有插座和現有設備連接起來的目標轉換器。
核心思路:
現有插座:Socket類,擁有一個待適配的方法PowerSupply 目標轉換器:目標接口 Switch; 現有插頭:Device 類,通過繼承 Socket,持有 Switch 類的實例,將 Socket 的方法PowerSupply 擴展到 Device 里
public class Device implements Switch { private Socket socket
; public Device ( Socket s
) { super ( ) ; socket
= s
; } @Override public void PowerSupply ( ) { socket. PowerSupply( ) ; } @Override public void OpenUp ( ) { System . out
. println ( "Starting up......" ) ; }
}
public class Test { public static void main ( String [ ] args
) { Socket socket
= new Socket ( ) ; Device device
= new Device ( socket
) ; device. OpenUp( ) ; device. PowerSupply( ) ; }
}
應用場景: 當希望將一個對象轉換成滿足另一個新接口的對象時,可以創建一個Wrapper 類,持有原類的一個實例,在Wrapper 類的方法中,調用實例的方法就行。
2.6.3 接口的適配器模式
問題 :有時我們寫的一個接口中有多個抽象方法,當我們寫該接口的實現類時,必須實現該接口的所有方法,這明顯有時比較浪費,因為并不是所有的方法都是我們需要的;接口的適配器模式思想 :借助于一個抽象類,該抽象類實現了該接口,實現了所有的方法,而我們不和原始的接口打交道,只和該抽象類取得聯系。也即:寫一個類,繼承該抽象類,重寫我們需要的方法就行;
核心思想:
創建一個接口,擁有數個方法; 創建一個抽象類,實現接口; 創建幾個類,繼承抽象類,并實現想實現的方法。
場景: 可知:一棟大樓有很多房間 如果:房東有所有房間的鑰匙,而我們只想進去其中的幾間 需求:就需要各取所需的從房東那里打新鑰匙。
核心思路:
一棟大樓的所有房間:接口Building,有room1,room2等方法 房東的鑰匙們:抽象類KeyOrigin,內有room1,room2等方法的實現; 個人持有的鑰匙:KeyPerson1類,繼承KeyOrigin類,然后實現自己的房間的方法。比如Person1有room2,room3。
public interface Building { public void room1 ( ) ; public void room2 ( ) ; public void room3 ( ) ; public void room4 ( ) ;
}
public abstract class KeyOrigin implements Building { public void room1 ( ) { } public void room2 ( ) { } public void room3 ( ) { } public void room4 ( ) { }
}
public class Person1 extends KeyOrigin { public void room2 ( ) { System . out
. println ( "I own room2" ) ; } public void room3 ( ) { System . out
. println ( "I own room3" ) ; }
}
public class Person2 extends KeyOrigin { public void room1 ( ) { System . out
. println ( "I own room1" ) ; }
}
public class Test { public static void main ( String [ ] args
) { KeyOrigin person1
= new Person1 ( ) ; person1
. room2 ( ) ; person1
. room3 ( ) ; KeyOrigin person2
= new Person2 ( ) ; person2
. room1 ( ) ; }
}
應用場景: 當不希望實現一個接口中所有的方法時,可以創建一個抽象類Wrapper,實現所有方法,我們寫別的類的時候,繼承抽象類即可。
2.7 裝飾模式(Decorator)
給一個對象增加一些新的功能,而且是動態的; 要求裝飾對象和被裝飾對象實現同一個接口,裝飾對象持有被裝飾對象的實例。
核心思想:
Sourceable 是接口,其中有method方法; Source 類是被裝飾類,實現Sourceable,實現method方法; Decorator 類是一個裝飾類,實現Sourceable,在它的構造方法中傳入 Source 類實例,在實現method方法中調用 Source 類實例的method方法;
場景: 可知:我們要做漢堡,漢堡有三層,其上下均為面包,其中間為肉餅和菜; 需求:我們有肉餅和菜,要添加上其上下的面包;
核心思路:
Maker 是接口,其中有makeHamburger方法; MeatPie 類是被裝飾類,實現Maker,實現makeHamburger方法; Bread 類是一個裝飾類,實現Maker,在它的構造方法中傳入 Maker 類實例,在實現的makeHamburger方法中調用 MeatPie 類實例的makeHamburger方法;
public interface Maker { public void makeHamburger ( ) ;
}
public class MeatPie implements Maker { @Override public void makeHamburger ( ) { System . out
. println ( "Ketchup" ) ; System . out
. println ( "Vegetable" ) ; System . out
. println ( "Meat Pie" ) ; }
}
public class Bread implements Maker { private Maker maker
; public Bread ( Maker meatpie
) { super ( ) ; maker
= meatpie
; } @Override public void makeHamburger ( ) { System . out
. println ( "Bread" ) ; maker
. makeHamburger ( ) ; System . out
. println ( "Bread" ) ; }
}
public class Test { public static void main ( String [ ] args
) { Maker meatPie
= new MeatPie ( ) ; Bread bread
= new Bread ( meatPie
) ; bread
. makeHamburger ( ) ; }
}
2.8 代理模式(Proxy)
代理模式就是多一個代理類出來,替原對象進行一些操作。 目的也就是:讓專業的人做專業的事。
結構:
Sourceable 是接口,其中有method方法; Source 類,實現Sourceable,實現method方法; Proxy 類是一個代理類,實現Sourceable,在它的構造方法中new一個 Source 類實例,在實現method方法中調用 Source 類實例的method方法。
場景: 可知:我們要做漢堡,漢堡有三層,其上下均為面包,其中間為肉餅和菜; 需求:我們有肉餅和菜,要添加上其上下的面包;
核心思路:
Maker 是接口,其中有makeHamburger方法; MeatPie 類,實現Maker,實現makeHamburger方法; BreadAdder 類是一個代理類,實現Maker,在它的構造方法中new一個 MeatPie 類實例,在實現的makeHamburger方法中調用 MeatPie 類實例的makeHamburger方法;
public interface Maker { public void makeHamburger ( ) ;
}
public class MeatPie implements Maker { @Override public void makeHamburger ( ) { System . out
. println ( "Ketchup" ) ; System . out
. println ( "Vegetable" ) ; System . out
. println ( "Meat Pie" ) ; }
}
public class BreadAdder implements Maker { private Maker maker
; public BreadAdder ( ) { super ( ) ; maker
= new MeatPie ( ) ; } @Override public void makeHamburger ( ) { before ( ) ; maker
. makeHamburger ( ) ; after ( ) ; } public void before ( ) { System . out
. println ( "Bread" ) ; } public void after ( ) { System . out
. println ( "Bread" ) ; }
}
public class Test { public static void main ( String [ ] args
) { BreadAdder bread
= new BreadAdder ( ) ; bread
. makeHamburger ( ) ; }
}
2.9 外觀模式(Facade)
外觀模式就是將類之家的依賴關系放在一個Facade 類中,降低了類類之間的耦合度,該模式中沒有涉及到接口。
該方法比較直觀,下面是抽象開啟電腦的代碼,我們直接看代碼:
public class CPU
{ public void startup ( ) { System . out
. println ( "cpu startup!" ) ; } public void shutdown ( ) { System . out
. println ( "cpu shutdown!" ) ; }
}
public class Disk { public void startup ( ) { System . out
. println ( "disk startup!" ) ; } public void shutdown ( ) { System . out
. println ( "disk shutdown!" ) ; }
}
public class Memory { public void startup ( ) { System . out
. println ( "memory startup!" ) ; } public void shutdown ( ) { System . out
. println ( "memory 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 ( ) ; }
}
2.10 橋接模式(Bridge)
橋接模式就是把事物和其具體實現分開,使他們可以各自獨立的變化。
橋接的用意 是:將抽象化與實現化解耦,使得二者可以獨立變化
e.g. JDBC 橋 DriverManager:JDBC 進行連接數據庫的時候,在各個數據庫之間進行切換,基本不需要動太多的代碼,甚至絲毫不用動,原因就是JDBC 提供統一接口,每個數據庫提供各自的實現,用一個叫做數據庫驅動的程序來橋接就行了。
結構:
一個接口:Sourceable 接口的n個實現類:SourceSub1、SourceSub2 … 定義一個橋(abstract),持有 Sourceable 的一個實例 繼承橋的類
場景: 可知:我們要用同樣的方式,連接幾個不同的數據庫
核心思路:
一個接口:DatabaseTemplate 接口的n個實現類:Database1、Database2 … 定義一個橋AbstractManager,持有 DatabaseTemplate 的一個實例 繼承橋的類DriverManager
public interface DatabaseTemplate { public void build ( ) ;
}
public class MySQL implements DatabaseTemplate { @Override public void build ( ) { System . out
. println ( "Build MySQL" ) ; }
}
public class PostgreSQL implements DatabaseTemplate { @Override public void build ( ) { System . out
. println ( "Build PostgreSQL" ) ; }
}
public abstract class AbstractManager { private DatabaseTemplate template
; public void setDatabase ( DatabaseTemplate databaseTemplate
) { template
= databaseTemplate
; } public DatabaseTemplate getDatabase ( ) { return template
; } public void build ( ) { template
. build ( ) ; }
}
public class DriverManager extends AbstractManager { public void build ( ) { getDatabase ( ) . build ( ) ; }
}
public class Test { public static void main ( String [ ] args
) { AbstractManager driverManager
= new DriverManager ( ) ; MySQL mySQL
= new MySQL ( ) ; driverManager
. setDatabase ( mySQL
) ; driverManager
. build ( ) ; PostgreSQL postgreSQL
= new PostgreSQL ( ) ; driverManager
. setDatabase ( postgreSQL
) ; driverManager
. build ( ) ; }
}
2.11 組合模式(Composite)
有時又叫部分-整體模式 在處理類似樹形結構的問題時比較方便
public class TreeNode { private String name
; private TreeNode parent
; private Vector < TreeNode > children
= new Vector < TreeNode > ( ) ; 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 < TreeNode > 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 branch" ) ; TreeNode nodeB
= new TreeNode ( "B branch" ) ; TreeNode nodeC
= new TreeNode ( "C branch" ) ; nodeB
. add ( nodeC
) ; tree
. root
. add ( nodeB
) ; System . out
. println ( "Grow the tree finished!" ) ; }
}
2.12 享元模式(Flyweight)
享元模式的主要目的是實現對象的共享,即共享池,當系統中對象多的時候可以減少內存的開銷,通常與工廠模式一起使用。
FlyWeightFactory 負責創建和管理享元單元,當一個客戶端請求時,工廠需要檢查當前對象池中是否有符合條件的對象,如果有,就返回已經存在的對象,如果沒有,則創建一個新對象; FlyWeight 是超類。
e.g. Java 里面的JDBC 連接池
適用于作共享的一些個對象,他們有一些共有的屬性,url、driverClassName、username、password 及dbname,這些屬性對于每個連接來說都是一樣的,所以就適合用享元模式來處理 建一個工廠類,將上述類似屬性作為內部數據,其它的作為外部數據,在方法調用時,當做參數傳進來,這樣就節省了空間,減少了實例的數量。
public class ConnectionPool { private Vector < Connection > pool
; 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 < Connection > ( 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 ; } }
}
2.13 策略模式(strategy)
模式結構
定義一系列算法,并將每個算法封裝起來,使他們可以相互替換,且算法的變化不會影響到使用算法的客戶。 設計一個接口,為一系列實現類提供統一的方法,多個實現類實現該接口, 設計一個抽象類(可有可無,屬于輔助類),提供輔助函數
場景 一個計算器,其中包含有減法、加法、乘法、除法等運算
設計思路
設計一個接口ICalculator,為一系列實現類提供統一的方法,多個實現類實現該接口 定義一系列類,Minus、Plus、Multiply、Division,其中均有calculate方法,在方法中實現不同的算法; 設計一個抽象類AbstractCalculator,提供輔助函數
public interface ICalculator { public int calculate ( String exp
) ;
}
public abstract class AbstractCalculator { public int [ ] split ( String exp
, String opt
) { String array
[ ] = exp
. split ( opt
) ; int arrayInt
[ ] = new int [ 2 ] ; arrayInt
[ 0 ] = Integer . parseInt ( array
[ 0 ] ) ; arrayInt
[ 1 ] = Integer . parseInt ( array
[ 1 ] ) ; return arrayInt
; }
}
public class
Plus extends
AbstractCalculator implements
ICalculator { @Overridepublic int
calculate ( String exp
) { int arrayInt
[ ] = split ( exp
, "\\+" ) ; return arrayInt
[ 0 ] + arrayInt
[ 1 ] ; }
}
public class
Divide extends
AbstractCalculator implements
ICalculator { @Overridepublic int
calculate ( String exp
) { int arrayInt
[ ] = split ( exp
, "/" ) ; return arrayInt
[ 0 ] / arrayInt
[ 1 ] ; }
}
省略 Minus和Multiply類的建立過程,類似。
public class
StrategyTest { public static void
main ( String
[ ] args
) { String exp
= "8/2" ; ICalculator cal
= new Divide ( ) ; int result
= cal
. calculate ( exp
) ; System
. out
. println ( result
) ; }
}
2.14 模板方法模式(Template Method)
模式結構
一個抽象類中,有一個主方法,再定義1…n 個方法,可以是抽象的,也可以是實際的方法 定義一個類,繼承該抽象類,重寫抽象方法 通過調用抽象類,實現對子類的調用
場景 一個計算器,其中包含有減法、加法、乘法、除法等運算
設計思路
一個抽象類AbstractCalculator中,有一個主方法calculate,再定義1…n 個方法,可以是抽象的,也可以是實際的方法 定義幾個類,比如Plus、Minus,繼承抽象類AbstractCalculator,重寫抽象方法 通過調用抽象類AbstractCalculator,實現對子類的調用
public abstract class AbstractCalculator { public final int calculate ( String exp
, String opt
) { int array
[ ] = split ( exp
, opt
) ; return calculate ( array
[ 0 ] , array
[ 1 ] ) ; } abstract public int calculate ( int num1
, int num2
) ; public int [ ] split ( String exp
, String opt
) { String array
[ ] = exp
. split ( opt
) ; int arrayInt
[ ] = new int [ 2 ] ; arrayInt
[ 0 ] = Integer . parseInt ( array
[ 0 ] ) ; arrayInt
[ 1 ] = Integer . parseInt ( array
[ 1 ] ) ; return arrayInt
; }
}
public class Plus extends AbstractCalculator { @Override public int calculate ( int num1
, int num2
) { return num1
+ num2
; }
}
public class Minus extends AbstractCalculator { @Override public int calculate ( int num1
, int num2
) { return num1
- num2
; }
}
public class Test { public static void main ( String [ ] args
) { String exp
= "4+8" ; AbstractCalculator cal
= new Plus ( ) ; int result
= cal
. calculate ( exp
, "\\+" ) ; System . out
. println ( result
) ; exp
= "8-2" ; cal
= new Minus ( ) ; result
= cal
. calculate ( exp
, "\\-" ) ; System . out
. println ( result
) ; } }
2.15 觀察者模式(Observer)
當一個對象變化時,其它依賴該對象的對象都會收到通知,并且隨著變化
模式結構
接口類是 Observer; Observer1 和 Observer2 是實現于 Observer 的類,當 Observer 變化時,Observer1 和 Observer2 必然變化; 接口 Subject ; 抽象類 AbstractSubject 實現 Subject; MySubject 繼承 AbstractSubject,其中的 operation方法 隨著加入的Observer實現類不同而改變;
場景 比如我們關注了n個博客,可以關注到它們的更新信息
設計思路
接口 User ; Avatar1 和 Avatar2 是實現于 AbstractUser 的類; 接口類是 ProgramGroup; 抽象類 AbstractProgram 實現 ProgramGroup; Program 繼承 AbstractProgram,其中的 operation 方法 隨著加入的 User 實現類不同而改變;
public interface User { public void update ( ) ;
}
public class Avatar1 implements User { @Override public void update ( ) { System . out
. println ( "Avatar1 has received." ) ; }
}
public class Avatar2 implements User { @Override public void update ( ) { System . out
. println ( "Avatar2 has received." ) ; }
}
public interface ProgramGroup { public void add ( User user
) ; public void del ( User user
) ; public void notifyObservers ( ) ; public void operation ( ) ;
}
public abstract class AbstractProgram implements ProgramGroup { private Vector < User > vector
= new Vector < User > ( ) ; @Override public void add ( User user
) { vector
. add ( user
) ; } @Override public void del ( User user
) { vector
. remove ( user
) ; } @Override public void notifyObservers ( ) { Enumeration < User > enumo
= vector
. elements ( ) ; while ( enumo
. hasMoreElements ( ) ) { enumo
. nextElement ( ) . update ( ) ; } }
}
public class Program extends AbstractProgram { @Override public void operation ( ) { System . out
. println ( "update self!" ) ; notifyObservers ( ) ; }
}
public class Test { public static void main ( String [ ] args
) { AbstractProgram program
= new Program ( ) ; program
. add ( new Avatar1 ( ) ) ; program
. add ( new Avatar2 ( ) ) ; program
. operation ( ) ; }
}
2.16 迭代子模式(Iterator)
迭代器模式就是順序訪問聚集中的對象;
一是需要遍歷的對象,即聚集對象; 二是迭代器對象,用于對聚集對象進行遍歷訪問。
public interface Iterator { public Object previous ( ) ; public Object next ( ) ; public boolean hasNext ( ) ; public Object first ( ) ;
}
public interface Collection { public Iterator iterator ( ) ; public Object get ( int i
) ; public int size ( ) ;
}
public class MyIterator implements Iterator { private Collection collection
; private int pos
= - 1 ; public MyIterator ( Collection collection
) { this . collection
= collection
; } @Override public Object previous ( ) { if ( pos
> 0 ) { pos
-- ; } return collection
. get ( pos
) ; } @Override public Object next ( ) { if ( pos
< collection
. size ( ) - 1 ) { pos
++ ; } return collection
. get ( pos
) ; } @Override public boolean hasNext ( ) { if ( pos
< collection
. size ( ) - 1 ) { return true ; } else { return false ; } } @Override public Object first ( ) { pos
= 0 ; return collection
. get ( pos
) ; }
}
public class MyCollection implements Collection { public String string
[ ] = { "A" , "B" , "C" , "D" , "E" } ; @Override public Iterator iterator ( ) { return new MyIterator ( this ) ; } @Override public Object get ( int i
) { return string
[ i
] ; } @Override public int size ( ) { return string
. length
; }
}
public class Test { public static void main ( String [ ] args
) { Collection collection
= new MyCollection ( ) ; Iterator it
= collection
. iterator ( ) ; while ( it
. hasNext ( ) ) { System . out
. println ( it
. next ( ) ) ; } }
}
2.17 責任鏈模式(Chain of Responsibility)
有多個對象,每個對象持有對下一個對象的引用,這樣就會形成一條鏈,請求在這條鏈上傳遞,直到某一對象決定處理該請求。
模式結構
Abstracthandler 類提供了get 和set 方法 MyHandle 類是核心,設置和修改引用對象,實例化后生成一系列相互持有的對象,構成一條鏈。
public interface Handler { public void operator ( ) ;
}
public abstract class AbstractHandler { private Handler handler
; public Handler getHandler ( ) { return handler
; } public void setHandler ( Handler handler
) { this . handler
= handler
; } }
public class MyHandler extends AbstractHandler implements Handler { private String name
; public MyHandler ( String name
) { this . name
= name
; } @Override public void operator ( ) { System . out
. println ( name
+ "deal!" ) ; if ( getHandler ( ) != null ) { getHandler ( ) . operator ( ) ; } }
}
public class Test { public static void main ( String [ ] args
) { MyHandler h1
= new MyHandler ( "h1" ) ; MyHandler h2
= new MyHandler ( "h2" ) ; MyHandler h3
= new MyHandler ( "h3" ) ; h1
. setHandler ( h2
) ; h2
. setHandler ( h3
) ; h1
. operator ( ) ; }
}
2.18 命令模式(Command)
每個類相互解耦,任何一方都不用去依賴其他人,只需要做好自己的事兒就行
模式結構
Invoker類 是調用者 Receiver類 是被調用者 Command 接口 MyCommand 是命令,實現了Command 接口,持有接收對象
背景 司令員下令讓士兵去干件事情,從整個事情的角度來考慮,司令員的作用是,發出口令,口令經過傳遞,傳到了士兵耳朵里,士兵去執行。司令員要的是結果,不會去關注到底士兵是怎么實現的。
設計思路
Command 接口 MyCommand 是命令,實現了Command 接口,持有接收對象 Soldier 是士兵 Commander是司令員
public interface Command { public void exe ( ) ;
}
public class MyCommand implements Command { private Soldier receiver
; public MyCommand ( Soldier receiver
) { this . receiver
= receiver
; } @Override public void exe ( ) { receiver
. action ( ) ; }
}
public class Soldier { public void action ( ) { System . out
. println ( "Command received." ) ; }
}
public class Commander { private Command command
; public Commander ( Command command
) { this . command
= command
; } public void action ( ) { command
. exe ( ) ; }
}
2.19 備忘錄模式(Memento)
主要目的 保存一個對象的某個狀態,以便在適當的時候恢復對象
背景 假設有原始類A,A 中有各種屬性,A 可以決定需要備份的屬性,備忘錄類B 是用來存儲A 的一些內部狀態,類C 呢,就是一個用來存儲備忘錄的,且只能存儲,不能修改等操作。
結構
Original 類是原始類,里面有需要保存的屬性value 及創建一個備忘錄類,用來保存 value值; Memento 類是備忘錄類; Storage 類是存儲備忘錄的類,持有 Memento 類的實例,該模式很好理解。
public class Memento { private String value
; public Memento ( String value
) { this . value
= value
; } public String getValue ( ) { return value
; } public void setValue ( String value
) { this . value
= value
; }
}
public class Storage { private Memento memento
; public Storage ( Memento memento
) { this . memento
= memento
; } public Memento getMemento ( ) { return memento
; } public void setMemento ( Memento memento
) { this . memento
= memento
; }
}
public class Original { private String value
; public String getValue ( ) { return value
; } public void setValue ( String value
) { this . value
= value
; } public Original ( String value
) { this . value
= value
; } public Memento createMemento ( ) { return new Memento ( value
) ; } public void restoreMemento ( Memento memento
) { this . value
= memento
. getValue ( ) ; }
}
public class Test { public static void main ( String [ ] args
) { Original origi
= new Original ( "egg" ) ; Storage storage
= new Storage ( origi
. createMemento ( ) ) ; System . out
. println ( "初始化狀態為:" + origi
. getValue ( ) ) ; origi
. setValue ( "niu" ) ; System . out
. println ( "修改后的狀態為:" + origi
. getValue ( ) ) ; origi
. restoreMemento ( storage
. getMemento ( ) ) ; System . out
. println ( "恢復后的狀態為:" + origi
. getValue ( ) ) ; }
}
2.20 狀態模式(State)
核心思想 : 當對象的狀態改變時,同時改變其行為
背景 在QQ中,有幾種狀態,在線、隱身、忙碌等,每個狀態對應不同的操作,而且你的好友也能看到你的狀態
結構
State 類是個狀態類 Context 類實現切換
public class State { private String value
; public String getValue ( ) { return value
; } public void setValue ( String value
) { this . value
= value
; } public void method1 ( ) { System . out
. println ( "execute the first opt!" ) ; } public void method2 ( ) { System . out
. println ( "execute the second opt!" ) ; }
}
public class Context { private State state
; public Context ( State state
) { this . state
= state
; } public State getState ( ) { return state
; } public void setState ( State state
) { this . state
= state
; } public void method ( ) { if ( state
. getValue ( ) . equals ( "online" ) ) { state
. method1 ( ) ; } else if ( state
. getValue ( ) . equals ( "offline" ) ) state
. method2 ( ) ; }
}
public class Test { public static void main ( String [ ] args
) { State state
= new State ( ) ; Context context
= new Context ( state
) ; state
. setValue ( "online" ) ; context
. method ( ) ; state
. setValue ( "offline" ) ; context
. method ( ) ; }
}
2.21 訪問者模式(Visitor)
優缺點 :
優點是增加操作很容易,因為增加操作意味著增加新的訪問者。訪問者模式將有關行為集中到一個訪問者對象中,其改變不影響系統數據結構。 缺點就是增加新的數據結構很困難。
簡單來說,訪問者模式就是一種分離對象數據結構與行為的方法,通過這種分離,可達到為一個被訪問者動態添加新的操作而無需做其它的修改的效果。
結構
接口Visitor MyVisitor類實現接口Visitor,其中有visit方法 接口Subject,accept 方法,接受將要訪問它的對象,getSubject()獲取將要被訪問的屬性 MySubject類實現接口Subject,其中accept 方法導入參數為Visitor類,調用其中的visit方法
public interface Visitor { public void visit ( Subject sub
) ;
}
public class MyVisitor implements Visitor { @Override public void visit ( Subject sub
) { System . out
. println ( "visit the subject:" + sub
. getSubject ( ) ) ; }
}
public interface Subject { public void accept ( Visitor visitor
) ; public String getSubject ( ) ;
}
public class MySubject implements Subject { @Override public void accept ( Visitor visitor
) { visitor
. visit ( this ) ; } @Override public String getSubject ( ) { return "love" ; }
}
public class Test { public static void main ( String [ ] args
) { Visitor visitor
= new MyVisitor ( ) ; Subject sub
= new MySubject ( ) ; sub
. accept ( visitor
) ; }
}
2.22 中介者模式(Mediator)
降低類類之間的耦合的,因為如果類類之間有依賴關系的話,不利于功能的拓展和維護,因為只要修改一個對象,其它關聯的對象都得進行修改。 如果使用中介者模式,只需關心和Mediator 類的關系,具體類類之間的關系及調度交給Mediator 就行。
結構
User 抽象類,其中在實現方法中傳入 Mediator 類對象 User1 和User2 繼承 User 引入了 Mediator類,提供統一接口 MyMediator 為其實現類,里面持有 User1 和User2 的實例,用來實現對User1 和User2 的控制
public abstract class User { private Mediator mediator
; public Mediator getMediator ( ) { return mediator
; } public User ( Mediator mediator
) { this . mediator
= mediator
; } public abstract void work ( ) ; }
public class User1 extends User { public User1 ( Mediator mediator
) { super ( mediator
) ; } @Override public void work ( ) { System . out
. println ( "user1 exe!" ) ; }
}
public class User2 extends User { public User2 ( Mediator mediator
) { super ( mediator
) ; } @Override public void work ( ) { System . out
. println ( "user2 exe!" ) ; }
}
public interface Mediator { public void createMediator ( ) ; public void workAll ( ) ;
}
public class MyMediator implements Mediator { private User user1
; private User user2
; public User getUser1 ( ) { return user1
; } public User getUser2 ( ) { return user2
; } @Override public void createMediator ( ) { user1
= new User1 ( this ) ; user2
= new User2 ( this ) ; } @Override public void workAll ( ) { user1
. work ( ) ; user2
. work ( ) ; }
}
2.23 解釋器模式(Interpreter)
應用的少,主要應用在 OOP 開發中的編譯器的開發
public interface Expression { public int interpret ( Context context
) ;
}
public class Context { private int num1
; private int num2
; public Context ( int num1
, int num2
) { this . num1
= num1
; this . num2
= num2
; } public int getNum1 ( ) { return num1
; } public void setNum1 ( int num1
) { this . num1
= num1
; } public int getNum2 ( ) { return num2
; } public void setNum2 ( int num2
) { this . num2
= num2
; } }
public class Minus implements Expression { @Override public int interpret ( Context context
) { return context
. getNum1 ( ) - context
. getNum2 ( ) ; }
}
public class Plus implements Expression { @Override public int interpret ( Context context
) { return context
. getNum1 ( ) + context
. getNum2 ( ) ; }
}
public class Test { public static void main ( String [ ] args
) { int result
= new Minus ( ) . interpret ( ( new Context ( new Plus ( ) . interpret ( new Context ( 9 , 2 ) ) , 8 ) ) ) ; System . out
. println ( result
) ; }
}
總結
以上是生活随笔 為你收集整理的23种设计模式解析 的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔 網站內容還不錯,歡迎將生活随笔 推薦給好友。