設(shè)計(jì)模式

模型圖

用例圖

  • 用例建模最主要的功能是表達(dá)系統(tǒng)的功能性需求或行為
  • 參互者: 參與者指的是與系統(tǒng)交互的角色咏删,可以是人,也可以是事物或其他系統(tǒng)
  • 用例是系統(tǒng)為參與者提供的功能募逞,用戶名稱一般是一個(gè)帶動(dòng)作性的詞語
2.jpg

用例描述

項(xiàng)目 內(nèi)容
用例名稱 登錄
用例ID login
角色 用戶
用例說明 描述用戶的登錄過程
前置條件 打開網(wǎng)站頁面
基本事件流 1. 點(diǎn)擊登錄 2.輸入用戶名和密碼 3. 點(diǎn)擊登錄 4.服務(wù)器會(huì)使用會(huì)話登錄保存用戶登錄狀態(tài)
其它事件流 1. 用戶名為空提示用戶名不能為空 2. 密碼為空提示密碼不能為空
異常事件流 登錄超時(shí)則返回登錄頁
后置條件 登錄成功弓摘,進(jìn)入個(gè)人中心

類圖

  • 類圖描述類的靜態(tài)結(jié)構(gòu),定義類以及描述類之間的聯(lián)系腕够,如關(guān)聯(lián),依賴舌劳,聚合等帚湘,還包括類的內(nèi)部結(jié)構(gòu)(類的屬性和操作)
  • 類圖是一種靜態(tài)模型類型,一個(gè)類圖根據(jù)結(jié)構(gòu)系統(tǒng)中的類以及各個(gè)類之間的關(guān)系描述系統(tǒng)的靜態(tài)結(jié)構(gòu)
  • 類圖包含7個(gè)元素
    • 接口
    • 協(xié)作
    • 泛化關(guān)系
    • 依賴關(guān)系
    • 關(guān)聯(lián)關(guān)系
    • 實(shí)現(xiàn)關(guān)系
  • 在UML中甚淡,類用矩形來表示大诸,分為3個(gè)部分,名稱部分贯卦,屬性部分和操作部分

依賴關(guān)系

只要在類中使用了對(duì)方资柔,那么它們之間就存在依賴關(guān)系,如果沒有對(duì)方撵割,連編譯都通過不了


3.jpg

泛化關(guān)系

泛化關(guān)系實(shí)際上就是繼承關(guān)系贿堰,它就是依賴關(guān)系的特例

4.jpg

實(shí)現(xiàn)關(guān)系

實(shí)現(xiàn)關(guān)系實(shí)際上就是A類實(shí)現(xiàn)B類(接口),他就是依賴關(guān)系的特例


5.jpg

關(guān)聯(lián)關(guān)系

  • 關(guān)聯(lián)關(guān)系實(shí)際上就是類與類之間的聯(lián)系啡彬,它是依賴關(guān)系的特例
  • 關(guān)聯(lián)關(guān)系比依賴的關(guān)系更強(qiáng)
  • 關(guān)聯(lián)具有導(dǎo)航性羹与。即雙向關(guān)系或單向關(guān)系故硅,表示關(guān)系在哪一方維護(hù)
  • 關(guān)聯(lián)具有多重性,如
    • 1 表示有且僅有一個(gè)
    • 0... 表示0或者多個(gè)
    • 0,1 表示0或者1個(gè)
    • n,m 表示n到m個(gè)都可以
    • m... 表示至少m個(gè)
6.jpg

聚合關(guān)系

  • 聚合關(guān)系表示的是整體和部分的關(guān)系纵搁,整體與部分可以分開
  • 聚合關(guān)系是關(guān)聯(lián)關(guān)系的特例吃衅,所以它具有關(guān)聯(lián)的導(dǎo)向性和多重性
  • 聚合的雙方聲明周期是獨(dú)立的


    7.jpg

組合關(guān)系

  • 也是整體和部分的關(guān)系,但是整體和部分不可分開
  • 整體和部分生命周期一致
8.jpg

對(duì)象圖(不常用)

  • 對(duì)象圖描述一組對(duì)象和它們之間的關(guān)系诡渴,它是系統(tǒng)狀態(tài)的某一時(shí)刻的快照捐晶,它的使用相當(dāng)有限,它主要用于了解系統(tǒng)在某個(gè)特定時(shí)刻的具體情況和數(shù)據(jù)結(jié)構(gòu)
  • 對(duì)象圖表示方法和類圖大致相同妄辩,對(duì)象圖中的對(duì)象屬性可以有具體值惑灵,類圖中的一個(gè)類可以對(duì)應(yīng)成對(duì)象圖中的多個(gè)對(duì)象,例如:部門類的自關(guān)聯(lián)就可以對(duì)應(yīng)成多個(gè)部門之間的關(guān)聯(lián)


    1.png

活動(dòng)圖

  • 在UML里眼耀,活動(dòng)圖本質(zhì)上就是流程圖
  • 它描述系統(tǒng)的活動(dòng)英支,判斷系統(tǒng)的活動(dòng),判斷點(diǎn)和分支等
四角圓滑的矩形---終端框(起止框)
矩形----處理框(執(zhí)行框)
普通的平行四邊形---輸入\輸出框
菱形---判斷框
2.png
image.png

時(shí)序圖

  • 時(shí)序圖強(qiáng)調(diào)消息時(shí)間順序的交互圖
  • 時(shí)序圖描述類系統(tǒng)中類與類之間的交互哮伟,它將這些交互建模換成消息交換
  • 時(shí)序圖用于描述對(duì)象之間如何隨著時(shí)間進(jìn)行協(xié)作
  • 時(shí)序圖由活動(dòng)者干花、對(duì)象、消息楞黄、生命線和控制焦點(diǎn)組成
  • 不同元素由不同表示
    • 對(duì)象是一個(gè)矩形池凄,對(duì)象名稱下由下劃線
    • 消息用有方向的箭頭表示,調(diào)用是實(shí)線鬼廓,返回消息是虛線
    • 生命線由縱向的虛線表示
    • 控制焦點(diǎn)是縱向的矩形肿仑,也就是活動(dòng)條


      3.png

協(xié)作圖

時(shí)序圖可一鍵轉(zhuǎn)換成協(xié)作圖

  • 協(xié)作圖是時(shí)序圖的一種變種
  • 協(xié)作圖強(qiáng)調(diào)的是發(fā)送和接受消息的對(duì)象之間的組織結(jié)構(gòu)
  • 協(xié)作圖顯示了一系列對(duì)象和在這些對(duì)象之前的聯(lián)系以及對(duì)象間發(fā)送和接受的消息
  • 時(shí)序圖主要側(cè)重于對(duì)象間消息傳遞在時(shí)間上的先后關(guān)系,而協(xié)作圖則側(cè)重與對(duì)象以及對(duì)象和角色交互的靜態(tài)關(guān)系


    4.png

組件圖

  • 組件圖用例建立系統(tǒng)的各個(gè)組件之間的關(guān)系碎税,它們是通過軟件或者文檔組織在一起尤慰,使用組件圖可以幫助讀者了解某個(gè)功能位于軟件包中的哪一個(gè)位置,以及各個(gè)版本組件包含哪些功能
  • 組件圖可以用來幫助設(shè)計(jì)系統(tǒng)的整體架構(gòu)
5.png

部署圖

  • 部署圖是來幫助讀者了解軟件中的各個(gè)組件運(yùn)行硬件什么位置雷蹂,以及這些硬件之間的交互關(guān)系
  • 節(jié)點(diǎn):用來表示一種硬件伟端,它可以是服務(wù)器,計(jì)算機(jī)等匪煌。節(jié)點(diǎn)的符號(hào)是一個(gè)三位盒子责蝠,在左上角包含節(jié)點(diǎn)的名稱
  • 通信關(guān)聯(lián):節(jié)點(diǎn)通過通信關(guān)聯(lián)建立彼此的關(guān)系,采用從節(jié)點(diǎn)到節(jié)點(diǎn)繪制實(shí)現(xiàn)來表示關(guān)聯(lián)
6.png

設(shè)計(jì)原則

SOLID五大設(shè)計(jì)原則

首字母 指代 概念
S 單一職責(zé)原則 單一功能原則認(rèn)為對(duì)象應(yīng)該僅具有一種單一功能的概念
O 開放封閉原則 開閉原則認(rèn)為 軟件應(yīng)該是對(duì)于擴(kuò)展開放的虐杯,但是對(duì)于修改關(guān)閉的概念
L 里氏替換原則 里氏替換原則認(rèn)為程序中的對(duì)象應(yīng)該是可以在不改變程序正確性的前提下玛歌,被子類所替代的 的概念
I 接口隔離原則 接口隔離原則認(rèn)為 多個(gè)特定客戶端接口要好于一個(gè)寬泛用途的接口的概念
D 依賴反轉(zhuǎn)原則 依賴反轉(zhuǎn)原則認(rèn)為一個(gè)方法應(yīng)該遵從依賴與抽象而不是一個(gè)實(shí)例的概念,依賴注入是該原則的一種實(shí)現(xiàn)方式

開放封閉原則

  • 對(duì)擴(kuò)展開放擎椰,對(duì)修改關(guān)閉
  • 增加需求時(shí),擴(kuò)展新代碼创肥,而非修改已有的代碼
  • 開閉原則是設(shè)計(jì)模式的總原則
  • 對(duì)近期可能會(huì)變化并且如果有變化但改動(dòng)量巨大的地方要增加擴(kuò)展點(diǎn)达舒,擴(kuò)展點(diǎn)過多會(huì)降低可讀性
/**
 * 開閉原則-失敗案例值朋,每次新增客戶類型都修改
 */
class Customer {
    constructor(public rank:string) {
        
    }
}

class Product {
    constructor(public name:string,public price:number) {
        
    }
    cost(customer:Customer){
        switch (customer.rank) {
            case 'member':
                return this.price*.8;
            case 'vip':
                return this.price*.6;
            default:
                return this.price;
        }
    }
}

let product=new Product('筆記本電腦',1000);
let c1=new Customer('member');
let c2=new Customer('guest');

console.log(product.cost(c1));
console.log(product.cost(c2));
/**
 * 開閉原則
 */
export {}

class Customer {
    constructor(public rank:string,public discount:number=1) {}
}

class Product {
    constructor(public name:string,public price:number) {
        
    }
    cost(customer:Customer){
        return this.price*customer.discount;
    }
}

let product=new Product('筆記本電腦',1000);
let c1=new Customer('member',0.8);
let c2=new Customer('guest');

console.log(product.cost(c1));
console.log(product.cost(c2));

單一職責(zé)原則

  • 一個(gè)類或者模塊只負(fù)責(zé)完成一個(gè)職責(zé),如果功能特別復(fù)雜就進(jìn)行拆分
  • 單一職責(zé)可以降低類的復(fù)雜性巩搏,提高代碼可讀性昨登,可維護(hù)性
  • 當(dāng)類的代碼行數(shù)過多,方法過多贯底,功能太多丰辣,職責(zé)太雜的時(shí)候就要對(duì)類進(jìn)行拆分了
  • 拆分不能過去,如果拆分過度會(huì)損失內(nèi)聚性和維護(hù)性

里氏替換原則

  • 所有引用基類的地方必須能透明的使用其子類的對(duì)象
  • 子類能替換掉父類禽捆,使用者可能根本不需要知道是父類還是子類笙什,反之則不行
  • 里氏替換原則是開閉原則的實(shí)現(xiàn)基礎(chǔ),程序設(shè)計(jì)的時(shí)候盡量使用基類定義及引用胚想,運(yùn)行時(shí)再?zèng)Q定使用哪個(gè)子類
  • 里氏替換原則可以提高代碼的復(fù)用性琐凭,提高代碼的可擴(kuò)展性,也增加了耦合性
  • 相對(duì)于多態(tài)浊服,這個(gè)原則是講的是類如何設(shè)計(jì)统屈,子類如果違反了父類的功能則表示違反了里氏替換原則

依賴倒置原則

  • 面向接口編程,依賴于抽象而不依賴于具體實(shí)現(xiàn)
  • 要求我們?cè)诔绦虼a中傳遞參數(shù)或者再關(guān)聯(lián)關(guān)系中牙躺,盡量引用層級(jí)高得抽象層類
  • 使用方只關(guān)注接口而不關(guān)注具體類得實(shí)現(xiàn)

接口隔離原則

  • 保持接口得單一獨(dú)立愁憔,避免出現(xiàn)胖接口
  • 客戶端不應(yīng)該依賴它不需要得接口,類間得依賴關(guān)系應(yīng)該建立在最小得接口上
  • 接口盡量細(xì)化孽拷,而且接口中得方法盡量得少
  • 類似于單一職責(zé)原則吨掌,更關(guān)注接口

迪米特法則

  • 也叫做最少知識(shí)原則
  • 一個(gè)軟件實(shí)體應(yīng)該盡可能少的與其他實(shí)體發(fā)生相互作用
  • 迪米特法則得初衷在于降低類之間得耦合
  • 類定義時(shí)盡量要實(shí)現(xiàn)內(nèi)聚,少使用public乓搬,盡量使用private思犁,protected等

合成復(fù)用原則

類得原則

  • 類之間有三種基本關(guān)系,分別是關(guān)聯(lián)(聚合和組合)进肯、泛化和依賴
  • 如果一個(gè)類單向依賴另一個(gè)類激蹲,那么他們之間就是單向關(guān)聯(lián)。如果彼此依賴則為相互依賴江掩,即雙向關(guān)聯(lián)
  • 關(guān)聯(lián)關(guān)系包括兩種特例:聚合和組合
    • 聚合学辱,用來表示整體與部分得關(guān)系或者擁有關(guān)系,代表部分得對(duì)象可能會(huì)被整體擁有环形,但并不一定會(huì)隨著整體的消亡而銷毀策泣。比如班級(jí)和學(xué)生
    • 合成或者說組合要比聚合關(guān)系強(qiáng)的多,部分和整體得生命周期是一致得抬吟,比如人和器官之間

從弱到強(qiáng):依賴>關(guān)聯(lián)>聚合>組合
合成復(fù)用原則

  • 合成復(fù)用原則是通過將已有得對(duì)象納入新對(duì)象中萨咕,作為新對(duì)象得成員來實(shí)現(xiàn)的
  • 新對(duì)象可以調(diào)用已有對(duì)象得功能,從而達(dá)到復(fù)用
  • 原則是盡量首先使用組合/聚合得方式火本,而不是使用繼承

工廠模式

簡單工廠

由一個(gè)工廠對(duì)象決定創(chuàng)建出哪一種產(chǎn)品類得實(shí)例

/**
 * 簡單工廠模式
 */
abstract class Coffee {
    constructor(public name: string) {}
}
class AmericanCoffee extends Coffee {}
class LatteCoffee extends Coffee {}
//簡單工廠
class CafeFactory {
    static order(name: string) {
        switch (name) {
            case 'American':
                return new AmericanCoffee('美式');
            case 'Latte':
                return new LatteCoffee('拿鐵');
            default:
                throw new Error("咖啡類型沒有");
        }
    }
}

缺點(diǎn):不符合開閉原則危队,每次增加或者刪除都要修改switch代碼
工廠方法

  • 又稱為多態(tài)性工廠模式
  • 在工廠方法模式中聪建,核心得工廠類不再負(fù)責(zé)所有得產(chǎn)品得創(chuàng)建,而是將具體創(chuàng)建得工作交給工廠子類去做
/**
 * 工廠方法模式
 */

abstract class Coffee {
    constructor(public name: string) {}
}
class AmericanCoffee extends Coffee {}
class LatteCoffee extends Coffee {}




abstract class CafeFactory {
    abstract createCoffee():Coffee;
}

class AmericanCoffeeFactory extends CafeFactory{
    createCoffee(): Coffee {
        return new AmericanCoffee('美式');
    }
}
class LatteCoffeeFactory extends CafeFactory{
    createCoffee(): Coffee {
        return new AmericanCoffee('拿鐵');
    }
}


//在工廠方法里茫陆,不再由Factory來創(chuàng)建產(chǎn)品金麸,而是先創(chuàng)建具體得工廠,然后具體得工廠來創(chuàng)建產(chǎn)品
class Factory {
    static order(name: string) {
        switch (name) {
            case 'American':
                return new AmericanCoffeeFactory().createCoffee();
            case 'Latte':
                return new LatteCoffeeFactory().createCoffee();
            default:
                throw new Error("咖啡類型沒有");
        }
    }
}

抽象工廠模式

  • 抽象工廠模式可以向客戶端提供一個(gè)接口簿盅,使客戶端在不必指定產(chǎn)品得具體得情況下挥下,創(chuàng)建多個(gè)產(chǎn)品族中得產(chǎn)品對(duì)象
  • 工廠方法模式針對(duì)得是同一類或同等級(jí)產(chǎn)品,而抽象工廠模式針對(duì)得是多種類得產(chǎn)品設(shè)計(jì)
  • 系統(tǒng)中有多個(gè)產(chǎn)品族桨醋,每個(gè)具體工廠負(fù)責(zé)創(chuàng)建同一族但屬于不同產(chǎn)品等級(jí)(產(chǎn)品種類)得產(chǎn)品
  • 產(chǎn)品族是一組相關(guān)或相互依賴得對(duì)象
  • 系統(tǒng)一次只能消費(fèi)某一族產(chǎn)品棚瘟,即相同產(chǎn)品族得產(chǎn)品是一起被使用得
  • 當(dāng)系統(tǒng)需要新增一個(gè)產(chǎn)品族時(shí),只需要增加新的工廠類即可,無需修改源代碼讨盒;但是如果需要產(chǎn)品族中增加一個(gè)新種類得產(chǎn)品時(shí)候解取,則所有得工廠類都需要修改
1.png
/**
 * 抽象工廠模式
 */

abstract class AmericanCoffee { }
abstract class LatteCoffee { }

class StarBucksAmericanCoffee extends AmericanCoffee {

}
class LuckinAmericanCoffee extends AmericanCoffee {

}
class StarBucksLatteCoffee extends LatteCoffee {

}
class LuckinLatteCoffee extends LatteCoffee {

}
abstract class CafeFacroty {
    abstract createAmericanCoffee():AmericanCoffee;
    abstract createLatteCoffee():LatteCoffee;
}

class LuckinCafeFactory extends CafeFacroty {
    createAmericanCoffee(): AmericanCoffee {
       return new LuckinAmericanCoffee()
    }
    createLatteCoffee(): LatteCoffee {
        return new LuckinLatteCoffee()
    }
}
class StarBucksCafeFactory extends CafeFacroty {
    createAmericanCoffee(): AmericanCoffee {
       return new StarBucksAmericanCoffee()
    }
    createLatteCoffee(): LatteCoffee {
        return new StarBucksLatteCoffee()
    }
}

單例模式

class Windows {
    private static instance:Windows;

    private constructor() {
        
    }
    public static getInstance(){
        if (!Windows.instance) {
            Windows.instance=new Windows();
        }
        return Windows.instance;
    }
}
let w1=Windows.getInstance();
let w2=Windows.getInstance();
console.log(w1===w2);//true

透明單例

  • 使用者并不需要知道按單例使用
let Window=(function() {
    let window:Window;
    let Window=function(this:Window) {
        if (window) {
            return window;
        }else{
            //this變量賦值給window并返回
            return (window=this);
        }
    }
    return Window;
})();
//還是正常new著使用
let w1=new (Window as any)();
let w2=new (Window as any)();
console.log(w1===w2);

單例與構(gòu)建過程的分離

function Window() {
    
}

Window.prototype.hello=function() {
    console.log('hello');
}
let createInstance=(function() {
    let instance:Window;
    return function() {
        if (!instance) {
            instance=new (Window as any);
        }
        return instance;
    }
})();

let w1=createInstance();
let w2=createInstance();
console.log(w1===w2);

封裝變化

function Window() {

}
Window.prototype.hello = function () {
    console.log('hello');
}
//希望可以創(chuàng)建任意類型的實(shí)例
let createInstance = function (Constructor: any) {
    let instance: any;
    return function (this: any) {
        if (!instance) {
            Constructor.apply(this, arguments);
            //因?yàn)檎G闆r下,this的__proto__是當(dāng)前函數(shù)返顺,即匿名函數(shù)的禀苦,但是此時(shí)需要的是外部指向,因?yàn)槭莿?dòng)態(tài)的
            //this.__proto__=Constructor.prototype
            Object.setPrototypeOf(this,Constructor.prototype)
            instance = this;
        }
        return instance;
    }
};

/*let createWindow = createInstance(Window);
let w1= new  (createWindow  as any)();
let w2= new  (createWindow  as any)();*/
let createWindow:any = createInstance(Window);
let w1= new  createWindow();
let w2= new  createWindow();
console.log(w1 === w2);

適配器模式

  • 適配器模式又稱包裝器模式遂鹊,將一個(gè)類得接口轉(zhuǎn)化成用戶需要得另一個(gè)接口振乏,解決類(對(duì)象)之間接口不兼容得問題
  • 舊得接口和使用者不兼容
  • 中間加一個(gè)適配器轉(zhuǎn)換接口
//需要被適配得類
class Socket {
   output(){
       return '220V';
   }
}

abstract class Power{
    abstract charge():string;
}
//適配器類
class PowerAdapter extends Power {
    constructor(public socket:Socket) {
        super();
    }
    charge(): string {
        return this.socket.output()+'轉(zhuǎn)換成24V';
    }
}
let adapter=new PowerAdapter(new Socket());
console.log(adapter.charge()); //220V轉(zhuǎn)換成24V

axios適配簡化邏輯

function getDefaultAdapter() {
    let adapter;
    if (typeof XMLHtttpRequest !='undefined') {
        adapter=xhr;//xhr另外函數(shù),其實(shí)就是瀏覽器環(huán)境邏輯
    }else{
        adapter=http;//http另外函數(shù)秉扑,其實(shí)就是node環(huán)境邏輯
    }
    return adapter;
}

其他例如node得promisify也是適配器模式得使用慧邮,回調(diào)轉(zhuǎn)promise;還有vue中得computed中可以把字符串轉(zhuǎn)大寫

裝飾器模式

  • 在不改變其原有結(jié)構(gòu)和功能為對(duì)象添加新功能得模式其實(shí)就叫做裝飾器模式
  • 最直觀得就是買房后得裝修
  • 裝飾比繼承更加靈活,可以實(shí)現(xiàn)裝飾著和被裝飾者之間松耦合
  • 被裝飾者可以使用裝飾者動(dòng)態(tài)得增加和撤銷功能
abstract class Shape {
    abstract draw():void;
}
class Circle extends Shape {
    draw(): void {
        console.log('繪制圓形');
    }
}
class Rectangle extends Shape {
    draw(): void {
        console.log('繪制矩形');
    }
}

//裝飾器模式
abstract class ColorfulShape extends Shape {
    constructor(public shape:Shape) {
        super();
    }
    abstract draw():void;
}
class RedColorfulShape extends ColorfulShape{
    draw(): void {
        this.shape.draw();
        console.log('邊框紅色');
    }
}

let redColorfulShape=new RedColorfulShape(new Circle());
redColorfulShape.draw();
namespace c{
    interface Animal{
        swings:number;
        fly:Function;
    }
    function flyable(target: any) {
        target.prototype.swings=2;
        target.prototype.fly=function() {
            console.log('飛');
        }
    }

    @flyable
    class Animal {
        constructor() {
            
        }
    }
    let animal:Animal=new Animal();
    animal.fly();
}

裝飾器模式擴(kuò)展(重點(diǎn))

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<style>

</style>

<body>
    <input type="text" id="username">
    <button id="register">提交</button>
</body>

</html>
<script>
    Function.prototype.before = function (beforeFn) {
        let thisFn = this;
        return function () {
            let pass = beforeFn();
            if (pass) {
                thisFn.apply(this, arguments);
            }
        }
    }
    function registerFn(event) {
        console.log('提交表單');
    }
    registerFn = registerFn.before(function () {
        let username = document.getElementById('username').value;
        if (!username) {
            return alert('用戶名不能為空!')
        }
        return true;
    })

    let registerBnt = document.getElementById('register');
    registerBnt.addEventListener('click', registerFn);
</script>

代理模式

  • 由于一個(gè)對(duì)象不能直接引用另一個(gè)對(duì)象舟陆,所以需要通過代理對(duì)象在兩個(gè)對(duì)象之間起到中介作用
  • 代理模式就算為目標(biāo)對(duì)象創(chuàng)造一個(gè)代理對(duì)象误澳,以實(shí)現(xiàn)對(duì)目標(biāo)對(duì)象的訪問
  • 這樣就可以在代理對(duì)象里增加一些邏輯判斷,調(diào)用前或調(diào)用后執(zhí)行一些操作秦躯,從而實(shí)現(xiàn)擴(kuò)展目標(biāo)的功能
  • 火車票代購忆谓,房產(chǎn)中介,律師等

類描述

  • Target目標(biāo)對(duì)象踱承,也就是被代理的對(duì)象倡缠,是具體業(yè)務(wù)的執(zhí)行者
  • Proxy代理對(duì)象,里面會(huì)包含一個(gè)目標(biāo)對(duì)象的引用茎活,可以實(shí)現(xiàn)對(duì)訪問的擴(kuò)展和額外處理

interface Star{
     answerPhone():void;//接電話
}
class Anglebaby implements Star {
    //是否有空的意思
    available:boolean=true;
    answerPhone(): void {
        console.log('你好,我是Anglebaby');
        
    }
}
//Anglebaby經(jīng)紀(jì)人
class AnglebabyAgent implements Star {
    anglebaby
    constructor(){
        this.anglebaby= new Anglebaby();
    }
    answerPhone(): void {
        console.log('你好,我是Anglebaby經(jīng)紀(jì)人');
        if (this.anglebaby.available) {
            this.anglebaby.answerPhone();
        }else{
            console.log('Anglebaby沒空');
        }
    }
}

let anglebabyAgent=new AnglebabyAgent();
anglebabyAgent.answerPhone();

代理模式使用場(chǎng)景

事件委托代理

  • 事件捕獲指的是從document到觸發(fā)事件的那個(gè)節(jié)點(diǎn)昙沦,即自上而下的去觸發(fā)事件
  • 事件冒泡是自下而上的去觸發(fā)事件
  • 綁定事件的方法的第三個(gè)參數(shù),就算控制事件觸發(fā)順序是否為事件捕獲载荔。true為事件捕獲盾饮,false為事件冒泡,默認(rèn)false
1.png

圖片預(yù)加載

  • 本質(zhì)就是大圖先加載loading圖,等實(shí)際圖片加載完畢時(shí)候才顯示
  • 通過data-set設(shè)置真實(shí)圖片地址丐谋,然后通過new Image()的Onload事件回調(diào)設(shè)置真實(shí)路徑
    虛擬代理(圖片懶加載)
  • 即判斷圖片距離頂端的距離來確認(rèn)是否在可視區(qū)域芍碧,在的話就從dataset中取出來圖片地址做顯示煌珊,否則只顯示占位(可能是圖片)
  • 當(dāng)前可視區(qū)域的高度window.innerHeight||document.documentElement.clientHeight
  • 元素距離可視區(qū)域頂部的高度getBoundingClientRect().top
    緩存代理
  • 有些時(shí)候可以用空間換時(shí)間
  • 一個(gè)正整數(shù)的階乘是所有小于及等于該數(shù)的正整數(shù)的積号俐,并且0的階乘為1
const factorial=function f(num) {
    if (num==1) {
        return 1;
    } else {
        return (num*f(num-1))
    }
}

const proxy=function(fn) {
    const cache={};//緩存對(duì)象
    return function(num) {
        if (num in cache) {
            return cache[num];//使用緩存代理
        }
        return cache[num]=fn.call(this,num);
    }
}
const proxyFactorial=proxy(factorial);

防抖代理

  • 通過防抖代理優(yōu)化可以把多次請(qǐng)求合并為一次,提高性能
  • 節(jié)流和防抖都是為了減少頻繁觸發(fā)事件回調(diào)
  • 節(jié)流是在某段時(shí)間內(nèi)不管觸發(fā)了多少次回調(diào)都只認(rèn)第一個(gè)定庵,并在第一次結(jié)束后指定回調(diào)
  • 防抖就是在某段時(shí)間不管觸發(fā)了多少回調(diào)都只看最后一個(gè)
    代理跨域
  • 正向代理和反向代理
    • 正向代理的對(duì)象是客戶端吏饿,服務(wù)器端看不到真正的客戶端
    • 通過公司代理服務(wù)器上網(wǎng)
    • 反向代理的對(duì)象是服務(wù)端,客戶端看不到真正的服務(wù)端
    • nginx代理應(yīng)用服務(wù)器
let http=require('http');
const  httpProxy=require('http-proxy');
const proxy=httpProxy.createProxyServer();

//把當(dāng)前請(qǐng)求代理到9999端口對(duì)應(yīng)的服務(wù)-反向代理
let server=http.createServer((req,res)=>{
    proxy.web(req,res,{
        target:'http://127.0.0.1:9999'
    });
})
server.listen(8888,()=>console.log('8888'))
  • 代理跨域

https://segmentfault.com/a/1190000011007043

Proxy

  • Proxy用于修改某些操作的默認(rèn)行為
  • Proxy可以理解成蔬浙,在目標(biāo)對(duì)象之前架設(shè)一層攔截猪落,外界對(duì)該對(duì)象的訪問,都必須先通過這層攔截畴博,因此提供了一種機(jī)制笨忌,可以對(duì)外界的訪問進(jìn)行過濾和改寫
  • Proxy這個(gè)次的愿意就是代理,用在這里表示由它來代理某些操作
let wang={
   name:'wanglaoshi',
   age:31,
   height:160
}
let wangMama=new Proxy(wang,{
   get(target,key){
       //target其實(shí)就是wang
       if (key==='age') {
           return wang.age-5;
       } else {
           return wang.height+5;
       }
       return target[key];
   },
   set(target,key,value){
       if (key==='boyfriend') {
           if (value.age>40) {
               throw new Error('太大')
           }else if (value.salary<20000) {
               throw new Error('賺的太少')
           }else{
               target[key]=value;
               return true;
           }
       }
       return true;
   }
})

對(duì)比

  • 代理模式VS適配器模式 適配器提供不同接口俱病,代理模式提供一摸一樣的接口
  • 代理模式VS裝飾器模式 裝飾器模式原來的功能不變還可以使用官疲,代理模式改變?cè)瓉淼墓δ?/li>

外觀模式

該模式就是把一些復(fù)雜的流程封裝成一個(gè)接口供給外部用戶更簡單的使用

  • 門面角色:外觀模式的核心绑改。它被客戶角色調(diào)用癞揉,它熟悉子系統(tǒng)的功能久妆。內(nèi)部根據(jù)客戶角色的需求預(yù)定義
  • 子系統(tǒng)角色:實(shí)現(xiàn)了子系統(tǒng)的功能榆苞。它對(duì)客戶角色和Facade時(shí)未知的
  • 客戶角色:通過調(diào)用Facede來完成要實(shí)現(xiàn)的功能
class Sum{
    sum(a,b){return a+b;}
}
class Minus{
    minus(a,b){return a-b;}
}
class Multiply{
    multiply(a,b){return a*b;}
}

//門面
class Calculator{
    constructor(){
        this.sum1=new Sum();
        this.minus1=new Minus();
        this.multiply1=new Multiply();
    }
    sum(a,b){
        return this.sum1.sum(a,b);
    }
    minus(a,b){
        return this.minus1.minus(a,b);
    }
}
let calculator=new Calculator();
console.log(calculator.sum(1,2));

觀察者模式(發(fā)布訂閱模式)

例如node中的事件總線庫也是這么實(shí)現(xiàn)

  • 被觀察者供維護(hù)觀察者的一系列方法
  • 觀察者提供更新接口
  • 觀察者把自己注冊(cè)到被觀察者里面
  • 在被觀察者發(fā)生變化時(shí)候成箫,調(diào)用觀察者的更新方法
class Star {
    constructor(name) {
        this.name = name;
        this.state = '';
        this.observers = [];//粉絲
    }
    getState() {
        return this.state
    }
    setState(state) {
        this.state = state;
        this.notifyAllObservers();
    }
    //增加新的觀察者
    attach(observer) {
        this.observers.push(observer);
    }
    notifyAllObservers() {
        if (this.observers.length > 0) {
            this.observers.forEach(observer => {
                observer.update();
            })
        }
    }
}

class Fan {
    constructor(name, star) {
        this.name = name;
        this.star = star;
        this.star.attach(this);
    }
    update() {
        console.log(this.name, this.star.state);
    }
}
let star = new Star('dsa');
let f1 = new Fan('張三', star);
let f2 = new Fan('李四', star);
star.setState('綠色');

當(dāng)然觀察者模式很多種寫法铆铆,不見得就兩者關(guān)系种蝶,也可以N者员萍,例如:租客促王,房東犀盟,中介,那么中介就處于監(jiān)聽二者消息并觸發(fā)對(duì)應(yīng)的回調(diào)邏輯

狀態(tài)模式

例如一些有限狀態(tài)機(jī)(例如:冰到水水到氣蝇狼,逆向也是阅畴,狀態(tài)有限,狀態(tài)切換順序執(zhí)行不能跳躍切換题翰,稱作狀態(tài)機(jī)恶阴,)就是利用了狀態(tài)模式

  • 當(dāng)一個(gè)對(duì)象的內(nèi)部狀態(tài)發(fā)生改變時(shí),回導(dǎo)致其行為的改變豹障,這看起來就像是改變了對(duì)象
  • 對(duì)象有自己的狀態(tài)
  • 不同狀態(tài)下執(zhí)行的邏輯不一樣
  • 明確狀態(tài)和每個(gè)狀態(tài)下執(zhí)行的動(dòng)作
  • 用來減少if else語句
class Battery{
    constructor(){
        this.amount='high';
        this.state=new SuccessState();//綠色狀態(tài)
    }
    show(){
        this.state.show();//把顯示的邏輯委托給狀態(tài)對(duì)象
        //雖然也有if else但是具體邏輯時(shí)候很復(fù)雜則避免了多層嵌套冯事,因?yàn)檫壿嬏崛×?        if (this.amount=='high') {
            this.amount='middle';
            this.state=new ErrorState();
        } else {
            this.amount='high';
            this.state=new SuccessState();
        }
    }
}
class SuccessState{
    show(){
        console.log('綠色');
    }
}
class ErrorState{
    show(){
        console.log('紅色');
    }
}

let b=new Battery();
b.show();
b.show();
b.show();
b.show();

有限狀態(tài)機(jī):https://github.com/jakesgordon/javascript-state-machine

策略模式

  • 將定義的一組算法封裝起來,使其相互之間可以替換血公。封裝的算法具有一定的獨(dú)立性昵仅,不會(huì)隨著客戶端變化而變化
  • 避免大量的swith case
class Customer{
    constructor(kind){
        this.kind=kind;
    }
    pay(amount){
        //此處本來是通過kind判斷類型,然后switch 或者if else
        return this.kind.pay(amount);
    }
}
class Normal{
    pay(amount){return amount};
}
class Vip{
    pay(amount){return amount*0.8};
}

let c=new Customer(new Normal());
console.log(c.pay(100));
c.kind=new Vip();
console.log(c.pay(100));
  • 策略抽取
class Customer{
    constructor(){
        this.kinds={
            normal:function(amount) {
                return amount;
            },
            memeber:function(amount) {
                return amount*.9;
            },
            vip:function(amount) {
                return amount*.8;
            }
        }
    }
    pay(kind,amount){
        return this.kinds[kind](amount);
    }
}

let c=new Customer();
console.log(c.pay('normal',100));

策略模式在emementui中也有,例如登錄框校驗(yàn)策略

策略模式和狀態(tài)模式的區(qū)別

  • 策略模式和狀態(tài)模式都有上下文摔笤,有策略或者狀態(tài)類够滑,上下文把這些請(qǐng)求委托給這些類來執(zhí)行
  • 策略模式中各個(gè)類是平等的,沒有關(guān)系吕世,客戶端需要知道算法主動(dòng)切換彰触,狀態(tài)模式中,狀態(tài)的切換被封裝好了客戶端不需要了解細(xì)節(jié)

原型模式

  • 基于原有的一個(gè)對(duì)象創(chuàng)建一個(gè)新對(duì)象
  • 原型模式是一個(gè)創(chuàng)建型的模式
  • 創(chuàng)建基類的時(shí)候命辖,簡單差異化的屬性放在構(gòu)造函數(shù)中况毅,消耗資源相同的功能放在基類原型中

不是原型模式

function Person(name) {
    this.name=name;
    this.getName=function() {
        console.log(this.name);
    }
}
let p1=new Person('zs');
let p2=new Person('ls');
console.log(p1.getName===p2.getName);//false
  • 函數(shù)復(fù)用
function Person(name) {
    this.name=name;
}
Person.prototype.getName=function() {
    console.log(this.name);
}
let p1=new Person('zs');
let p2=new Person('ls');
console.log(p1.getName===p2.getName);//true

橋接模式

  • 將抽象部分與它的實(shí)現(xiàn)部分分離,這樣抽象化與實(shí)現(xiàn)化解耦尔艇,使他們可以獨(dú)立的變化
  • 應(yīng)用場(chǎng)景是實(shí)現(xiàn)系統(tǒng)可能有多個(gè)角度分類尔许,每一種角度都可能變化
  • 橋方可以通過實(shí)現(xiàn)橋接口進(jìn)行單方面擴(kuò)展,而另一方可以繼承抽象類而單方面擴(kuò)展终娃,而之間的調(diào)用就從橋接口來作為突破口味廊,不會(huì)受到雙方擴(kuò)展的任何影響
class A {
    constructor(bridge) {
        this.position = 'A地點(diǎn)';
        this.bridge = bridge;
    }
    go() {
        console.log(`從${this.from()}到達(dá)${this.bridge.to()}`);
    }
    from() {
        throw new Error('子類必須實(shí)現(xiàn)此方法')
    }
}

class A1 extends A {
    from() {
        return 'A1';
    }
}
class A2 extends A {
    from() {
        return 'A2';
    }
}

class B {
    to() {
        throw new Error('子類必須實(shí)現(xiàn)此方法')
    }
}
class B1 extends B {
    to() { return 'B1' }
}
class B2 extends B {
    to() { return 'B2' }
}

let b2 = new B2();
let a1 = new A1(b2);
a1.go();//從A1到達(dá)B2 
// 此時(shí)B就是一座橋,A .B都是抽象棠耕,符合橋接模式定義余佛,然后B是橋連接A1  B2

//重點(diǎn):其他場(chǎng)景,例如:事件綁定中的callback昧辽,把callback提取出去衙熔,
//在node和瀏覽器環(huán)境傳入不同回調(diào)適應(yīng)不同環(huán)境同時(shí)降低了代碼耦合

//項(xiàng)目中:例如運(yùn)行態(tài)注冊(cè)的事件循環(huán),也是橋接模式的實(shí)現(xiàn)


/**
 * 至于解耦實(shí)現(xiàn):
 *  例如:在canvas繪畫中搅荞,畫一個(gè)形狀红氯,那么內(nèi)部可以傳入不同的位置和顏色等
 *  new  Position()  new Color()當(dāng)作參數(shù)傳入,而不是通過不同判斷實(shí)現(xiàn)不同邏輯復(fù)雜糾纏在一起
 * /

組合模式

  • 又稱整體-部分模式
  • 將對(duì)象組合成樹形結(jié)構(gòu)以表示部分-整體的層次結(jié)構(gòu)
  • 客戶可以使用統(tǒng)一的方式對(duì)待組合對(duì)象和葉子對(duì)象
  • 優(yōu)點(diǎn):可以方便地構(gòu)造一棵樹來表示對(duì)象的部分-整體 結(jié)構(gòu)咕痛。在樹的構(gòu)造最終 完成之后痢甘,只需要通過請(qǐng)求樹的最頂層對(duì) 象,便能對(duì)整棵樹做統(tǒng)一一致的操作
  • 缺點(diǎn):創(chuàng)建出來的對(duì)象長得都差不多茉贡,可能會(huì)使代碼不好理解塞栅,創(chuàng)建太多的對(duì)象對(duì)性能也會(huì)有一些影響
// 創(chuàng)建一個(gè)宏命令
const MacroCommand = function () {
    return {
        // 宏命令的子命令列表
        commandsList: [],
        // 添加命令到子命令列表
        add: function (command) {
            this.commandsList.push(command)
        },
        // 依次執(zhí)行子命令列表里面的命令
        execute: function () {
            for (var i = 0, command; command = this.commandsList[i++];) {
                command.execute()
            }
        }
    }
}

// 打開空調(diào)命令
const openAcCommand = {
    execute: function () {
        console.log('打開空調(diào)')
    }
}

//打開電視和音響
const openTvCommand = {
    execute: function () {
        console.log('打開電視')
    }
}
var openSoundCommand = {
    execute: function () {
        console.log('打開音響')
    }
}
// 創(chuàng)建一個(gè)宏命令
const macroCommand1 = MacroCommand()
// 把打開電視裝進(jìn)這個(gè)宏命令里
macroCommand1.add(openTvCommand)
// 把打開音響裝進(jìn)這個(gè)宏命令里
macroCommand1.add(openSoundCommand)

//關(guān)門、打開電腦和打登錄QQ的命令
const closeDoorCommand = {
    execute: function () {
        console.log('關(guān)門')
    }
}
const openPcCommand = {
    execute: function () {
        console.log('開電腦')
    }
}
const openQQCommand = {
    execute: function () {
        console.log('登錄QQ')
    }
};
//創(chuàng)建一個(gè)宏命令
const macroCommand2 = MacroCommand()
//把關(guān)門命令裝進(jìn)這個(gè)宏命令里
macroCommand2.add(closeDoorCommand)
//把開電腦命令裝進(jìn)這個(gè)宏命令里
macroCommand2.add(openPcCommand)
//把登錄QQ命令裝進(jìn)這個(gè)宏命令里
macroCommand2.add(openQQCommand)

//把各宏命令裝進(jìn)一個(gè)超級(jí)命令中去
const macroCommand = MacroCommand()
macroCommand.add(openAcCommand)//子命令
macroCommand.add(macroCommand1)//宏命令
macroCommand.add(macroCommand2)//宏命令
//重點(diǎn):從上可知腔丧,不論是什么類型的命令對(duì)調(diào)用者來說使用方式相同放椰,沒有區(qū)別

命令模式

  • 執(zhí)行命令時(shí),發(fā)布者和執(zhí)行者分開
  • 中間加入命令對(duì)象愉粤,作為中轉(zhuǎn)站
  • 三種角色
    • Receiver接受者角色:該角色就是干活的角色砾医,命令傳遞到這里是應(yīng)該被執(zhí)行的
    • Command命令角色:需要執(zhí)行的所有命令都在這里聲明
    • Invoker調(diào)用者角色:接收到命令,并執(zhí)行命令
class Cooker {
    cook() {
        console.log('做飯');
    }
}

class Cleaner {
    clean() {
        console.log('保潔');
    }
}
class CookCommand {
    constructor(receiver) {
        this.receiver = receiver;
    }
    execute() {
        this.receiver.cook();
    }

}
class CleanCommand {
    constructor(receiver) {
        this.receiver = receiver;
    }
    execute() {
        this.receiver.clean();
    }
}

class Customer {
    constructor(command) {
        this.command = command;
    }
    setCommand(command){
        this.command = command;
    }
    clean() {
        this.command.execute();
    }
    cook() {
        this.command.execute();
    }
}

//接收者
let cooker=new Cooker();
let cleaner=new Cleaner();
//命令角色
let cookCommand=new CookCommand(cooker);
let cleanCommand=new CleanCommand(cleaner);
//調(diào)用者
let customer=new Customer(cookCommand);
customer.cook();//做飯
customer.setCommand(cleanCommand);
customer.clean();//保潔

享元模式

  • 共享內(nèi)存衣厘,節(jié)約內(nèi)存空間
  • 相同的數(shù)據(jù)共享使用
  • 主要還是對(duì)數(shù)據(jù)如蚜、方法共享分離压恒,將數(shù)據(jù)的方法分為內(nèi)部數(shù)據(jù)、內(nèi)部方法和外部數(shù)據(jù)错邦、外部方法
  • 內(nèi)部狀態(tài)保存在對(duì)象內(nèi)部探赫,通常不會(huì)改變,可以共享
  • 外部狀態(tài)保存在對(duì)象外部撬呢,可以隨場(chǎng)景改變伦吠,不可以共享
function Person(name,age) {
    this.name=name;
    this.age=age;
}

Person.prototype.getName=function() {
    return this.name;
}

Person.prototype.getAge=function() {
    return this.age;
}
let p1=new Person();
let p2=new Person();

方式演進(jìn)

  • 正常無享元模式寫法
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <input type="radio" value="red" name="color" checked>紅色
    <input type="radio" value="yellow" name="color">黃色
    <input type="radio" value="blue" name="color">藍(lán)色
    <button onclick="draw()">繪制</button>
    <div id="container"></div>
</body>
</html>
<script>
   function draw() {
       let btns=Array.from(document.getElementsByName('color'));
       let btn=btns.find(item=>item.checked);
       let color=btn?btn.value:'red';
       let div=document.createElement('div');
       div.style=`width:100px;height:100px;background-color:${color}`;
       document.getElementById('container').appendChild(div);
   }
</script>
  • 享元模式優(yōu)化
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <input type="radio" value="red" name="color" checked>紅色
    <input type="radio" value="yellow" name="color">黃色
    <input type="radio" value="blue" name="color">藍(lán)色
    <button onclick="draw()">繪制</button>
    <div id="container">
    </div>
</body>
</html>
<script>
    class MyDiv{
        constructor(){
            this.element=document.createElement('div');
        }
        setColor(color){
            this.element.style=`width:100px;height:100px;background-color:${color}`;
        }
    }
    //div對(duì)象是同一個(gè),則下面即使是appendChild也不會(huì)追加而是修改
    let myDiv=new MyDiv();
   function draw() {
       let btns=Array.from(document.getElementsByName('color'));
       let btn=btns.find(item=>item.checked);
       let color=btn?btn.value:'red';
       myDiv.setColor(color);
       document.getElementById('container').appendChild(myDiv.element);
   }
</script>

模板方法模式

  • 模板方法模式在一個(gè)方法種定義一個(gè)算法的骨架倾芝,而將一些步驟的實(shí)現(xiàn)延遲到子類中
  • 模板方法使得子類可以在不改變算法結(jié)構(gòu)的情況下讨勤,重新定義算法中某些步驟的具體實(shí)現(xiàn)
  • 一般有兩部分組成,第一部分是抽象父類晨另,第二部分是具體的實(shí)現(xiàn)子類
  • 好萊塢原則,子類放棄了控制權(quán)谱姓,改由父類來調(diào)用
    • 發(fā)布訂閱
    • 回調(diào)函數(shù)
class Person {
    //此處就是不改變的算法結(jié)構(gòu)
    dinner() {
        this.buy();
        this.cook();
        this.eat();
    }
    buy() {
        //相當(dāng)于抽象
        throw new Error('必須由子類去實(shí)現(xiàn)')
    }
    cook() {
        throw new Error('必須由子類去實(shí)現(xiàn)')
    }
    eat() {
        throw new Error('必須由子類去實(shí)現(xiàn)')
    }
}

class Teacher extends Person {
    //子類重新定義算法的實(shí)現(xiàn)
    buy() {
        console.log('買菜');
    }
    cook() {
        console.log('做菜');
    }
    eat() {
        console.log('吃飯');
    }
}
let t=new Teacher();
t.dinner();

例如:elementui的警告框借尿,其實(shí)內(nèi)部不同顏色顯示久利用了模板方法模式

職責(zé)鏈模式

備忘錄模式

中介者模式

訪問者模式

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市屉来,隨后出現(xiàn)的幾起案子路翻,更是在濱河造成了極大的恐慌,老刑警劉巖茄靠,帶你破解...
    沈念sama閱讀 216,692評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件茂契,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡慨绳,警方通過查閱死者的電腦和手機(jī)掉冶,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,482評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來脐雪,“玉大人厌小,你說我怎么就攤上這事≌角铮” “怎么了璧亚?”我有些...
    開封第一講書人閱讀 162,995評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長脂信。 經(jīng)常有香客問我癣蟋,道長,這世上最難降的妖魔是什么狰闪? 我笑而不...
    開封第一講書人閱讀 58,223評(píng)論 1 292
  • 正文 為了忘掉前任疯搅,我火速辦了婚禮,結(jié)果婚禮上尝哆,老公的妹妹穿的比我還像新娘秉撇。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,245評(píng)論 6 388
  • 文/花漫 我一把揭開白布琐馆。 她就那樣靜靜地躺著规阀,像睡著了一般。 火紅的嫁衣襯著肌膚如雪瘦麸。 梳的紋絲不亂的頭發(fā)上谁撼,一...
    開封第一講書人閱讀 51,208評(píng)論 1 299
  • 那天,我揣著相機(jī)與錄音滋饲,去河邊找鬼厉碟。 笑死,一個(gè)胖子當(dāng)著我的面吹牛屠缭,可吹牛的內(nèi)容都是我干的箍鼓。 我是一名探鬼主播,決...
    沈念sama閱讀 40,091評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼呵曹,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼款咖!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起奄喂,我...
    開封第一講書人閱讀 38,929評(píng)論 0 274
  • 序言:老撾萬榮一對(duì)情侶失蹤铐殃,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后跨新,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體富腊,經(jīng)...
    沈念sama閱讀 45,346評(píng)論 1 311
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,570評(píng)論 2 333
  • 正文 我和宋清朗相戀三年域帐,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了赘被。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,739評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡俯树,死狀恐怖帘腹,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情许饿,我是刑警寧澤阳欲,帶...
    沈念sama閱讀 35,437評(píng)論 5 344
  • 正文 年R本政府宣布,位于F島的核電站陋率,受9級(jí)特大地震影響球化,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜瓦糟,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,037評(píng)論 3 326
  • 文/蒙蒙 一筒愚、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧菩浙,春花似錦巢掺、人聲如沸句伶。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,677評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽考余。三九已至,卻和暖如春轧苫,著一層夾襖步出監(jiān)牢的瞬間楚堤,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,833評(píng)論 1 269
  • 我被黑心中介騙來泰國打工含懊, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留身冬,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,760評(píng)論 2 369
  • 正文 我出身青樓岔乔,卻偏偏與公主長得像酥筝,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子重罪,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,647評(píng)論 2 354