溫習設計模式

OO基礎:

  • 抽象
  • 封裝
  • 多態
  • 繼承

 

OO設計特性:

  • 可複用
  • 可擴充
  • 可維護


設計原則:

  • 封裝變化:把會變化的部分取出並“封裝”起來,好讓其他部分不會受到影響(找出應用中可能需要變化之處,把它們獨立出來,不要和那些不需要變化的代碼混在一起)
  • 針對接口編程,而不是針對實現編程
  • 多用組合,少用繼承
  • 爲了交互對象之間的鬆耦合設計而努力
  • 類應該對擴展開放,對修改封閉

 

設計模式:

  • 策略模式:定義了算法族,分別封裝起來,讓他們之前可以互相替換,此模式讓算法的變化獨立於使用算法的客戶
  • 觀察者模式:定義了對象之前的一對多依賴,這樣一來,對一個對象改變狀態時,它的所有依賴者都會收到通知並自動更新(java也內置了觀察者模式:參考java.util.Observer觀察者接口、被觀察者java.util.Observable接口)
  • 裝飾者模式:動態的將責任附加到對象上,若有擴展功能,裝飾者提供了比繼承更有彈性的替代方案(前提:裝飾者和被裝飾對象有相同的超類型)、(java中的io大量使用裝飾者模式:)
  • 簡單工廠模式:簡單工廠其實不是一個設計模式,反而更像一種編程習慣,定義一個生產工廠類,根據輸入類型生產對應的產品(利用靜態方法根據輸入參數生成對應的產品,隱藏了產品實例化的細節),但是當用戶需要新增產品ProductD時,必須在工廠類的生產方法中增加對應的判斷分支,所以簡單工廠模式違背了開放封閉原則
  • 工廠模式:定義了一個創建對象的接口,但由子類決定要實例化的類是哪一個,工廠方法讓類把實例化推遲到子類;符合開放封閉原則,但是由於每增加一個產品,都需要新增對應的生產工廠,導致增加額外的開發工作量
  • 抽象工廠模式:提供一個接口,用於創建相關或依賴對象的家族,而不需要明確指定具體類
  • 單例模式:一個類只有一個實例,並提供一個全局訪問點
  • 適配器模式:將一個類的接口,轉換成客戶期望的另一個接口。適配器讓原本接口不兼容的類可以合作無間

難理解的模式下面給了示例,讀者根據示例更容易理解一點

 

代碼示例:

簡單工廠模式:

簡單工廠模式:
首先定義一個產品類的共同接口:
public interface Product{
  //價格
  int price();
  //產品名
  String getName();
}
分別有三個產品ProductA、ProductB、ProductC ,均實現Product接口:
public class ProductA implements Product {
    @Override
    public int price() {
        return 100;
    }

    @Override
    public String getName() {
        return "ProductA";
    }
}
public class ProductB implements Product {
    @Override
    public int price() {
        return 200;
    }

    @Override
    public String getName() {
        return "ProductB";
    }
}
public class ProductC implements Product {
    @Override
    public int price() {
        return 300;
    }

    @Override
    public String getName() {
        return "ProductC";
    }
}
定義一個生產工廠類,根據輸入類型生產對應的產品:
public class Factory {
    public static Product createProduct(String type){
        Product product =null;
        switch (type){
            case "A":
                product = new ProductA();
                break;
            case "B":
                product = new ProductB();
                break;
            case "C":
                product = new ProductC();
                break;
        }
        return product;
    }
}

工廠模式:

首先聲明一個工廠接口,所有工廠必須實現這個接口:
public interface IFactory {
    Product createProduct();
}
生產ProductA的工廠FactoryA:
public class FactoryA implements IFactory {
    @Override
    public Product createProduct() {
        return new ProductA();
    }
}
生產ProductB的工廠FactoryB:
public class FactoryB implements IFactory {
    @Override
    public Product createProduct() {
        return new ProductB();
    }
}
現在來根據新的工廠方法模式來生產:
IFactory factoryA = new FactoryA();
Product productA = factoryA.createProduct();

IFactory factoryB = new FactoryB();
Product productB = factoryB.createProduct();

抽象工廠模式:

假設現在需要針對每種產品生產對應的贈品,難道我們要新增一個Gift的生產工廠嗎?其實沒有必要,因爲在這個場景下,每種產品必須附帶了贈品,所以我們可以利用原有的工廠來生產贈品
先定一個共同的Gift接口:
public interface Gift {
    String getGiftName();
}
增加GiftA、GiftB:
public class GiftA implements Gift {
    @Override
    public String getGiftName() {
        return "GiftA";
    }
}
修改Factory接口,增加生產Gift的方法:
public interface IFactory { 
    Product createProduct();
    Gift createGift();
}
修改工廠方法模式下的FactoryA、FactoryB、FactoryC:
public class FactoryA implements IFactory {
    @Override
    public Gift createGift() {
        return new GiftA();
    }
    @Override
    public Product createProduct() {
        return new ProductA();
    }
}
生產產品和贈品:
IFactory factoryA = new FactoryA();
Product productA = factoryA.createProduct();
Gift giftA = factoryA.createGift();

裝飾者模式:

以點餐爲例,我在麥*勞點餐可以根據我需求增加食物種類和數量
抽象構件角色:
public interface Food {
    String getDescription();
}
具體構件角色:
public class BasicSet implements Food{
    @Override
    public String getDescription() {
        return "漢堡 + 可樂";
    }
}
抽象裝飾類角色:
public abstract class Decorator implements Food {

