設計模式彙總
總體來說設計模式分為三大類:
建立型模式,共五種:工廠方法模式、抽象工廠模式、單例模式、建造者模式、原型模式。
結構型模式,共七種:介面卡模式、裝飾器模式、代理模式、外觀模式、橋接模式、組合模式、享元模式。
行為型模式,共十一種:策略模式、模板方法模式、觀察者模式、迭代子模式、責任鏈模式、命令模式、備忘錄模式、狀態模式、訪問者模式、中介者模式、直譯器模式。
其實還有兩類:併發型模式和執行緒池模式。用一個圖片來整體描述一下:
一:工廠模式:
(1):工廠模式主要是為建立物件提供過渡介面,以便將建立物件的具體過程遮蔽隔離起來,達到提高靈活性的目的。
首先,建立二者的共同介面:
- public interface Sender {
- public void Send();
- }
其次,建立實現類:
- public class MailSender implements Sender {
- @Override
- public void Send() {
- System.out.println("this is mailsender!");
- }
- }
- public class SmsSender implements Sender {
- @Override
- public void Send() {
- System.out.println("this is sms sender!");
- }
- }
最後,建工廠類:
- public class SendFactory {
- public Sender produce(String type) {
- if ("mail".equals(type)) {
- return new MailSender();
- } else if ("sms".equals(type)) {
- return new SmsSender();
- } else {
- System.out.println("請輸入正確的型別!");
- return null;
- }
- }
- }
我們來測試下:
- public class FactoryTest {
- public static void main(String[] args) {
- SendFactory factory = new SendFactory();
- Sender sender = factory.produce("sms");
- sender.Send();
- }
- }
輸出:this is sms sender!
a、多個工廠方法模式,是對普通工廠方法模式的改進,在普通工廠方法模式中,如果傳遞的字串出錯,則不能正確建立物件,而多個工廠方法模式是提供多個工廠方法,分別建立物件。關係圖:
將上面的程式碼做下修改,改動下SendFactory類就行,如下:
[java] view plaincopypublic class SendFactory {
public Sender produceMail(){
- return new MailSender();
- }
- public Sender produceSms(){
- return new SmsSender();
- }
- }
測試類如下:
- public class FactoryTest {
- public static void main(String[] args) {
- SendFactory factory = new SendFactory();
- Sender sender = factory.produceMail();
- sender.Send();
- }
- }
輸出:this is mailsender!
b、靜態工廠方法模式,將上面的多個工廠方法模式裡的方法置為靜態的,不需要建立例項,直接呼叫即可。
- public class SendFactory {
- public static Sender produceMail(){
- return new MailSender();
- }
- public static Sender produceSms(){
- return new SmsSender();
- }
- }
- public class FactoryTest {
- public static void main(String[] args) {
- Sender sender = SendFactory.produceMail();
- sender.Send();
- }
- }
輸出:this is mailsender!
總體來說,工廠模式適合:凡是出現了大量的產品需要建立,並且具有共同的介面時,可以通過工廠方法模式進行建立。在以上的三種模式中,第一種如果傳 入的字串有誤,不能正確建立物件,第三種相對於第二種,不需要例項化工廠類,所以,大多數情況下,我們會選用第三種——靜態工廠方法模式。
可以看出工廠方法的加入,使得物件的數量成倍增長。當產品種類非常多時,會出現大量的與之對應的工廠物件,這不是我們所希望的。因為如果不能避免這種情 況,可以考慮使用簡單工廠模式與工廠方法模式相結合的方式來減少工廠類:即對於產品樹上類似的種類(一般是樹的葉子中互為兄弟的)使用簡單工廠模式來實 現。
c、簡單工廠和工廠方法模式的比較
工廠方法模式和簡單工廠模式在定義上的不同是很明顯的。工廠方法模式的核心是一個抽象工廠類,而不像簡單工廠模式, 把核心放在一個實類上。工廠方法模式可以允許很多實的工廠類從抽象工廠類繼承下來, 從而可以在實際上成為多個簡單工廠模式的綜合,從而推廣了簡單工廠模式。
反過來講,簡單工廠模式是由工廠方法模式退化而來。設想如果我們非常確定一個系統只需要一個實的工廠類, 那麼就不妨把抽象工廠類合併到實的工廠類中去。而這樣一來,我們就退化到簡單工廠模式了。
d、抽象工廠模式
程式碼:
//抽象工廠類
public abstract class AbstractFactory {
public abstract Vehicle createVehicle();
public abstract Weapon createWeapon();
public abstract Food createFood();
}
//具體工廠類,其中Food,Vehicle,Weapon是抽象類,
public class DefaultFactory extends AbstractFactory{
@Override
public Food createFood() {
return new Apple();
}
@Override
public Vehicle createVehicle() {
return new Car();
}
@Override
public Weapon createWeapon() {
return new AK47();
}
}
//測試類
public class Test {
public static void main(String[] args) {
AbstractFactory f = new DefaultFactory();
Vehicle v = f.createVehicle();
v.run();
Weapon w = f.createWeapon();
w.shoot();
Food a = f.createFood();
a.printName();
}
}
在抽象工廠模式中,抽象產品 (AbstractProduct) 可能是一個或多個,從而構成一個或多個產品族(Product Family)。 在只有一個產品族的情況下,抽象工廠模式實際上退化到工廠方法模式。
六、總結。
(1)簡單工廠模式是由一個具體的類去建立其他類的例項,父類是相同的,父類是具體的。
(2)工廠方法模式是有一個抽象的父類定義公共介面,子類負責生成具體的物件,這樣做的目的是將類的例項化操作延遲到子類中完成。
(3)抽象工廠模式提供一個建立一系列相關或相互依賴物件的介面,而無須指定他們具體的類。它針對的是有多個產品的等級結構。而工廠方法模式針對的是一個產品的等級結構。
二、單例模式(Singleton)
單例物件(Singleton)是一種常用的設計模式。在Java應用中,單例物件能保證在一個JVM中,該物件只有一個例項存在。這樣的模式有幾個好處:
1、某些類建立比較頻繁,對於一些大型的物件,這是一筆很大的系統開銷。
2、省去了new操作符,降低了系統記憶體的使用頻率,減輕GC壓力。
3、有些類如交易所的核心交易引擎,控制著交易流程,如果該類可以建立多個的話,系統完全亂了。(比如一個軍隊出現了多個司令員同時指揮,肯定會亂成一團),所以只有使用單例模式,才能保證核心交易伺服器獨立控制整個流程。
首先我們寫一個簡單的單例類:
- public class Singleton {
- /* 持有私有靜態例項,防止被引用,此處賦值為null,目的是實現延遲載入 */
- private static Singleton instance = null;
- /* 私有構造方法,防止被例項化 */
- private Singleton() {
- }
- /* 靜態工程方法,建立例項 */
- public static Singleton getInstance() {
- if (instance == null) {
- instance = new Singleton();
- }
- return instance;
- }
- /* 如果該物件被用於序列化,可以保證物件在序列化前後保持一致 */
- public Object readResolve() {
- return instance;
- }
- }
這個類可以滿足基本要求,但是,像這樣毫無執行緒安全保護的類,如果我們把它放入多執行緒的環境下,肯定就會出現問題了,如何解決?我們首先會想到對getInstance方法加synchronized關鍵字,如下:
- public static synchronized Singleton getInstance() {
- if (instance == null) {
- instance = new Singleton();
- }
- return instance;
- }
但是,synchronized關鍵字鎖住的是這個物件,這樣的用法,在效能上會有所下降,因為每次呼叫getInstance(),都要對物件上鎖,事實上,只有在第一次建立物件的時候需要加鎖,之後就不需要了,所以,這個地方需要改進。我們改成下面這個:
- public static Singleton getInstance() {
- if (instance == null) {
- synchronized (instance) {
- if (instance == null) {
- instance = new Singleton();
- }
- }
- }
- return instance;
- }
1、最簡單的實現
首先,能想到的最簡單的實現是,把類的建構函式寫成private的,從而保證別的類不能例項化此類。然後在類中返回一個靜態示例並返回給呼叫者。這樣,呼叫者就可以通過這個引用使用這個例項了。
public class Singleton{ private static final Singleton singleton = new Singleton(); public static Singleton getInstance(){ return singleton; } private Singleton(){ }}
如上例,外部使用者如果需要使用SingletonClass的例項,只能通過getInstance()方法,並且它的構造方法是private的,這樣就保證了只能有一個物件存在。