設計模式 — 建立型模式

簡介

建立型模式,就是建立對象的模式,抽象了實例化的過程。它幫助一個系統獨立於如何建立、組合和表示它的那些對象。關注的是對象的建立,建立型模式將建立對象的過程進行了抽象,也能夠理解爲將建立對象的過程進行了封裝,做爲客戶程序僅僅須要去使用對象,而再也不關心建立對象過程當中的邏輯html

單例模式

定義:確保一個類只有一個實例,並且自行實例化並向整個系統提供這個實例。
類圖:java

clipboard.png

主要有三個部分:數據庫

私有的構造方法
指向本身實例的私有靜態引用
以本身實例爲返回值的靜態的公有的方法

特色:*
優勢:編程

在內存中只有一個對象,節省內存空間。
避免頻繁的建立銷燬對象,能夠提升性能。
避免對共享資源的多重佔用。
能夠全局訪問。

適用場景:安全

須要頻繁實例化而後銷燬的對象。
建立對象時耗時過多或者耗資源過多,但又常常用到的對象。
有狀態的工具類對象。
頻繁訪問數據庫或文件的對象等等。

注意事項:多線程

只能使用單例類提供的方法獲得單例對象,不要使用反射,不然將會實例化一個新對象。
不要作斷開單例類對象與類中靜態引用的危險操做。
多線程使用單例使用共享資源時,注意線程安全問題。

餓漢式:ide

/**
 * 一:餓漢式(類加載的時候就建立了實例)
 * 優勢:實現了線程安全,編寫簡單;執行效率高
 * 缺點:初始化就建立了實例,對加載速度和內存有消耗,,因此這種方法要求單例對象初始化速度快且佔用內存小
 */
// 一、成員變量靜態化
private static Singleton3 instance = new Singleton3();
//二、構造函數私有化,防止外部實例化
private Singleton3(){}
//三、提供公共靜態建立實例方法
public static Singleton3 getInstance(){
    return instance;
}

 /**
 * 二:枚舉類型:根據枚舉類型的特色,實現單例模式所須要的建立單例、線程安全、簡潔的需求
 * 優勢:實現比較簡潔,保證了單實例,線程安全
 * 缺點:使用枚舉類型,不是很熟悉
 */

/**
 * 枚舉類型的特色:
 * 一、枚舉類型 = 不可被繼承的類(final):
 *      枚舉本質上是經過普通類實現的,只是編譯器爲咱們進行了特殊處理
 *      每一個枚舉類型都繼承自java.lang.Enum,並自動添加了values(),valueOf()
 *      枚舉類的實例 = 常量
 * 二、每一個枚舉元素 = 類靜態常量 = 1個實例
 *      枚舉元素,都是經過靜態代碼來進行初始化,即在類加載期間進行初始化,保證了實例只被建立一次,線程安全
 *      獲取枚舉元素 = 獲取實例
 * 三、構造方法 訪問權限 默認=私有(private):他的構造器是私有的,底層沒有可供調用的無參數的構造器;防止了其餘人建立實例
 * 四、每個枚舉類型&枚舉變量在JVM中都是惟一的:
 *      即java在序列化和反序列化美劇時作了特殊的規定:枚舉的writeObject(),readObject(),readObjectNoData()等方法是被禁用的,所以不存在序列化接口以後調用readObject會破環單例的問題
 *      保證了枚舉元素的不可變行,即不能經過克隆、序列化&反序列化來複制枚舉,即保證了1個枚舉常量=1個實例 即單例
 */


public enum Singleton {
    INSTANCE;
    public void whateverMethod() {
    }
}

懶漢式:函數

//程序中建立類只有兩種方式:1建立類的一個對象,用該對象去調用類中的方法;2使用類名直接調用類中方法,類名.方法名();單例模式防止外部new對象,只能使用類方法,且是靜態的。

/**
 * 一:懶漢式(須要的時候建立實例),線程不安全。當多個線程同時訪問時,不能正常工做。
 * 優勢:按需加載
 * 缺點:線程不安全。多個線程同時訪問時,會建立多個實例。
 */
