1. 程式人生 > >Java設計模式-單例模式、觀察者模式、工廠模式

Java設計模式-單例模式、觀察者模式、工廠模式

單例設計模式

概念:

全域性只有一個例項,自行例項化物件,自行向整個系統提供這個例項。

應用場景:
  • 需要全域性只有一個例項的時候,如儲存使用者資訊。
  • 只有一個訪問途徑
優點:
  • 全域性只有一個例項,避免了頻繁的建立例項,耗費的資源。
  • 提供了對唯一例項的受控訪問。
  • 允許改變數目的例項。
缺點:
  • 單例模式沒有抽象層,因此單例類擴充套件困難。
  • 單例職責過重。
  • 濫用單例可能造成其他問題,例如:持有上下文無法釋放造成記憶體洩漏;例項化的物件長期未被使用,被回收導致物件狀態丟失。
  • 單例實現的幾種方式

餓漢式

類載入的時候就開始載入,使用的是靜態變數,由JVM的classloader機制避免了執行緒安全問題,保證執行緒安全

缺點:一開始便載入佔用記憶體,沒有達到懶載入效果,如果例項化是耗費資源的,則懶載入可以節省載入時耗費的資源。另外如果例項一直沒有使用會佔用記憶體。

public class SingleTon{
    private static SingleTon single = new SingleTon();
    
    private SingleTon(){}
    
    public static SingleTon getInstanceO(){
        retrun single;
    }
}
餓漢式的另外方式

與正常的餓漢式並沒有太大的區別。

public class SingleTon{
    private SingleTon instance = null;
    static{
        instance = new SingleTon();
    }
    private SingleTon(){}
    public static SingleTon getInstance(){
        return this.instance;
    } 
}
懶漢式

延遲載入,在呼叫getInstance的時候才開始載入,無須一直佔用系統資源。從資源利用率的角度來講優於餓漢式。

缺點:執行緒不安全,當執行緒A判斷了是空的時候進行建立物件,在建立物件前執行緒B進來判斷到是空,也建立了物件,因此執行緒A和執行緒B的物件不一致。

public class SingleTon {
    private static SingleTon single;
    
    private SingleTon(){}
    
    public static SingleTon getInstance(){
        if(single == null){
            single = new SingleTon();
        }
        return single;
    }
}

//優化---增加鎖機制 1 ,在方法上加
public synchronize SingleTon getInstance(){
      if(single == null){
            single = new SingleTon();
        }
}
//缺點:鎖住了整個類,這個類中的其他成員變數也需要等待釋放鎖後被其他執行緒使用,效率低下。
//優化,雙重鎖校驗,缺點:可能會出現等待時間,降低系統性能。
public static SingleTon getInstance(){
    if(single == null){
        synchronize(SingleTon.class){
            if(single == null){
                single = new SingleTon();
            }
        }
    }
    return single;
}
靜態內部類

靜態內部類不是在一開始啟動的時候載入,而是第一次呼叫的使用載入,實現了懶載入,並且由JVM的classloader機制實現執行緒同步,保證執行緒安全

虛擬機器會保證一個類的構造器()方法在多執行緒環境中被正確地載入,同步,如果多個執行緒同時去初始化一個類,那麼只有一個執行緒去執行這個類的.

public class SingleTon{
    private SingleTon();
    
    private static class SingleTonHelper{
        private static final SingleTon single = new SingleTon();
    }
    
    public static SingleTon getInstance(){
        retrun SingleTonHelper.single;
    }
}

觀察者模式

概念:

實現一對多的依賴關係,當一方改變時,存在依賴關係的多方可以做出更改。

即釋出訂閱關係,釋出者釋出訊息,存在訂閱關係的訂閱者可以接收訊息。

包含的類
  • 抽象被觀察者介面:定義被觀察者需要實現的介面,如註冊觀察者建立關係;移除觀察者,通知所有觀察變化。
  • 抽象觀察者介面:定義接收到訊息後的更新方法。
  • 具體被觀察者:抽象被觀察者實現者,與觀察者建立關係,並通知觀察者的實現方法。
  • 具體觀察者:被通知物件,具體實現收到通知後做出更新。
定義被觀察者介面
public Interface IObservable{
    void registObserver(IObserver o);
    void removeObserver(IObserver o);
    void notifyObserver();
}
定義觀察者介面
public Interface IObserver{
    void update(Strign message);  //傳入的引數時任意想接收的訊息
}
具體被觀察者實現
public class MyObservable impelement IObservable{