    private Food food;

    public Decorator(Food food) {
        this.food = food;
    }

    @Override
    public String getDescription() {
        return this.food.getDescription();
    }
}
具體裝飾類角色:
public class FrenchFries extends Decorator {
    public FrenchFries(Food food) {
        super(food);
    }
    @Override
    public String getDescription() {
        return super.getDescription() + " + 薯條";
    }
}
public class FriedChicken extends Decorator {
    public FriedChicken(Food food) {
        super(food);
    }
    @Override
    public String getDescription() {
        return super.getDescription() + " + 炸雞";
    }
}
public class IceCream extends Decorator {
    public IceCream(Food food) {
        super(food);
    }
    @Override
    public String getDescription() {
        return super.getDescription() + " + 冰淇淋";
    }
}
測試類:
public class Test {
    public static void main(String[] args) {
        Food food = new BasicSet();
        Decorator setMealA = new FrenchFries(food);
        setMealA = new FrenchFries(setMealA);
        setMealA = new FriedChicken(setMealA);
        setMealA = new IceCream(setMealA);
        System.out.println("套餐A:" + setMealA.getDescription());
    }
}
輸出結果:
套餐A:漢堡 + 可樂 + 薯條 + 薯條 + 炸雞 + 冰淇淋

單例模式:

第一種(懶漢,線程不安全):這種寫法lazy loading很明顯,但是致命的是在多線程不能正常工作
public class Singleton {  
    private static Singleton instance;  
    private Singleton (){}  
  
    public static Singleton getInstance() {  
    if (instance == null) {  
        instance = new Singleton();  
    }  
    return instance;  
    }  
}  

第二種(懶漢,線程安全):這種寫法能夠在多線程中很好的工作,而且看起來它也具備很好的lazy loading,但是,遺憾的是,效率很低,99%情況下不需要同步
public class Singleton {  
    private static Singleton instance;  
    private Singleton (){}  
    public static synchronized Singleton getInstance() {  
    if (instance == null) {  
        instance = new Singleton();  
    }  
    return instance;  
    }  
}  

第三種(餓漢):
public class Singleton {  
    private static Singleton instance = new Singleton();  
    private Singleton (){}  
    public static Singleton getInstance() {  
       return instance;  
    }  
}  

第四種(餓漢,變種):
public class Singleton {  
    private Singleton instance = null;  
    static {  
       instance = new Singleton();  
    }  
    private Singleton (){}  
    public static Singleton getInstance() {  
       return this.instance;  
    }  
}  

第五種(靜態內部類):
public class Singleton {  
    private static class SingletonHolder {  
      private static final Singleton INSTANCE = new Singleton();  
    }  
    private Singleton (){}  
    public static final Singleton getInstance() {  
       return SingletonHolder.INSTANCE;  
    }  
} 
這種方式同樣利用了classloder的機制來保證初始化instance時只有一個線程,它跟第三種和第四種方式不同的是(很細微的差別):第三種和第四種方式是隻要Singleton類被裝載了,那麼instance就會被實例化(沒有達到lazy loading效果),而這種方式是Singleton類被裝載了,instance不一定被初始化。因爲SingletonHolder類沒有被主動使用,只有顯示通過調用getInstance方法時,纔會顯示裝載SingletonHolder類,從而實例化instance。想象一下,如果實例化instance很消耗資源,我想讓他延遲加載,另外一方面,我不希望在Singleton類加載時就實例化,因爲我不能確保Singleton類還可能在其他的地方被主動使用從而被加載,那麼這個時候實例化instance顯然是不合適的。這個時候,這種方式相比第三和第四種方式就顯得很合理


第六種(雙重校驗鎖):
public class Singleton {  
    private volatile static Singleton singleton;  
    private Singleton (){}  
    public static Singleton getSingleton() {  
    if (singleton == null) {  
        synchronized (Singleton.class) {  
          if (singleton == null) {  
            singleton = new Singleton();  
          }  
        }  
    }  
    return singleton;  
    }  
}  
爲什麼要加volatile關鍵字來修飾singleton對象?因爲new Singleton()這塊存在重排序的問題,可能導致單例非單例,加上volatile後能讓jvm限制指令重排序,這樣就沒有問題了

適配器模式:

目標角色(PowerTarget.java):
public interface PowerTarget {
    public int output5V();
}

適配者角色(PowerAdaptee.java):
public class PowerAdaptee {
    private int output =  220;
    public int output220V() {
        System.out.println("電源輸出電壓:" + output);
        return output;
    }
}

適配器角色(PowerAdapter.java):
public class PowerAdapter implements PowerTarget{
    private PowerAdaptee powerAdaptee;

    public PowerAdapter(PowerAdaptee powerAdaptee) {
        super();
        this.powerAdaptee = powerAdaptee;
    }

    @Override
    public int output5V() {
        int output = powerAdaptee.output220V();
        System.out.println("電源適配器開始工作,此時輸出電壓是:" + output);
        output = output/44;
        System.out.println("電源適配器工作完成,此時輸出電壓是:" + output);
        return output;
    } 
}

 

參考文章:

https://www.cnblogs.com/heliusKing/p/11577837.html

https://www.cnblogs.com/mingmingcome/p/9810731.html

 

 

 

 

 

 

 

發佈了142 篇原創文章 · 獲贊 345 · 訪問量 45萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章