// 一、成員變量靜態化
private static Singleton1 instance;
//二、構造函數私有化,防止外部實例化
private Singleton1(){}
//三、提供公共靜態建立實例方法
public static Singleton1 getInstance() {
    if (instance == null) {
        instance = new Singleton1();
    }
    return instance;
}
/**
 * 二:懶漢式:線程安全,加同步鎖,
 * 優勢:實現了線程安全
 * 缺點:每次訪問都要進行線程同步(調用synchronized鎖),形成過多的同步開銷(加鎖=耗時、耗能)
 */

// 一、成員變量靜態化
private static Singleton1 instance;
//二、構造函數私有化,防止外部實例化
private Singleton1(){}
//三、提供公共靜態建立實例方法
public static synchronized Singleton1 getInstance() {
    if (instance == null) {
        instance = new Singleton1();
    }
    return instance;
}

// 一、成員變量靜態化
private static Singleton1 instance;
//二、構造函數私有化,防止外部實例化
private Singleton1(){}
//三、提供公共靜態建立實例方法
public static Singleton1 getInstance() {
    synchronized(Singleton.class){
        if (instance == null) {
            instance = new Singleton1();
        }
    }
    return instance;
}


/**
 *三:懶漢式改進—雙重校驗鎖;在同步鎖的基礎上,添加一層if判斷,若單例已經建立,則不須要再執行加鎖操做就能夠獲取實例,從而提升了性能。
 *優勢:避免了每次調用都要調用synchronized鎖,同時雙重校驗又保證了線程安全,不會重複建立實例。
 * 缺點:較爲複雜,容易出錯
 */

// 一、成員變量靜態化
private static Singleton1 instance = null;
//二、構造函數私有化,防止外部實例化
private Singleton1(){}
//三、提供公共靜態建立實例方法

public static Singleton1 getInstance() {
    if (instance == null) {
        synchronized (Singleton1.class) {
            if (instance == null) {
                instance = new Singleton1();
            }
        }
    }
    return instance;
}

/**
 * 四:靜態內部類。在靜態內部類中建立單例,在加載內部類時纔會建立單例
 * 優勢:根據靜態內部類的特性,實現了線程安全,按需加載,同時比較簡潔
 */
// 一、建立靜態內部類
private static class Singleton2{
    // 靜態類裏面建立單例
    private static Singleton1 instance = new Singleton1();
}

//二、構造函數私有化,防止外部實例化
private Singleton1(){}

//三、提供公共靜態建立實例方法
public static Singleton1 getInstance() {
    //調用靜態類的實例方法
    return Singleton2.instance;
}
/**
 * 調用過程說明
 * 一、外部調用類的getInstance()方法
 * 二、getInstance()方法自動調用內部類的方法,實現初始化
 * 三、而該類在裝載 & 被初始化時,會初始化他的靜態域,從而建立單例
 * 四、因爲是靜態域,所以JVM只會加載一遍,java虛擬機保證了線程安全
 * 五、最終實現只建立一個實例。
 */

簡單工廠模式

定義:又靜態工廠模式,能夠根據參數的不一樣返回不一樣類的實例。
類圖:工具

clipboard.png

由此能夠看出:簡單工廠模式由三部分組成:具體工廠、具體產品和抽象產品性能

工廠類(Creator)角色:擔任這個角色的是簡單工廠模式的核心,含有與應用緊密相關的商業邏輯。工廠類在客戶端的直接調用下建立產品對象,它每每由一個具體Java類實現。

抽象產品(AbstractProduct)角色:擔任這個角色的類是由簡單工廠模式所建立的對象的父類,或它們共同擁有的接口。抽象產品角色能夠用一個Java接口或者Java抽象類實現。

具體產品(ConcreteProduct)角色:簡單工廠模式所建立的任何對象都是這個角色的實例,具體產品角色由一個具體Java類實現。

總結:

簡單工廠只有一個工廠類,經過switch語句來區分建立哪一個產品。
工廠方法模式是擴展了簡單工廠模式,區分爲抽象工廠和具體工廠實現。

工廠方法模式

定義:定義一個建立對象的工廠接口,讓子類決定實例化哪個類,將實際的建立工做推遲到子類當中。

類圖:

clipboard.png

工廠方法模式包含