	private String message ;//需要傳遞的訊息
	private List<IObserver> observers ;
	
	public MyObservable(){
        observers = new ArrayList<>();
	}
    
    @override
    public void registObserver(IObserver o){
        if(observers!=null){
            observers.add(o);
        }
    }
    
    @override
    public void removeObserver(IObserver o){
        if(observers!=null && observers.size()>0){
            observers.remove(o);
        }
    }
    
    @override
    public void notifyObserver(){
        for(int i=0 ;i<observers.size();i++){
            observers.get(i).update(message);
        }
    }
    
    //需要更新的訊息
    public void sendMsg(String msg){
        this.message = msg;
        //通知觀察者
        notifyObserver();
    }
}
具體觀察者
public class MyObserver impelement IObserver{
    @override 
    public void update(String message){
        System.out.println("接收到訊息,開始處理");
    }
}

工廠模式

概念:

集中建立產品的類,是呼叫者和具體建立例項類分離開來,實現解偶

簡單工廠模式

概念與步驟

又叫靜態工廠模式,通過工廠類根據型別建立不同的例項類。

優點:結構簡單,便於理解。客戶不用關心具體的類的建立過程。

缺點:程式碼邏輯較其他工廠模式複雜,新增產品時必須修改工廠類。當需要建立的類比較多時,工廠類會變的較為臃腫。

//需建立的例項類的共同點
public interface Car{
    void go();
}
//具體例項
public class Audi{
    @override
    public void go(){
        System.out.println("奧迪在跑");
    }
}
public class Baoma{
    @override
    public void go(){
        System.out.println("奧迪在跑");
    }
}
//工廠類
public class CarFactory{
    public static final int AUDI_TYPR = 1;
    public static final int BMW_TYPR = 2;
    
    public static Car createCar(int type){
        Car car = null;
        switch(type){
            case AUDI_TYPR:
            	car = new Audi();
            case BMW_TYPR:
            	car = new Baoma();
        }
        return car;
    }
}

工廠方法模式

概念與步驟

把工廠類抽象出去,建立例項由具體的工廠類實現,針對每一個產品都由自己的具體工廠類實現。

優點:

呼叫者無需關心產品的實現,只需要關心產品的介面。增加新的產品時,只要介面不變,不需要修改工廠類的邏輯,實現解偶。

缺點:

類比較多,如果需要建立多個產品的時候專案結構會比較大。

//抽象工廠介面
public interface IFactory{
    Car createCar();
}
//具體工廠類
public class AudiFactory impelement IFactory{
    @Override
    public Car createCar(){
        return new Audi();
    }
}

//抽象產品
public interface Car{
    void getName();
}
//具體的產品
public class Audi impelement Car{
    @Override
    public void getName(){
        System.out.println("get an audi");
    }
}

//新增產品時新增產品類及產品工廠類

抽象工廠模式

概念與步驟

具有關聯功能的產品作為一個產品族。 步驟:抽象工廠類,定於具體工廠類必須要實現的方法。

具體工廠類,建立一族產品;抽象產品類:定義產品的共性。具體產品類:建立具體的產品。

優點:具有工廠方法模式的優點外,另外可以在類內對產品族進行約束。

缺點:擴充套件比較麻煩。

試用場景:當建立的物件是一系列相互關聯或相互依賴的產品族時適用。

//抽象工廠類
public interface AbstractFactory {
    AbstractCar createCar();
    AbstractPlane createPlane();
}
//抽象產品類
 public abstract class AbstractCar {
     public abstract void getName();
}

public abstract class AbstractPlane {
    public abstract void getName();
}
//具體工廠類
public class BigFactory implements AbstractFactory{
    @Override
    public AbstractCar createCar() {
        return new BigCar();
    }
    @Override
    public AbstractPlane createPlane() {
        return new BigPlane();
    }
}
//具體產品類
public class BigCar extends AbstractCar {

    @Override
    public void getName() {
        System.out.print("抽象工廠-大車");
    }
}
class BigPlane extends AbstractPlane {
    @Override
    public void getName() {
        System.out.print("抽象工廠-大飛機");
    }
}

demo地址:https://github.com/MarinaTsang/demo