1. 程式人生 > 其它 >設計模式詳解——單例、工廠、抽象工廠

設計模式詳解——單例、工廠、抽象工廠

tags: [#設計模式]

從今天開始,我們逐一看下常用的設計模式,希望能夠儘可能搞清楚它們的應用場景,以便我們能夠寫出更優秀的程式碼。

1、單例模式

核心要點

  • 構造方法私有
  • 構造由static修飾的、返回例項的方法

優勢

  • 減少建立Java例項所帶來的系統開銷
  • 便於系統跟蹤單個Java例項的宣告週期、例項狀態等

示例程式碼

package singleton;

public class Singleton {
    private static Singleton instance;
    private Singleton() {}
    public static Singleton getInstance() {
        if(instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}

場景

執行緒池(threadpool)、快取(cache)、日誌物件

2、簡單工廠模式

要點

  • 通過工廠類的形式進行解耦合
  • 依賴關係通過介面解耦合

優缺點

  • 讓物件的呼叫者和物件建立過程分離,當物件呼叫者需要物件時,直接向工廠請求即可;
  • 避免了物件的呼叫者和物件的實現類以硬解碼方式耦合,提高了系統的可維護性、拓展性;
  • 需要注意的一個陷阱是:當產品修改時,工廠類也要做相應的修改;

示例程式碼

這裡的computer依賴了Printer類,但是如果直接寫Printer的話,會直接影響當前類的擴充套件,比如我們後期增加了WriterWriterPrinter只是方法不一致,這時候如果用簡單工廠模式,就可以完美解決這個問題。

當然,這時依然需要修改OutputFactory的程式碼,但是對Computer是不需要修改的。

public class Computer {
    private Output out;
    public Computer(Output out) {
        this.out = out;
    }
    
    public void keyIn(String msg) {
        out.getData(msg);
    }
    
    public void print() {
        out.out();
    }
}

簡單工廠

package simplefactory;

public class OutputFactory {
    public Output getOutput() {
        return new Printer();
    }
}

介面

package simplefactory;

public interface Output {
    final int MAX_CACHE_LINE=200;
    void getData(String msg);
    void out();
}

介面實現類

package simplefactory;

public class Printer implements Output {
    private String[] printData = new String[MAX_CACHE_LINE];
    private int dataNum = 0;

    @Override
    public void getData(String msg) {
        if(dataNum >= MAX_CACHE_LINE) {
            System.out.println("輸出佇列已滿,新增失敗");
        } else {
            printData[dataNum++] = msg;
        }
        
    }

    @Override
    public void out() {
        while(dataNum > 0) {
            System.out.println("印表機列印:" + printData[0]);
            System.arraycopy(printData, 1, printData, 0, --dataNum);
        }
        
    }

}

測試類

package simplefactory;

public class Test {
    public static void main(String[] args) {
        OutputFactory of = new OutputFactory();
        Computer c = new Computer(of.getOutput());
        c.keyIn("hello world");
        c.keyIn("java");
        c.keyIn("spring");
        c.print();
    }
}

3、工廠方法和抽象工廠

要點

  • 和簡單工廠相比,工廠方法多了一個介面,也就是工廠介面,Ouput子類的工廠類均繼承該介面,實現getOutput()方法
  • 當使用工廠方法設計模式時,物件呼叫者需要與具體的工廠類進行耦合:當需要不同物件時,程式需要呼叫相應工廠物件的方法來得到所需的物件
  • 對於採用工廠方法的設計架構,客戶端程式碼成功與被呼叫物件實現了分離,但帶來了另一種耦合:客戶端程式碼與不同的工廠類耦合
  • 為了解決上面的耦合,增加一個工廠類,用於建立不同的工廠物件,這個特殊的工廠類被稱為抽象工廠類,這種設計模式被稱為抽象工廠模式

比較

和簡單工廠相比,抽象工廠降低了目標例項與例項工廠的耦合性,但是它又引入了抽象工廠的耦合關係。

在簡單工廠模式中,要建立一個物件的例項,直接呼叫該物件的工廠方法即可,當然前提條件是增加該物件時要同步增加它的工廠方法;

在抽象工廠模式中,不僅對例項物件做了抽象處理,還對物件的工廠做了抽象處理,所以在例項化一個物件的時候,要先例項化它的工廠,然後再通過工廠方法例項化物件(實線表示程式碼實際執行流程,虛線表示解耦過程,工廠的工廠創建出來的是抽象工廠的例項,抽象工廠最終建立的是物件的抽象介面)

示例程式碼

例項工廠介面:

// 工廠介面
package abstractfactory;

import simplefactory.Output;
/**
 * 
 *TODO output工廠介面
 *
 * @author CaoLei 2018年7月1日下午3:19:36
 * OutputFactory
 */
public interface OutputFactory {
    
    Output getOutput();

}

例項工廠實現:

// 工廠方法,工廠類

package abstractfactory;

import simplefactory.BetterPrinter;
import simplefactory.Output;

public class BetterPrinterFactory implements OutputFactory {

    @Override
    public Output getOutput() {
        return new BetterPrinter();
    }

}

例項工廠例項化方法:

// 抽象工廠,抽象工廠類
package abstractfactory;

public class OutputFactoryFactory {
    public static OutputFactory getOutputFactory(String type) {
        if ("better".equals(type)) {
            return new BetterPrinterFactory();
        } else {
            return new PrinterFactory();
        }

    }
}

好了,今天就先說這三種設計模式,明天我們來繼續看其他的設計模式。