抽象產品:通常是產品接口或者抽象產品類。主要目的是定義產品的規範,全部的產品實現都必須遵循產品接口定義的規範。產品接口是調用者最爲關心的,產品接口定義的優劣直接決定了調用者代碼的穩定性。
具體產品:實現產品接口的具體類,決定了產品在客戶端中的具體行爲。
抽象工廠:通常是工廠接口或者抽象工廠類。是工廠方法模式的核心,與調用者直接交互用來提供產品。
具體工廠:在編程中,工廠實現決定如何實例化產品,是實現擴展的途徑,須要有多少種產品,就須要有多少個具體的工廠實現。

優缺點:

優勢:(1)封裝了建立產品的方法,用戶無須關心具體實現;(2)添加新產品時,只須要添加具體產品類和具體工廠類(實現或繼承抽象產品、工廠類);(3)將建立工廠方法推遲到子類當中,實現了多態。工廠方法模式也叫多態工廠模式,之因此是多態,由於全部具體工廠類都具備同一父類。
缺點:(1)在添加新產品時,須要添加具體產品類、具體工廠類。當存在較多產品時,致使產品、產品工廠類增多,必定程度上增長了系統的複雜度,更多的類須要編譯和運行,給系統帶來了一些額外的開銷。(2) 因爲考慮到系統的可擴展性,須要引入抽象層,在客戶端代碼中均使用抽象層進行定義,增長了系統的抽象性和理解難度,且在實現時可能須要用到DOM、反射等技術,增長了系統的實現難度。

代碼舉例

//一、抽象產品類
public interface Moveable {
    public void run();
}
//二、具體產品實現類
public class Car implements Moveable {
    @Override
    public void run() {
        System.out.println("小汽車!");
    }
}
public class Plane implements Moveable {
    @Override
    public void run() {
        System.out.println("大飛機!");
    }
}
//三、抽象工廠類
public abstract  class Factory {
    public abstract Moveable create();
}
//四、具體工廠實現類
public class CarFactory extends Factory {
    @Override
   public Moveable create() {
        return new Car();
    }
}
public class PlaneFactory extends Factory {
    @Override
    public Moveable create() {
        return new Plane();
    }
}
//測試類
public class FactoryTest {
    @Test
    public  void FactoryTest(){
        Factory car = new CarFactory();
        Moveable m = car.create();
//        Factory plane = new PlaneFactory();
//        Moveable m= plane.create();
        m.run();
    }
}

抽象工廠模式

定義:提供一個建立一系列相關或相互依賴對象的接口,而無需指定它們具體的類。

類圖:

clipboard.png

能夠看到,抽象工廠模式也是包含抽象產品、具體產品、抽象工廠、具體工廠。
可是抽象工廠中有產品等級結構和產品族的概念。

產品等級結構:產品等級結構即產品的繼承結構,如一個抽象類是電視機,其子類有海爾電視機、海信電視機、TCL電視機,則抽象電視機與具體品牌的電視機之間構成了一個產品等級結構,抽象電視機是父類,而具體品牌的電視機是其子類。
產品族:在抽象工廠模式中,產品族是指由同一個工廠生產的,位於不一樣產品等級結構中的一組產品,如海爾電器工廠生產的海爾電視機、海爾電冰箱,海爾電視機位於電視機產品等級結構中,海爾電冰箱位於電冰箱產品等級結構中。

和工廠方法模式的區別:
工廠方法模式提供的是一個產品等級結構的實現,抽象工廠模式提供多個不一樣的產品等級結構的實現。

優缺點:

優勢:能夠在類的內部對產品族進行約束
缺點:產品族擴展比較麻煩。當增長新的產品時,全部的工廠類都要添加其相關代碼。

代碼舉例:

//一、抽象產品類
public abstract class Vehicle{
    public abstract void run();
}

public abstract class Food {
    public abstract void printName();
}

public abstract class Weapon {
    public abstract void shoot();
}
//二、具體實現類
//第一個產品族
public class Car extends Vehicle {
    @Override
    public void run() {
        System.out.println("小汽車!");
    }
}
public class Apple extends Food{
    @Override
    public void printName() {
        System.out.println("紅蘋果");
    }
}
public class AK47 extends Weapon {
    @Override
    public void shoot() {
        System.out.println("大火球,huhuhu。。。。。。");
    }
}
//第2個產品族
public class Plane extends Vehicle {
    @Override
    public void run() {
        System.out.println("大灰機");
    }
}
public class Pizza  extends Food{
    @Override
    public void printName() {
        System.out.println("披薩");
    }
}
public class _98K extends Weapon{
    @Override
    public void shoot() {
        System.out.println("砰砰砰。。。。。。");
    }
}
//三、抽象工廠類
public  abstract class AbstractFactory {

    public abstract Vehicle createVehicle();
    public  abstract  Weapon createWeapon();
    public abstract Food createFood();
}
//四、具體工廠實現類
public class DefaultFactory extends AbstractFactory{

    @Override
    public Vehicle createVehicle() {
        return new Car();
    }

    @Override
    public Weapon createWeapon() {
        return new AK47();
    }

    @Override
    public Food createFood() {
        return new Apple();
    }
}

public class SuperFactory extends AbstractFactory{

    @Override
    public Vehicle createVehicle() {
        return new Plane();
    }

    @Override
    public Weapon createWeapon() {
        return new _98K();
    }

    @Override
    public Food createFood() {
        return new Pizza();
    }
}
//五、測試類
public class AbstractFactoryTest {
    @Test
    public void abstractFactoryTest(){
//        AbstractFactory a = new DefaultFactory();
        AbstractFactory a = new SuperFactory();
        Vehicle v= a.createVehicle();
        v.run();
        Weapon w = a.createWeapon();
        w.shoot();
        Food f= a.createFood();
        f.printName();
    }

}

總結:

建造者模式

定義:將一個複雜對象的構建與它的表示分離,使得一樣的構建過程能夠建立不一樣的表示。

類圖:

clipboard.png

建造者模式包含四個要素:

產品類:通常是一個較爲複雜的對象,也就是說建立對象的過程比較複雜,通常會有比較多的代碼量。在本類圖中,產品類是一個具體的類,而非抽象類。實際編程中,產品類能夠是由一個抽象類與它的不一樣實現組成,也能夠是由多個抽象類與他們的實現組成。
抽象建造者:引入抽象建造者的目的,是爲了將建造的具體過程交與它的子類來實現。這樣更容易擴展。通常至少會有兩個抽象方法,一個用來建造產品,一個是用來返回產品。
建造者:實現抽象類的全部未實現的方法,具體來講通常是兩項任務:組建產品;返回組建好的產品。
導演類:負責調用適當的建造者來組建產品,導演類通常不與產品類發生依賴關係,與導演類直接交互的是建造者類。通常來講,導演類被用來封裝程序中易變的部分。

優缺點:
優勢:

將具體的業務邏輯實現封裝在了導演類中,無須知道具體產品類的結構;
當添加新的產品時,只須要實現一個新的建造者類,並添加相應的導演類實現建立具體的產品。

代碼實現:

class Product {
        private String name;
        private String type;
        public void showProduct(){
            System.out.println("名稱:"+name);
            System.out.println("型號:"+type);
        }
        public void setName(String name) {
            this.name = name;
        }
        public void setType(String type) {
            this.type = type;
        }
    }

    abstract class Builder {
        public abstract void setPart(String arg1, String arg2);
        public abstract Product getProduct();
    }
    class ConcreteBuilder extends Builder {
        private Product product = new Product();

        public Product getProduct() {
            return product;
        }

        public void setPart(String arg1, String arg2) {
            product.setName(arg1);
            product.setType(arg2);
        }
    }

    public class Director {
        private Builder builder = new ConcreteBuilder();
        public Product getAProduct(){
            builder.setPart("寶馬汽車","X7");
            return builder.getProduct();
        }
        public Product getBProduct(){
            builder.setPart("奧迪汽車","Q5");
            return builder.getProduct();
        }
    }
    public class Client {
        public static void main(String[] args){
            Director director = new Director();
            Product product1 = director.getAProduct();
            product1.showProduct();

            Product product2 = director.getBProduct();
            product2.showProduct();
        }
    }

與工廠模式的區別:
從結構上看,建造者模式只比工廠模式多了一個「導演類」的角色,若是沒有這個導演類,就相似簡單工廠模式了。
工廠模式是將對象的建立過程封裝在工廠類中,由工廠類向客戶端提供最終的產品。
建造者模式中,建造類通常只提供產品類中各個組件的建造,而將具體的建造過程交由導演類,由導演類實現具體的產品。
因此建造者模式通常用來建立更復雜的對象。

原型模式

待續。

參考資料

http://design-patterns.readth...
https://www.w3cschool.cn/java...

相關文章
相關標籤/搜索