昨天講了六大原則,今天就進入設計模式的正題了。java
建立型設計模式,顧名思義就是與對象的建立相關。設計模式
定義:保證一個類僅有一個實例,並提供用於一個訪問它的全局訪問點。安全
(1) 餓漢模式ide
public class Singleton {
private static Singleton instance = new Singleton();
public static Singleton getInstance(){
return instance;
}
}
複製代碼
在類加載時就已經完成了初始化。 優勢:1. 保障了線程同步的問題;2. 獲取對象的效率高。 缺點:1. 下降了類加載時速度;2. 若是一直不使用,會內存的浪費。函數
(2) 懶漢模式學習
public class Singleton {
private static Singleton instance;
public static Singleton getInstance(){
if(instance == null) instance = new Singleton();
return instance;
}
}
複製代碼
缺點:存在線程同步問題 2. 線程安全ui
public class Singleton {
private static Singleton instance;
public static synchronized Singleton getInstance(){
if(instance == null) instance = new Singleton();
return instance;
}
}
複製代碼
缺點:每一次都須要同步,存在必定的開銷問題。this
懶漢模式相較於餓漢模式,不會存在不使用的問題。雖然再也不在加載時消耗資源,可是實例化時一樣會有必定的時間開銷。 (3) 雙重檢查模式/DCLspa
public class Singleton {
private volatile static Singleton instance;
public static Singleton getInstance(){
if(instance == null) {
synchronized (Singleton.class){
if(instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
複製代碼
使用volatile
關鍵詞是對正確性的一種保障。 相較於懶漢模式而言,這又是一種升級。由於不在將synchronized
套在了函數上,也就不會每次調用都對整個函數同步了,提升了資源的利用率。可是一樣存在失效的狀況。線程
失效案例
(4) 靜態內部類單例模式
public class Singleton {
public static Singleton getInstance() {
return SingletonHolder.instance;
}
private static class SingletonHolder {
private volatile static Singleton instance = new Singleton();
}
}
複製代碼
這是最經常使用的方法,也是對DCL
的一種升級。 優缺點和前面都差很少,就再也不復述了。 (5) 枚舉單例模式
public enum Singleton {
INSTANCE;
}
複製代碼
這是一種通常不經常使用的方法,可是可以保障線程同步。
定義:又稱靜態工廠模式,是由一個工廠對象決定建立出那一種產品類的實例。
既然是一個工廠就舉一個工廠的例子。 通常來講的工廠模式都是這樣的: 客戶 --> 工廠 --> 產品 因此產生了三個類
/** * 工廠類 */
public class Factory {
public static Product product(String type){
Product product = null;
switch (type){
case "雞翅":
product = new ChickenWing();
break;
case "漢堡":
product = new Hamburger();
break;
}
return product;
}
}
/** * 抽象產品類 */
public abstract class Product {
public abstract void finish();
}
/** * 具體產品類 */
public class Hamburger extends Product {
@Override
public void finish() {
System.out.println("漢堡製做完成");
}
}
public class ChickenWing extends Product {
@Override
public void finish() {
System.out.println("雞翅製做完成");
}
}
複製代碼
三個類已經完成了對應,就跟你在肯德基吃飯同樣,告訴他一個名字,他就開始生產。
優勢:根據參數得到實例,下降了耦合度。 缺點:不利於擴展功能,由於工廠從一開始就知道能加載的有什麼。 使用場景:(1) 工廠負責建立的對象較少;(2)客戶只須要知道想要什麼,不用關心怎麼生成的時候。
定義:定義一個用於建立對象的接口,讓子類決定實例化哪一個類。工廠方法將類的實例化放到子類中實現。
/** * 抽象工廠類 */
public abstract class Factory {
public abstract <T extends Product> T product(Class<T> clazz);
}
/** * 具體工廠類 */
public class KFC extends Factory {
@Override
public <T extends Product> T product(Class<T> clazz) {
Product product = null;
try{
product = (Product) Class.forName(clazz.getName()).newInstance();
}catch (Exception e){
e.printStackTrace();
}
return (T) product;
}
}
複製代碼
使用反射機制,也就解決了簡單工廠中分支可能存在增長的問題了。
講一個複雜對象的構建與它的表示分離,使一樣的構建過程能夠建立不一樣的表示。
四個角色:
Builder
只是說明要幹什麼事情。/** * 導演類 */
public class Director {
Builder builder;
Director(Builder builder){
this.builder = builder;
}
public Hamburger create(String meat, String vegetable, String bread){
builder.cookBread(bread);
builder.cookMeat(meat);
builder.cookVegetable(vegetable);
return builder.finish();
}
}
/** * Builder抽象類 */
public abstract class Builder {
public abstract void cookMeat(String meat);
public abstract void cookBread(String bread);
public abstract void cookVegetable(String vegetable);
public abstract Hamburger finish();
}
/** * Builder類 */
public class ChickenHamburgerBuilder extends Builder{
private Hamburger hamburger = new Hamburger();
@Override
public void cookMeat(String meat) {
hamburger.setMeat(meat);
}
@Override
public void cookBread(String bread) {
hamburger.setBread(bread);
}
@Override
public void cookVegetable(String vegetable) {
hamburger.setVegetable(vegetable);
}
@Override
public Hamburger finish() {
return hamburger;
}
}
/** * 產品類 */
public class Hamburger {
private String vegetable;
private String meat;
private String bread;
// 如下省略Getter 和 Setter方法
}
複製代碼
以上就是個人學習成果,若是有什麼我沒有思考到的地方或是文章內存在錯誤,歡迎與我分享。
相關文章推薦: