Java日記之設(shè)計(jì)模式總結(jié)(行為型)

前言

推薦看這篇文章之前先了解Java日記之設(shè)計(jì)模式初探勒叠。

行為型設(shè)計(jì)模式總共有11種

1.模板方法模式
2.迭代器模式
3.策略模式
4.解釋器模式
5.觀察者模式
6.備忘錄模式
7.命令模式
8.中介者模式
9.責(zé)任鏈模式
10.訪問者模式
11.狀態(tài)模式

1.模板方法模式

  • 定義:定義了一個(gè)算法的骨架式矫,并允許子類為一個(gè)或多個(gè)步驟提供實(shí)現(xiàn)加勤。比如把大象放進(jìn)冰箱分幾步,首先打開開門,然后放進(jìn)去,最后關(guān)山門,這3個(gè)步驟就可以用模板方法設(shè)計(jì)模式汇陆。這個(gè)算法就是一個(gè)處理過程。模板方法使得子類可以在不改變算法結(jié)構(gòu)的情況下带饱,重新定義算法的某些步驟毡代。

  • 適用場景:一次性實(shí)現(xiàn)一個(gè)算法的不變的部分,并將可變的行為留給子類來實(shí)現(xiàn)勺疼。各子類中公共的行為被提取出來并集中到一個(gè)公共父類中教寂,從而避免代碼重復(fù)。

  • 優(yōu)點(diǎn):提高復(fù)用性执庐,提高擴(kuò)展性酪耕。符合開閉原則。

  • 缺點(diǎn):類數(shù)目增加轨淌,增加了系統(tǒng)實(shí)現(xiàn)的復(fù)雜度迂烁,繼承關(guān)系自身缺點(diǎn),如果父類添加新的抽象方法递鹉,所有子類都要修改一遍盟步。

  • 擴(kuò)展:鉤子方法(它是這個(gè)模板對子類更進(jìn)一層的開發(fā)和拓展)。

  • 相關(guān)設(shè)計(jì)模式:工廠方法模式(工廠是模板的一種特殊實(shí)現(xiàn))躏结。策略模式(都有封裝算法却盘,策略模式的目的是使不同的算法可以相互替換,并且不影響應(yīng)用層的使用媳拴。模板是針對一個(gè)定義算法的流程谷炸,而將一些不太一樣的具體實(shí)現(xiàn)步驟交給子類實(shí)現(xiàn),模板是不改變算法的流程的禀挫,策略是可以改變的,并且是可以相互替換的)拓颓。

代碼舉例:
我們引入一個(gè)場景语婴,比如說制作一門課程。對于制作一個(gè)課程驶睦,需要制作PPT砰左,制作視頻,還要決定是否要寫一個(gè)手記场航,還有是否要提供一些素材缠导,意思就是說,不同的課程溉痢,制作的主線是一樣的僻造,在細(xì)分的一些細(xì)節(jié)上還是有所不同憋他。比如有一些課程不需要手記,所以寫手機(jī)這個(gè)是一個(gè)非必選項(xiàng)髓削,完全留給子類來擴(kuò)展竹挡,那就可以把這個(gè)方法做出鉤子方法。

//定義模板標(biāo)準(zhǔn)
public abstract class ACourse {


    protected final void makeCourse(){
        this.makePPT();
        this.makeVideo();
        if (needWriteArticle()){
            this.writeArticle();
        }
        this.packageCourse();
    }

    //制作什么課程都要PPT
    final void makePPT(){
        System.out.println("制作PPT");
    }

    final void makeVideo(){
        System.out.println("制作視頻");
    }

    final void writeArticle(){
        System.out.println("編寫手記");
    }


    //鉤子方法
    protected boolean needWriteArticle(){
        return false;
    }

    abstract void packageCourse();
}


//設(shè)計(jì)模式課程
public class DesignPatternCourse extends ACourse{


    @Override
    void packageCourse() {
        System.out.println("提供課程Java源代碼");
    }

    //如果這個(gè)課程需要手記就重寫為true
    @Override
    protected boolean needWriteArticle() {
        return true;
    }
}


//前端課程
public class FECourse extends ACourse{
    
    
    //這個(gè)鉤子值也可以交給應(yīng)用層
    private boolean needWriteArticleFlag = false;

    public FECourse(boolean needWriteArticleFlag) {
        this.needWriteArticleFlag = needWriteArticleFlag;
    }

    @Override
    void packageCourse() {
        System.out.println("提供課程前端代碼");
        System.out.println("提供課程圖片素材");
    }


    @Override
    protected boolean needWriteArticle() {
        return needWriteArticleFlag;
    }
}

//測試類
public class Test {

    public static void main(String[] args) {
        System.out.println("后端設(shè)計(jì)模式課程start---");
        ACourse designCourse = new DesignPatternCourse();
        designCourse.makeCourse();
        System.out.println("后端設(shè)計(jì)模式課程end---");


        System.out.println("前端課程start---");
        ACourse fECourse = new FECourse(true);
        fECourse.makeCourse();
        System.out.println("前端課程end---");
    }
}

模板方法設(shè)計(jì)模式運(yùn)行結(jié)果

通過定義一個(gè)模板類立膛,然后由子類詳細(xì)的編寫具體的步驟揪罕,模板方法設(shè)計(jì)模式的核心就是要加final,否則子類是可以重寫的宝泵,這就是失去模板方法設(shè)計(jì)模式的用意了好啰。

2.迭代器模式

  • 定義:提供一種方法,順序訪問一個(gè)集合對象中的各個(gè)元素儿奶,而又不暴露該對象的內(nèi)部表示框往。簡單理解就是遍歷。

  • 適用場景:訪問一個(gè)集合對象的內(nèi)容而無需暴露它的內(nèi)部表示廓握。為遍歷不同的集合結(jié)構(gòu)提供一個(gè)統(tǒng)一的接口搅窿。

  • 優(yōu)點(diǎn):分離了集合對象的遍歷行為。

  • 缺點(diǎn):類的個(gè)數(shù)成對增加隙券。因?yàn)檫@個(gè)設(shè)計(jì)模式是把存儲(chǔ)數(shù)據(jù)和遍歷數(shù)據(jù)這兩個(gè)職責(zé)進(jìn)行分離男应。

  • 相關(guān)設(shè)計(jì)模式:訪問者模式。

代碼舉例:
這里注意一下娱仔,迭代器在日常使用當(dāng)中是很廣泛的沐飘,但是我們是用的Jdk還有開源的項(xiàng)目當(dāng)中,這些數(shù)據(jù)結(jié)構(gòu)都會(huì)使用現(xiàn)成的迭代器牲迫,幾乎不會(huì)自己去寫一個(gè)耐朴。我們這里來解讀寫好的迭代器代碼。

舉例一個(gè)業(yè)務(wù)場景盹憎,就是慕課網(wǎng)網(wǎng)站的課程筛峭,首先我們有一個(gè)課程的實(shí)體類,然后進(jìn)行遍歷陪每。

//課程實(shí)體類
public class Course {
    private String name;

    public Course(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

}


//數(shù)據(jù)操作接口
public interface CourseAggregate {

    void addCourse(Course course);
    void removeCourse(Course course);
    
    //返回迭代器
    CourseIterator getCourseIterator();

}

//實(shí)現(xiàn)操作接口
public class CourseAggregateImpl implements CourseAggregate {

    private List courseList;

    public CourseAggregateImpl() {
        this.courseList = new ArrayList();
    }

    @Override
    public void addCourse(Course course) {
        courseList.add(course);
    }

    @Override
    public void removeCourse(Course course) {
        courseList.remove(course);
    }

    @Override
    public CourseIterator getCourseIterator() { 
        //返回實(shí)現(xiàn)迭代器接口的類
        return new CourseIteratorImpl(courseList);
    }
}

//迭代器接口
public interface CourseIterator {
    Course nextCourse();
    boolean isLastCourse();

}

//實(shí)現(xiàn)迭代器
public class CourseIteratorImpl implements CourseIterator {

    private List courseList;
    private int position;
    private Course course;

    public CourseIteratorImpl(List courseList){
        this.courseList=courseList;
    }

    @Override
    public Course nextCourse() {
        System.out.println("返回課程,位置是: "+position);
        course=(Course)courseList.get(position);
        position++;
        return course;
    }

    @Override
    public boolean isLastCourse(){
        if(position< courseList.size()){
            return false;
        }
        return true;
    }
}

//測試類
public class Test {


    public static void main(String[] args) {
        Course course1 = new Course("Java電商一期");
        Course course2 = new Course("Java電商二期");
        Course course3 = new Course("Java設(shè)計(jì)模式精講");
        Course course4 = new Course("Python課程");
        Course course5 = new Course("算法課程");
        Course course6 = new Course("前端課程");


        CourseAggregate courseAggregate = new CourseAggregateImpl();

        courseAggregate.addCourse(course1);
        courseAggregate.addCourse(course2);
        courseAggregate.addCourse(course3);
        courseAggregate.addCourse(course4);
        courseAggregate.addCourse(course5);
        courseAggregate.addCourse(course6);

        System.out.println("-----課程列表-----");
        printCourses(courseAggregate);

        courseAggregate.removeCourse(course4);
        courseAggregate.removeCourse(course5);

        System.out.println("-----刪除操作之后的課程列表-----");
        printCourses(courseAggregate);
    }


    public static void printCourses(CourseAggregate courseAggregate){
        CourseIterator courseIterator= courseAggregate.getCourseIterator();
        while(!courseIterator.isLastCourse()){
            Course course=courseIterator.nextCourse();
            System.out.println(course.getName());
        }
    }


}

我們分別創(chuàng)建了CourseAggregate和CourseIterator影晓,然后通過實(shí)現(xiàn)CourseAggregate的類的getCourseIterator()來獲取你自定義的迭代器,最后在測試類中通過printCourses()來遍歷課程檩禾。這就是迭代器的基本創(chuàng)建了挂签。

3.策略模式

  • 定義:定義了算法家族,分別封裝起來盼产,讓他們之間可以互相替換饵婆,此模式讓算法的變化不會(huì)影響到使用算法的用戶(應(yīng)用層)∠肥郏可以替換大量的if...else...侨核。

  • 適用場景:系統(tǒng)有很多類草穆,而他們的區(qū)別僅僅在于他們的行為不同。一個(gè)系統(tǒng)需要?jiǎng)討B(tài)地在幾種算法中選擇一種芹关。

  • 優(yōu)點(diǎn):提供了對開閉原則的完美支持续挟。可以避免使用多重條件轉(zhuǎn)移語句侥衬。提高算法的保密性和安全性诗祸。

  • 缺點(diǎn):客戶端必須知道所有的策略類,并且自行來決定使用哪一個(gè)策略類轴总。而且會(huì)產(chǎn)生很多策略類直颅。

  • 相關(guān)設(shè)計(jì)模式:工廠模式、狀態(tài)模式怀樟。

代碼舉例:
電商網(wǎng)站在618會(huì)舉行各種促銷活動(dòng)功偿,促銷是課程的行為,促銷行為往堡,但是有多種實(shí)現(xiàn)械荷。策略模式一般不是單獨(dú)使用的,一般是配合工廠虑灰、單例吨瞎、享元模式來使用的,我們這里創(chuàng)建一個(gè)策略工廠模式來配合實(shí)現(xiàn)穆咐。

//策略促銷接口
public interface PromotionStrategy {

    //進(jìn)行促銷
    void doPromotion();

}

//無促銷實(shí)現(xiàn)
public class EmptyPromotionStrategy implements PromotionStrategy{

    @Override
    public void doPromotion() {
        System.out.println("無促銷");
    }
}


//返現(xiàn)實(shí)現(xiàn)
public class FanXianPromotionStrategy implements PromotionStrategy{

    @Override
    public void doPromotion() {
        System.out.println("返現(xiàn)促銷颤诀,返回的金額存到慕課網(wǎng)用戶的余額中");
    }
}

//滿減實(shí)現(xiàn)
public class ManJIanPromotionStrategy implements PromotionStrategy{

    @Override
    public void doPromotion() {
        System.out.println("滿減促銷,滿200減20");
    }
}   

//立減實(shí)現(xiàn)
public class LiJianPromotionStrategy implements PromotionStrategy{


    @Override
    public void doPromotion() {
        System.out.println("立減促銷对湃,課程的價(jià)格直接減去配置的價(jià)格");
    }
}

//策略工廠
public class PromotionStrategyFactory {

    private static Map<String, PromotionStrategy> PROMOTION_STRATEGY_MAP = new HashMap<>();

    //類加載的時(shí)候
    static {
        PROMOTION_STRATEGY_MAP.put(PromotionKey.LIJIAN, new LiJianPromotionStrategy());
        PROMOTION_STRATEGY_MAP.put(PromotionKey.FANXIAN, new FanXianPromotionStrategy());
        PROMOTION_STRATEGY_MAP.put(PromotionKey.MANJIAN, new ManJIanPromotionStrategy());
    }


    private static final PromotionStrategy NON_PROMOTION = new EmptyPromotionStrategy();


    private PromotionStrategyFactory() {
    }

    public static PromotionStrategy getPromotionStrategy(String promotionStrategKey) {
        PromotionStrategy promotionStrategy = PROMOTION_STRATEGY_MAP.get(promotionStrategKey);

        return promotionStrategy == null ? NON_PROMOTION : promotionStrategy;
    }


    private interface PromotionKey {
        final String LIJIAN = "LIJIAN";
        final String FANXIAN = "FANXIAN";
        final String MANJIAN = "MANJIAN";
    }
}
//策略活動(dòng)
public class PromotionActivity {

    private PromotionStrategy promotionStrategy;

    public PromotionActivity(PromotionStrategy promotionStrategy) {
        this.promotionStrategy = promotionStrategy;
    }

    public void executePromotionStrategy(){
        promotionStrategy.doPromotion();
    }
    
}


//測試類
public class Test {


    public static void main(String[] args) {

        //假設(shè)key是外部傳進(jìn)來的
        String promotionKey1 = "LIJIAN";
        PromotionActivity promotionActivity1 = new PromotionActivity(PromotionStrategyFactory.getPromotionStrategy(promotionKey1));
        promotionActivity1.executePromotionStrategy();

        String promotionKey2 = "MANJIAN";
        PromotionActivity promotionActivity2 = new PromotionActivity(PromotionStrategyFactory.getPromotionStrategy(promotionKey2));
        promotionActivity2.executePromotionStrategy();


        String promotionKey3 = "";
        PromotionActivity promotionActivity3 = new PromotionActivity(PromotionStrategyFactory.getPromotionStrategy(promotionKey3));
        promotionActivity3.executePromotionStrategy();
    }
}

策略模式運(yùn)行結(jié)果

整個(gè)業(yè)務(wù)邏輯的架構(gòu)不變崖叫,只是替換其中的促銷業(yè)務(wù)邏輯,就可以通過key值來決定你要進(jìn)行什么樣子的促銷策略拍柒,然后將key值傳入工廠策略模式里面進(jìn)行調(diào)用心傀,這樣就可以減少大量的if...else...了,唯一的缺點(diǎn)就是應(yīng)用層必須知道有哪些促銷策略拆讯。

4.解釋器模式

  • 定義:給定一個(gè)語言剧包,定義它的文法的一種表示,并定義一個(gè)解釋器往果,這個(gè)解釋器使用該表示來解釋語言中的句子。為了解釋一種語言一铅,而為語言創(chuàng)建的解釋器陕贮。

  • 適用場景:某個(gè)特定類型問題發(fā)生頻率足夠高,例如腳本語言潘飘,或者日志文件肮之,我們需要對這些文件進(jìn)行解析掉缺,就要通過程序(解釋器)來解決該問題。就是其一般使用開源工具包

  • 優(yōu)點(diǎn):語言由很多類表示戈擒,容易改變及擴(kuò)展此“語言”眶明。

  • 缺點(diǎn):當(dāng)語法規(guī)則數(shù)目太多時(shí),增加了系統(tǒng)復(fù)雜度筐高。

  • 相關(guān)設(shè)計(jì)模式:適配器模式

解釋器模式的使用頻率其實(shí)是很低的搜囱。而且現(xiàn)在實(shí)現(xiàn)解釋器模式一般也是使用開源工具包來進(jìn)行實(shí)現(xiàn),這里就不上代碼舉例了柑土。

5.觀察者模式

  • 優(yōu)點(diǎn):定義了對象之間的一對多的依賴蜀肘,讓多個(gè)觀察者對象同時(shí)監(jiān)聽某一個(gè)主題對象,當(dāng)主題對象發(fā)生變化時(shí)稽屏,它的所有依賴者(觀察者)都會(huì)收到通知并更新扮宠。比如,微信的朋友圈點(diǎn)贊之后狐榔,就代表著你是觀察者坛增,而朋友圈這條信息就是被觀察者就是主題對象,那在這個(gè)主題對象被評論的時(shí)候薄腻,微信就會(huì)通知觀察者即點(diǎn)贊的人收捣,這就是觀察者模式的應(yīng)用、

  • 適用場景:關(guān)聯(lián)行為場景被廓,建立一套觸發(fā)機(jī)制塘匣。

  • 優(yōu)點(diǎn):觀察者和被觀察者之間建立了一個(gè)抽象的耦合。觀察者模式支持廣播通信每篷。

  • 缺點(diǎn):觀察者之間有過多的細(xì)節(jié)依賴扭吁,提高時(shí)間消耗及程序復(fù)雜度。還有使用要得到蜓斧,避免循環(huán)調(diào)用仓蛆。

代碼舉例:

//課程類,繼承Observable挎春,是被觀察者
public class Course extends Observable {

    private String CourseName;

    public Course(String courseName) {
        this.CourseName = courseName;
    }


    public String getCourseName() {
        return CourseName;
    }


    public void produceQuestion(Course course, Question question) {
        System.out.println(question.getUserName() + "在" + course.CourseName+"提交了一個(gè)問題");
        setChanged();
        notifyObservers(question);
    }
}

//問題類
public class Question {

    private String userName;

    private String questionContent;


    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public String getQuestionContent() {
        return questionContent;
    }

    public void setQuestionContent(String questionContent) {
        this.questionContent = questionContent;
    }
}


//老師看疙,繼承Observer,是觀察者
public class Teacher implements Observer {

    private String teacherName;

    public Teacher(String teacherName) {
        this.teacherName = teacherName;
    }


    @Override
    public void update(Observable o, Object arg) {
        Course course = (Course) o;
        Question question = (Question) arg;
        System.out.println(teacherName + "老師的" + course.getCourseName() + "課程接收到一個(gè)" + question.getUserName() + "提交的問題:" + question.getQuestionContent());



    }
}

//測試類
public class Test {
    public static void main(String[] args) {
        Course course = new Course("Java設(shè)計(jì)模式");
        Teacher teacher = new Teacher("alpha");


        course.addObserver(teacher);

        //業(yè)務(wù)邏輯
        Question question = new Question();
        question.setUserName("juju");
        question.setQuestionContent("java函數(shù)如何編寫");

        course.produceQuestion(course, question);
    }
    
}

觀察者模式運(yùn)行結(jié)果

Course類繼承Observable后就成為了被觀察者直奋,Teacher類繼承Observer接口就成為了被觀察者能庆,需要實(shí)現(xiàn)update()方法,這個(gè)方法就是當(dāng)被觀察者發(fā)生改變的時(shí)候會(huì)調(diào)用的方法脚线。在測試類中搁胆,通過addObserver()則就可以添加多個(gè)觀察者,然后調(diào)用Course類的produceQuestion()方法,在produceQuestion()方法里面渠旁,會(huì)調(diào)用Observable的setChanged()方法攀例,表示被觀察者發(fā)生改變,然后通過notifyObservers()可以傳遞需要處理的對象或者業(yè)務(wù)邏輯顾腊,這個(gè)對象從update()中的第二個(gè)參數(shù)可以獲取粤铭,第一個(gè)參數(shù)為被觀察者對象。

6.備忘錄模式

  • 定義: 保存一個(gè)對象的某個(gè)狀態(tài)杂靶,以便在適當(dāng)?shù)臓顟B(tài)恢復(fù)對象梆惯,一句話,后悔藥伪煤。

  • 適用場景:保存及恢復(fù)數(shù)據(jù)相關(guān)的業(yè)務(wù)場景加袋。還有后悔的時(shí)候,想恢復(fù)之間的狀態(tài)抱既。

  • 優(yōu)點(diǎn):為用戶提供一種可恢復(fù)的機(jī)制和存檔信息的封裝职烧。

  • 缺點(diǎn):資源占用。

  • 相關(guān)設(shè)計(jì)模式:狀態(tài)模式防泵。

我們這里引入一個(gè)業(yè)務(wù)場景蚀之,就是在網(wǎng)站上面發(fā)布一篇手記,然后其中有暫存的功能捷泞,而這個(gè)功能就可以通過備忘錄設(shè)計(jì)模式來進(jìn)行實(shí)現(xiàn)足删。

代碼舉例:

//手記類
public class Article {

    private String title;
    private String content;
    private String imgs;

    public Article(String title, String content, String imgs) {
        this.title = title;
        this.content = content;
        this.imgs = imgs;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public String getContent() {
        return content;
    }

    public void setContent(String content) {
        this.content = content;
    }

    public String getImgs() {
        return imgs;
    }

    public void setImgs(String imgs) {
        this.imgs = imgs;
    }
    
    
    //保存快照
    public ArticleMemento saveToMemento() {
        ArticleMemento articleMemento = new ArticleMemento(this.title,this.content,this.imgs);
        return articleMemento;
    }
    
    //恢復(fù)快照
    public void undoFromMemento(ArticleMemento articleMemento) {

        this.title = articleMemento.getTitle();
        this.content = articleMemento.getContent();
        this.imgs = articleMemento.getImgs();
    }

    @Override
    public String toString() {
        return "Article{" +
                "title='" + title + '\'' +
                ", content='" + content + '\'' +
                ", imgs='" + imgs + '\'' +
                '}';
    }
}


//快照類
public class ArticleMemento {
    private String title;
    private String content;
    private String imgs;

    public ArticleMemento(String title, String content, String imgs) {
        this.title = title;
        this.content = content;
        this.imgs = imgs;
    }

    public String getTitle() {
        return title;
    }

    public String getContent() {
        return content;
    }

    public String getImgs() {
        return imgs;
    }

    @Override
    public String toString() {
        return "ArticleMemento{" +
                "title='" + title + '\'' +
                ", content='" + content + '\'' +
                ", imgs='" + imgs + '\'' +
                '}';
    }
}

首先創(chuàng)建一個(gè)Article類,也就是手記類锁右,里面有兩個(gè)重要的方法失受,saveToMemento()undoFromMemento()方法。saveToMemento()主要就是會(huì)創(chuàng)建一個(gè)ArticleMemento實(shí)例咏瑟,也就是快照實(shí)例拂到,然后把需要保存的數(shù)據(jù)放入到ArticleMemento實(shí)例中保存下來,undoFromMemento()主要就是恢復(fù)那些已經(jīng)保存的快照實(shí)例里面的值码泞,這里注意一下兄旬,ArticleMemento也就是快照類是不需要set()方法的,它只能通過構(gòu)造函數(shù)來傳遞數(shù)值余寥。然后领铐,我們在創(chuàng)建一個(gè)管理這些快照的管理類。

public class ArticleMementoManager {

    private final Stack<ArticleMemento> ARTICLE_MEMENTO_STACK = new Stack<>();

    public ArticleMemento getMemento()
    {
        ArticleMemento articleMemento= ARTICLE_MEMENTO_STACK.pop();
        return articleMemento;
    }

    public void addMemento(ArticleMemento articleMemento)
    {
        ARTICLE_MEMENTO_STACK.push(articleMemento);
    }

}

管理方式通過Stack來進(jìn)行管理宋舷,getMemento()就是出棧绪撵,獲得最新保存的快照實(shí)例,addMemento()就是入棧操作了祝蝠。

備忘錄模式UML類圖

我們從UML中可以看出莲兢,ArticleMemento類汹来,也就是快照類是只能被Article類來進(jìn)行創(chuàng)造的,ArticleMemento類和ArticleMementoManager 類是一種聚合關(guān)系改艇,因?yàn)锳rticleMementoManager類可以有多個(gè)ArticleMemento。

//測試類
public class Test {

    public static void main(String[] args) {

        ArticleMementoManager articleMementoManager = new ArticleMementoManager();

        Article article= new Article("如影隨行的設(shè)計(jì)模式A","手記內(nèi)容A","手記圖片A");

        ArticleMemento articleMemento = article.saveToMemento();

        articleMementoManager.addMemento(articleMemento);
        System.out.println("標(biāo)題:"+article.getTitle()+" 內(nèi)容:"+article.getContent()+" 圖片:"+article.getImgs()+" 暫存成功");

        System.out.println("手記完整信息:"+article);


        System.out.println("修改手記start");

        article.setTitle("如影隨行的設(shè)計(jì)模式B");
        article.setContent("手記內(nèi)容B");
        article.setImgs("手記圖片B");

        System.out.println("修改手記end");

        System.out.println("手記完整信息:"+article);

        articleMemento = article.saveToMemento();
        articleMementoManager.addMemento(articleMemento);



        article.setTitle("如影隨行的設(shè)計(jì)模式C");
        article.setContent("手記內(nèi)容C");
        article.setImgs("手記圖片C");

        System.out.println("暫存回退start");

        System.out.println("回退出棧1次");
        articleMemento = articleMementoManager.getMemento();
        article.undoFromMemento(articleMemento);

        System.out.println("回退出棧2次");
        articleMemento = articleMementoManager.getMemento();
        article.undoFromMemento(articleMemento);



        System.out.println("暫存回退end");
        System.out.println("手記完整信息:"+article);

    }
}

備忘錄模式運(yùn)行結(jié)果


7.命令模式

  • 定義:將“請求”封裝為對象坟岔,以便使用不同的請求谒兄。命令模式解決了應(yīng)用程序中對象的職責(zé)以及它們之間的通信方式。命令模式可以使發(fā)送者和接收者完全解耦社付,發(fā)送命令的對象只知道如何發(fā)送請求承疲,不需要只要如何完成請求。

  • 適用場景:請求調(diào)用者和請求接收者需要解耦鸥咖,使得調(diào)用者和接收者不直接交互燕鸽。需要抽象出等待執(zhí)行的行為。

  • 優(yōu)點(diǎn):降低耦合啼辣。容易擴(kuò)展新命令或者一組命令啊研。

  • 缺點(diǎn):命令的無限擴(kuò)展會(huì)增加類的數(shù)量,提高系統(tǒng)實(shí)現(xiàn)復(fù)雜度鸥拧。

  • 相關(guān)設(shè)計(jì)模式:備忘錄模式党远,我們可以通過備忘錄保存命令的歷史記錄。

假設(shè)我們開發(fā)一個(gè)功能富弦,關(guān)閉一個(gè)課程的視頻沟娱,或者局部關(guān)閉某一小節(jié)或者打開。對于這些課程來說腕柜,第一章節(jié)是免費(fèi)開放的济似,后續(xù)章節(jié)需要購買之后才能學(xué)習(xí)觀看,假如說下了一個(gè)命令盏缤,免費(fèi)開放了第二章砰蠢,又過了一陣,免費(fèi)開放了第三章蛾找。然后又過了一陣把第二章節(jié)又關(guān)閉了娩脾。

代碼舉例:

//命令接口
public interface Command {

    void  execute();
}

//課程視頻類
public class CourseVideo {

    private String name;

    public CourseVideo(String name) {
        this.name = name;
    }

     public void open() {
        System.out.println(this.name + "課程視頻開發(fā)");
    }


    public void close() {
        System.out.println(this.name + "課程視頻關(guān)閉");
    }

}

//關(guān)閉視頻命令
public class CloseCourseVideoCommand implements Command {

    private CourseVideo courseVideo;

    public CloseCourseVideoCommand(CourseVideo courseVideo) {
        this.courseVideo = courseVideo;
    }


    @Override
    public void execute() {
        courseVideo.close();
    }
}

//打開視頻命令
public class OpenCourseVideoCommand implements Command {

    private CourseVideo courseVideo;

    public OpenCourseVideoCommand(CourseVideo courseVideo) {
        this.courseVideo = courseVideo;
    }

    @Override
    public void execute() {
        courseVideo.open();
    }
    
}

首先創(chuàng)建一個(gè)命令接口和一個(gè)CourseVideo類,CourseVideo類里面有要執(zhí)行的方法打毛,我們的目標(biāo)就是包裝這些方法(命令)柿赊,接著創(chuàng)建OpenCourseVideoCommand類和CloseCourseVideoCommand類,這兩個(gè)類繼承Command接口幻枉,構(gòu)造函數(shù)傳入CourseVideo實(shí)例碰声,接著在execute()里實(shí)現(xiàn)你要封裝的命令,接下來要執(zhí)行這些命令或者一組命令肯定要有一個(gè)執(zhí)行者熬甫,接著創(chuàng)建一個(gè)Staff類:

public class Staff {


    private List<Command> commandList = new ArrayList<>();

    public void addCommand(Command command) {
        commandList.add(command);
    }

    public void executeCommands() {
        for (Command command : commandList) {
            command.execute();
        }

        commandList.clear();
    }
}

Staff類里面有一個(gè)List胰挑,里面放入的就是一組命令,通過addCommand()方法可以放入你想要組合的命令,最后通過executeCommands()來執(zhí)行瞻颂,執(zhí)行完畢后會(huì)通過clear()來清除這個(gè)集合命令豺谈。

命令模式UML

從UML圖可以看出,首先CloseCourseVideoCommand和OpenCourseVideoCommand是命令它們實(shí)現(xiàn)Command接口贡这,Staff里面可以有多個(gè)Command或者一個(gè)茬末。也就是說如果我們擴(kuò)展Command,Command和Staff已經(jīng)是一對多的關(guān)系盖矫,所以Staff里面的代碼是不用動(dòng)的丽惭。

public class Test {

    public static void main(String[] args) {
        CourseVideo courseVideo = new CourseVideo("Java設(shè)計(jì)模式-命令模式");
        OpenCourseVideoCommand openCourseVideoCommand = new OpenCourseVideoCommand(courseVideo);
        CloseCourseVideoCommand closeCourseVideoCommand = new CloseCourseVideoCommand(courseVideo);

        Staff staff = new Staff();
        staff.addCommand(openCourseVideoCommand);
        staff.addCommand(closeCourseVideoCommand);

        staff.executeCommands();
    }
}

命令模式運(yùn)行結(jié)果


8.中介者模式

  • 定義:定義一個(gè)封裝一組對象如何交互的對象。通過使對象明確的相互引用來促進(jìn)松散耦合辈双,并允許獨(dú)立地改變它們的交互责掏。

  • 適用場景:在系統(tǒng)中對象之間存在復(fù)雜的引用關(guān)系,產(chǎn)生的相互依賴關(guān)系結(jié)構(gòu)混亂切難以理解湃望。交互的公共行為换衬,如果需要改變行為則可以增加新的中介者類。

  • 優(yōu)點(diǎn):將一對多轉(zhuǎn)化成了一對一喜爷、降低程序復(fù)雜度冗疮,以及類之間的解耦。

  • 缺點(diǎn):中介者過多檩帐,導(dǎo)致系統(tǒng)復(fù)雜术幔。

  • 相關(guān)設(shè)計(jì)模式:觀察者模式(有時(shí)候會(huì)結(jié)合使用)。

我們引入一個(gè)業(yè)務(wù)場景湃密,我們所有的課程都有一個(gè)學(xué)習(xí)的群诅挑,現(xiàn)在使用的是QQ群,對于學(xué)習(xí)群來說泛源,小伙伴在里面交流的介質(zhì)拔妥。

代碼舉例:

//中介者類
public class StudyGroup {

    public static void showMessage(User user, String message){
        System.out.println(new Date().toString() + " [" + user.getName() + "] : " + message);
    }
}

//用戶類
public class User {
    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public User(String name) {
        this.name = name;
    }

    public void sendMessage(String message) {
        StudyGroup.showMessage(this, message);
    }
}

//測試類
public class Test {
    public static void main(String[] args) {
        User geely = new User("Geely");
        User tom= new User("Tom");

        geely.sendMessage(" Hey! Tom! Let's learn Design Pattern");
        tom.sendMessage("OK! Geely");
    }
    
}

StudyGroup類就是一個(gè)中介者類,里面有一個(gè)showMessage()方法达箍,里面?zhèn)魅雞ser和message没龙,是一個(gè)靜態(tài)方法,接著看User類缎玫,里面有一個(gè)sendMessage()方法硬纤,對于A用戶來說,如果在調(diào)用sendMessage()的時(shí)候赃磨,只和這個(gè)中介者模式打交道就可以了筝家,A用戶發(fā)送了一個(gè)消息,然后交由StudyGroup類也就是中介者來進(jìn)行展示消息邻辉。這就是中介者模式的核心溪王。

中介者模式運(yùn)行結(jié)果


9.責(zé)任鏈模式

  • 定義:為請求創(chuàng)建一個(gè)接收此次請求對象的鏈腮鞍。

  • 適用場景:一個(gè)請求的處理需要多個(gè)對象當(dāng)中的一個(gè)或幾個(gè)協(xié)作處理。

  • 優(yōu)點(diǎn):請求的發(fā)送者和接收者(請求的處理)解耦莹菱,而且責(zé)任鏈也可以動(dòng)態(tài)組合移国。

  • 缺點(diǎn):如果責(zé)任鏈太長或者處理時(shí)間過長,影響性能道伟,責(zé)任鏈有可能過多桥狡。

  • 相關(guān)設(shè)計(jì)模式:狀態(tài)模式。

引入一個(gè)業(yè)務(wù)場景皱卓,也就是說線上的課程在發(fā)布的時(shí)候,經(jīng)過兩個(gè)人批準(zhǔn)部逮,一個(gè)是手記的檢查人娜汁,另一個(gè)是視頻的檢查人。

代碼舉例:

//課程類
public class Course {

    private String name;
    private String article;
    private String Video;
    
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getArticle() {
        return article;
    }

    public void setArticle(String article) {
        this.article = article;
    }

    public String getVideo() {
        return Video;
    }

    public void setVideo(String video) {
        Video = video;
    }

    @Override
    public String toString() {
        return "Course{" +
                "name='" + name + '\'' +
                ", article='" + article + '\'' +
                ", Video='" + Video + '\'' +
                '}';
    }
    
}

//責(zé)任鏈接口
public abstract class Approver {

    protected Approver approver;

    public void setNextApprover(Approver approver){
        this.approver = approver;
    }

    public abstract void deploy(Course course);
}

//手記檢查類
public class ArticleApprover extends Approver {


    @Override
    public void deploy(Course course) {
        if (course.getArticle() != null) {
            System.out.println(course.getName() + "含有手記批準(zhǔn)");
            if (approver != null){
                approver.deploy(course);
            }
        }else {
            System.out.println(course.getName()+"不包含手記兄朋,不批準(zhǔn)掐禁,流程結(jié)束");
            return;
        }
    }
}

//視頻檢查類
public class VideoApprover extends Approver{

    @Override
    public void deploy(Course course) {
        if (course.getVideo() != null) {
            System.out.println(course.getName() + "含有視頻批準(zhǔn)");
            if (approver != null){
                approver.deploy(course);
            }
        }else {
            System.out.println(course.getName()+"不包含視頻,不批準(zhǔn)颅和,流程結(jié)束");
            return;
        }
    }
}

首先創(chuàng)建一個(gè)責(zé)任鏈接口Approver 傅事,里面deploy()主要就是每個(gè)攔截器具體處理的業(yè)務(wù),還有一個(gè)setNextApprover()方法峡扩,這個(gè)方法也是責(zé)任鏈模式的核心方法蹭越,它決定這當(dāng)前攔截器處理完畢后要執(zhí)行的下一個(gè)攔截器的方法,類似數(shù)據(jù)結(jié)構(gòu)的鏈表教届,然后創(chuàng)建了ArticleApprover和VideoApprover類并實(shí)現(xiàn)了Approver接口响鹃,在deploy()方法里面編寫具體實(shí)現(xiàn)的代碼,在執(zhí)行業(yè)務(wù)邏輯后案训,開始判斷是否還有下一個(gè)攔截器买置,如果有,就執(zhí)行下一個(gè)攔截器的業(yè)務(wù)邏輯强霎,如果沒有忿项,則攔截鏈執(zhí)行完畢。

public class Test {
    public static void main(String[] args) {
        Approver artApprover = new ArticleApprover();
        Approver videoApprover = new VideoApprover();

        Course course = new Course();
        course.setName("java");
        course.setArticle("shouji");  //把這行代碼進(jìn)行注釋城舞,artApprover攔截器就會(huì)截止轩触,不會(huì)繼續(xù)往下面執(zhí)行
        course.setVideo("video");

        artApprover.setNextApprover(videoApprover);
        artApprover.deploy(course);
    }
}

在測試類中,artApprover通過setNextApprover()來設(shè)置下一個(gè)要處理的攔截器為videoApprover椿争,當(dāng)artApprover的攔截器處理完畢后就會(huì)執(zhí)行videoApprover攔截器的業(yè)務(wù)邏輯怕膛,但是當(dāng)artApprover的攔截器處理結(jié)果是有問題的,則不會(huì)處理下一個(gè)攔截器秦踪,會(huì)直接終止整個(gè)攔截器鏈褐捻。

責(zé)任鏈模式運(yùn)行結(jié)果


10.訪問者模式

  • 定義:封裝作用于某數(shù)據(jù)結(jié)構(gòu)(如List/Set/Map等)中的各元素的操作掸茅。可以在不改變各元素類的前提下柠逞,定義作用于這些元素的操作昧狮。訪問者模式平時(shí)用的其實(shí)非常少。

  • 適用場景:一個(gè)數(shù)據(jù)結(jié)構(gòu)(如List/Set/Map等)包含很多類型對象板壮,數(shù)據(jù)結(jié)構(gòu)與數(shù)據(jù)操作分離的需求逗鸣。

  • 優(yōu)點(diǎn):增加新的操作很容易,即增加新的訪問者绰精。

  • 缺點(diǎn):增加新的數(shù)據(jù)結(jié)構(gòu)困難撒璧,具體元素變更比較麻煩。

  • 相關(guān)設(shè)計(jì)模式:迭代器模式笨使。

引入一個(gè)業(yè)務(wù)場景卿樱,線上有免費(fèi)課程FreeCourse和實(shí)戰(zhàn)課程CodingCourse,然后對這些課程進(jìn)行遍歷硫椰。

代碼舉例:

//課程抽象類
public abstract class Course {
    private String name;


    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }


    public abstract void accept(IVisitor visitor);

}


//實(shí)戰(zhàn)課程類
public class CodingCourse extends Course {
    private int price;

    public int getPrice() {
        return price;
    }

    public void setPrice(int price) {
        this.price = price;
    }

    @Override
    public void accept(IVisitor visitor) {
        visitor.visit(this);
    }
}

//免費(fèi)課程類
public class FreeCourse extends Course {

    @Override
    public void accept(IVisitor visitor) {
        visitor.visit(this);
    }
}


//訪問者接口
public interface IVisitor {

    void visit(FreeCourse freeCourse);

    void visit(CodingCourse codingCourse);


}   

//訪問者實(shí)現(xiàn)類
public class Visitor implements IVisitor {

    //訪問免費(fèi)課程繁调,打印所有免費(fèi)課程名稱
    @Override
    public void visit(FreeCourse freeCourse) {
        System.out.println("免費(fèi)課程:"+freeCourse.getName());
    }

    //訪問實(shí)戰(zhàn)課程,打印所有實(shí)戰(zhàn)課程名稱及價(jià)格
    @Override
    public void visit(CodingCourse codingCourse) {
        System.out.println("實(shí)戰(zhàn)課程:"+codingCourse.getName()+" 價(jià)格:"+codingCourse.getPrice()+"元");
    }

}

首先定義一個(gè)Course抽象類靶草,具體的業(yè)務(wù)邏輯實(shí)現(xiàn)zeyou則由CodingCourse和FreeCourse來進(jìn)行是實(shí)現(xiàn)蹄胰,具體業(yè)務(wù)邏輯方法是放在accept()方法中,接下來定義一個(gè)訪問者IVisitor接口奕翔,并創(chuàng)建一個(gè)Visitor類來實(shí)現(xiàn)和這個(gè)訪問者接口裕寨,這里需要注意一下,如果需要新的訪問接口糠悯,就可以直接在IVisitor接口中進(jìn)行定義帮坚,具體的展示都是在Visitor里實(shí)現(xiàn)的方法來具體實(shí)現(xiàn)。

public class Test {
    public static void main(String[] args) {
        List<Course> courseList = new ArrayList<>();

        FreeCourse freeCourse = new FreeCourse();
        freeCourse.setName("SpringMVC數(shù)據(jù)綁定");

        CodingCourse codingCourse = new CodingCourse();
        codingCourse.setName("Java設(shè)計(jì)模式精講 -- By Geely");
        codingCourse.setPrice(299);

        courseList.add(freeCourse);
        courseList.add(codingCourse);

        for(Course course : courseList){
            course.accept(new Visitor());
        }

    }
}

在測試類中互艾,最后的循環(huán)那里需要一個(gè)訪問者试和,具體的實(shí)現(xiàn)都是在這個(gè)類里面了,應(yīng)用層就無需在糾結(jié)具體的業(yè)務(wù)邏輯的實(shí)現(xiàn)纫普。

訪問者模式運(yùn)行結(jié)果


11.狀態(tài)模式

  • 定義:允許一個(gè)對象在其內(nèi)部狀態(tài)改變時(shí)阅悍,改變它的行為。

  • 適用場景:一個(gè)對象存在多個(gè)狀態(tài)(不同狀態(tài)下行為不同)昨稼,且狀態(tài)可相互轉(zhuǎn)換节视。

  • 優(yōu)點(diǎn):將不同的狀態(tài)隔離,把各種狀態(tài)的轉(zhuǎn)換邏輯假栓,分不到State的子類中寻行,減少相互依賴。增加新的狀態(tài)非常簡單匾荆。

  • 缺點(diǎn):狀態(tài)多的業(yè)務(wù)場景導(dǎo)致數(shù)目增加拌蜘,系統(tǒng)變復(fù)雜杆烁。

  • 相關(guān)設(shè)計(jì)模式:享元模式

引入一個(gè)業(yè)務(wù)場景,就是網(wǎng)站的課程視頻简卧,有暫停兔魂、播放、快進(jìn)和停止举娩,在停止的時(shí)候是無法快進(jìn)的析校。所以如果是停止的狀態(tài),在轉(zhuǎn)換成快進(jìn)的時(shí)候要做一個(gè)校驗(yàn)铜涉。

代碼舉例:

//視頻上下文類
public class CourseVideoContext {

    private CourseVideoState courseVideoState;
    public final static PlayState PLAY_STATE = new PlayState();
    public final static StopState STOP_STATE = new StopState();
    public final static PauseState PAUSE_STATE = new PauseState();
    public final static SpeedState SPEED_STATE = new SpeedState();

    public CourseVideoState getCourseVideoState() {
        return courseVideoState;
    }

    public void setCourseVideoState(CourseVideoState courseVideoState) {
        this.courseVideoState = courseVideoState;
        this.courseVideoState.setCourseVideoContext(this);
    }

    public void play(){
        this.courseVideoState.play();
    }

    public void speed(){
        this.courseVideoState.speed();
    }

    public void stop(){
        this.courseVideoState.stop();
    }

    public void pause(){
        this.courseVideoState.pause();
    }
}

//視頻狀態(tài)類
public abstract class CourseVideoState {

    protected CourseVideoContext courseVideoContext;

    public void setCourseVideoContext(CourseVideoContext courseVideoContext) {
        this.courseVideoContext = courseVideoContext;
    }

    public abstract void play();
    public abstract void speed();
    public abstract void pause();
    public abstract void stop();

}

首先創(chuàng)建了一個(gè)CourseVideoContext類智玻,這是這個(gè)設(shè)計(jì)模式的核心類,里面持有了四個(gè)狀態(tài)的實(shí)例和一個(gè)CourseVideoState類芙代,getCourseVideoState()方法為獲取視頻的當(dāng)前狀態(tài)尚困,setCourseVideoState()為設(shè)置視頻的狀態(tài)。

//暫停類
public class PauseState extends CourseVideoState {

    @Override
    public void play() {
        super.courseVideoContext.setCourseVideoState(CourseVideoContext.PLAY_STATE);
    }

    @Override
    public void speed() {
        super.courseVideoContext.setCourseVideoState(CourseVideoContext.SPEED_STATE);
    }

    @Override
    public void pause() {
        System.out.println("暫停播放課程視頻狀態(tài)");
    }

    @Override
    public void stop() {
        super.courseVideoContext.setCourseVideoState(CourseVideoContext.STOP_STATE);
    }
}

//播放類
public class PlayState extends CourseVideoState {

    @Override
    public void play() {
        System.out.println("正常播放課程視頻狀態(tài)");
    }

    @Override
    public void speed() {
        super.courseVideoContext.setCourseVideoState(CourseVideoContext.SPEED_STATE);
    }

    @Override
    public void pause() {
        super.courseVideoContext.setCourseVideoState(CourseVideoContext.PAUSE_STATE);
    }

    @Override
    public void stop() {
        super.courseVideoContext.setCourseVideoState(CourseVideoContext.STOP_STATE);
    }
}


//停止類
public class StopState extends CourseVideoState {
    @Override
    public void play() {
        super.courseVideoContext.setCourseVideoState(CourseVideoContext.PLAY_STATE);
    }

    @Override
    public void speed() {
        System.out.println("ERROR 停止?fàn)顟B(tài)不能快進(jìn)!!");
    }

    @Override
    public void pause() {
        System.out.println("ERROR 停止?fàn)顟B(tài)不能暫停!!");
    }

    @Override
    public void stop() {
        System.out.println("停止播放課程視頻狀態(tài)");
    }
}


//快進(jìn)類
public class SpeedState extends CourseVideoState {
    @Override
    public void play() {
        super.courseVideoContext.setCourseVideoState(CourseVideoContext.PLAY_STATE);
    }

    @Override
    public void speed() {
        System.out.println("快進(jìn)播放課程視頻狀態(tài)");
    }

    @Override
    public void pause() {
        super.courseVideoContext.setCourseVideoState(CourseVideoContext.PAUSE_STATE);
    }

    @Override
    public void stop() {
        super.courseVideoContext.setCourseVideoState(CourseVideoContext.STOP_STATE);
    }
}
//測試類
public class Test {
    public static void main(String[] args) {

        CourseVideoContext courseVideoContext = new CourseVideoContext();
        courseVideoContext.setCourseVideoState(new PlayState());

        System.out.println("當(dāng)前狀態(tài):"+courseVideoContext.getCourseVideoState().getClass().getSimpleName());
        courseVideoContext.pause();

        System.out.println("當(dāng)前狀態(tài):"+courseVideoContext.getCourseVideoState().getClass().getSimpleName());

        courseVideoContext.speed();

        System.out.println("當(dāng)前狀態(tài):"+courseVideoContext.getCourseVideoState().getClass().getSimpleName());

        courseVideoContext.stop();

        System.out.println("當(dāng)前狀態(tài):"+courseVideoContext.getCourseVideoState().getClass().getSimpleName());


        courseVideoContext.speed();

    }
}

在測試類中链蕊,創(chuàng)建了一個(gè)CourseVideoContext實(shí)例,然后通過setCourseVideoState()方法設(shè)置視頻狀態(tài)為PlayState谬泌,然后可以通過getCourseVideoState()來獲取當(dāng)前視頻的狀態(tài)滔韵。也可以直接調(diào)用courseVideoContext類里的方法去改變狀態(tài)。

狀態(tài)模式運(yùn)行結(jié)果

參考

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末掌实,一起剝皮案震驚了整個(gè)濱河市陪蜻,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌贱鼻,老刑警劉巖宴卖,帶你破解...
    沈念sama閱讀 211,817評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異邻悬,居然都是意外死亡症昏,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,329評論 3 385
  • 文/潘曉璐 我一進(jìn)店門父丰,熙熙樓的掌柜王于貴愁眉苦臉地迎上來肝谭,“玉大人,你說我怎么就攤上這事蛾扇∪林颍” “怎么了?”我有些...
    開封第一講書人閱讀 157,354評論 0 348
  • 文/不壞的土叔 我叫張陵镀首,是天一觀的道長坟漱。 經(jīng)常有香客問我,道長更哄,這世上最難降的妖魔是什么芋齿? 我笑而不...
    開封第一講書人閱讀 56,498評論 1 284
  • 正文 為了忘掉前任腥寇,我火速辦了婚禮,結(jié)果婚禮上沟突,老公的妹妹穿的比我還像新娘花颗。我一直安慰自己,他們只是感情好惠拭,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,600評論 6 386
  • 文/花漫 我一把揭開白布扩劝。 她就那樣靜靜地躺著,像睡著了一般职辅。 火紅的嫁衣襯著肌膚如雪棒呛。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,829評論 1 290
  • 那天域携,我揣著相機(jī)與錄音簇秒,去河邊找鬼。 笑死秀鞭,一個(gè)胖子當(dāng)著我的面吹牛趋观,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播锋边,決...
    沈念sama閱讀 38,979評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼皱坛,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了豆巨?” 一聲冷哼從身側(cè)響起剩辟,我...
    開封第一講書人閱讀 37,722評論 0 266
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎往扔,沒想到半個(gè)月后贩猎,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,189評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡萍膛,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,519評論 2 327
  • 正文 我和宋清朗相戀三年吭服,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片蝗罗。...
    茶點(diǎn)故事閱讀 38,654評論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡噪馏,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出绿饵,到底是詐尸還是另有隱情欠肾,我是刑警寧澤,帶...
    沈念sama閱讀 34,329評論 4 330
  • 正文 年R本政府宣布拟赊,位于F島的核電站刺桃,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏吸祟。R本人自食惡果不足惜瑟慈,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,940評論 3 313
  • 文/蒙蒙 一桃移、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧葛碧,春花似錦借杰、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,762評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至乳绕,卻和暖如春绞惦,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背洋措。 一陣腳步聲響...
    開封第一講書人閱讀 31,993評論 1 266
  • 我被黑心中介騙來泰國打工济蝉, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人菠发。 一個(gè)月前我還...
    沈念sama閱讀 46,382評論 2 360
  • 正文 我出身青樓王滤,卻偏偏與公主長得像,于是被迫代替她去往敵國和親滓鸠。 傳聞我的和親對象是個(gè)殘疾皇子淑仆,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,543評論 2 349

推薦閱讀更多精彩內(nèi)容

  • 下面總結(jié)設(shè)計(jì)模式中的行為型模式: 1.責(zé)任鏈模式 顧名思義,責(zé)任鏈模式(Chain of Responsibili...
    Steven1997閱讀 3,446評論 0 1
  • Swift1> Swift和OC的區(qū)別1.1> Swift沒有地址/指針的概念1.2> 泛型1.3> 類型嚴(yán)謹(jǐn) 對...
    cosWriter閱讀 11,092評論 1 32
  • 創(chuàng)建型模式 工廠模式 工廠模式(Factory Pattern)是 Java 中最常用的設(shè)計(jì)模式之一哥力。這種類型的設(shè)...
    liuyang7519閱讀 324評論 0 2
  • 創(chuàng)建型模式 工廠模式 工廠模式(Factory Pattern)是 Java 中最常用的設(shè)計(jì)模式之一。這種類型的設(shè)...
    隔墻送來秋千影閱讀 2,662評論 0 11
  • 題記: 現(xiàn)在我已經(jīng)身處國外墩弯,可我仍舊忘記不了她—我的母親吩跋。 讀完朱自清的散文我這才明白母親有多么的偉大,我也有這樣...
    顧?quán)拍?/span>閱讀 333評論 0 0