[笔记]设计模式简要总结

用途

软件工程中总会遇到重复出现的问题,某些可复用的成功经验,就可以抽象为模式,在设计方面,就是设计模式。
设计模式不仅是针对某个需求的,更多是为了应对需求变更的,在修改代码以满足需求变更时,如何能提高可读性、降低工作量、不干扰无关业务等,就是设计模式的目标。
没有万能的设计模式,只有特定条件下为一些重复问题提供的合理解决方案。

6个设计原则

迪米特法则:最少知道法则,一个对象应该对其他对象有最少的了解
以及5个常被统称为SOLID原则:
单一职责:类的职责单一,不要上帝类
开放封闭:允许扩展,不允许修改
里氏替换:子类可以替换父类,所以我们用基类书写逻辑,在运行时再确定子类
接口隔离:不要大接口,用多个接口,且多个接口间应该是各自独立的角色
依赖倒置:就是面向接口编程,不应依赖具体而应依赖抽象,尽量用接口和抽象类解耦合
此外,还有一种合成复用原则:尽量组合对象,少用类的继承,减少耦合,维护封装

23种设计模式

Java 中一般认为有23 种设计模式,总体来说设计模式分为三大类:
创建型模式,共五种:工厂方法模式、抽象工厂模式、单例模式、建造者模式
原型模式。
单例模式主要考虑线程安全性和懒加载的问题,现在主要用静态内部类实现。
建造者模式主要依靠Director类持有的Builder类实例来返回Product对象,Product和Director也可以是一个类。
原型模式本质是通过clone对象内存复制一个对象实例出来,所以他与工厂模式是互斥的。
结构型模式,共七种:适配器模式、桥接模式、装饰器模式、代理模式、外观模式、组合模式、享元模式。
适配器是在不修改原类的前提下,让它能在新的接口中使用。
适配器主要分为类适配器(extends A implements B)和对象适配器(implements B),前者靠继承,后者靠构造注入对象
适配器里还有一种接口适配器,主要作用是可以只实现接口中的一部分函数,比如AnimatorListenerAdapter就可以用来避免实现AnimatorListener的所有函数。
对象适配器和桥接模式很相似,但适配器是为了让两个接口配合,而桥接是为了拆分成不同纬度
装饰和静态代理很相似,但意图和语义是相反的,装饰是为了动态增加功能;代理则是为了控制访问。
外观和代理的区别是外观代表一个子系统,而不是一个单一对象。
装饰模式与代理模式的区别(转载)
装饰者,适配器,代理和外观模式的区别
行为型模式,共十一种:策略模式、模板方法模式、命令模式、访问者模式、状态模式、观察者模式、迭代器模式、责任链模式、备忘录模式、中介者模式、解释器模式。
策略模式容易联想起装饰者模式,但是装饰者模式要求构造传参的是自己的兄弟类实例,策略模式是其他的业务类实例
策略模式和模板模式都是更换算法,但策略是整个更换,模板是保留算法框架,只更换部分细节函数。
策略模式和访问者模式很相似,不过策略是通过构造注入或属性注入传入业务的策略对象,访问者是在函数调用时传入业务的访问者对象,而且访问者会再回来调用元素。
策略模式和状态模式很相似,不过策略模式里是由调用者更换策略,而状态模式是在业务处理过程中,由状态类(或环境类)里自动切换状态的。
命令模式和状态模式很相似,但命令是把发送者和接收者解耦,接收者之间没有关系,有时候不要接收者,直接在命令里做业务;状态模式是为了切换状态,状态之间是可以切换的,而且最终还是在环境类里做业务。
命令模式像建造者模式中Director类和Product类分开的情况,访问者模式像Director类和Product类是一个类的情况。不过命令模式和访问者模式里处理的是抽象类。

*5种创建型模式

工厂模式

工厂模式也分为简单工厂(用if else提供多产品)、工厂(每种产品一个工厂)、抽象工厂(每个工厂提供多个流水线,流水线提供最终产品)

单例模式

单例模式主要考虑这几个因素:
1.延迟加载
2.线程安全
3.性能损耗
所以,现在比较好的写法是使用静态内部类或枚举来实现
单例模式的几种写法和各自优势

建造者模式

用一个Director去引用基础Builder对象,在扩展的ConcreteBuilder中实现建造方法,最终得到一个Product对象。
AlertDialog、Glide、Retrofit等都使用了建造者模式
优点
建造过程和使用过程是分离的
很容易修改Product
缺点
建造过程没有封闭,在调用者那里是可见的

原型模式

原型模式主要是在内存中直接复制一个对象

abstract class ProtoType implements Cloneable{
    String a1;
    int a2;
    public abstract ProtoType clone();
}

其实就是通过实现Cloneable接口,实现clone内存对象。
原型模式对于基本类型容易实现,但对于复杂的引用类型,还需要设法实现深拷贝。

*7种结构性模式

适配器

适配器可以在两个对象之间扩展出一种联系,调用对象A的方法a,实际执行的是对象B的方法b,同时A和B都不需要做改动。
适配器的优势是开放封闭原则好,原始类不需要改动
缺点是代码可读性差,看代码是A接口,实际实现却是B的方法,系统结构零乱,不容易理解。
适配器分为类适配器和对象适配器。
类适配器
对象A和B中,有一方为接口的情况下,可以利用类的继承关系,适配器继承类B,扩展接口A,在初始化A对象时,返回一个Adapter实例,该实例执行A的方法a时,在a内部调用父类B的方法b,实现适配器。
对象适配器
对象A和B中,均为类的情况下,因为类不能多继承,就需要利用引用关系,适配器继承类A,引用一个类B的实例对象,在初始化A对象时,返回一个Adapter实例,该实例执行A的方法a时,在a内部通过类B的实例对象调用方法b,实现适配器。

桥接模式

在抽象类里引用另外一个业务维度的接口,好像一座桥把两个业务维度连接起来,这样可以实现多继承。

abstract class IShape {
    protected IColor color;
    public IShape(IColor color) {
        this.color = color;
    }
    abstract void operation();
}

优先
满足单一职责的同时,部分实现多继承
把抽象和实现分离开,两个维度中任意扩展都不需要修改原系统
缺点
设计人员需要准确抓出两个独立维度,这不容易做到
在抽象层实现的聚合,不利于可读性和设计难度

装饰器模式

Decorator实际上是一层层的引用嵌套,其实就是在继承了同一个基类/接口的两个类中,把其中一个基础类的实例封装为基类/接口,(构造传参)传给另一个装饰类的实例,另一个类通过引用基础类,在接口函数中调用基础类的函数,再增加一些装饰功能。都要作为基类/接口来调用函数。
java.io就是典型的装饰者模式,InputStreamReader和BufferReader都是Reader,但是BufferReader通过装饰InputStreamReader扩展了功能。
Android里的Context也是一种典型的装饰者模式,所有的contextwrapper都是用contextimpl去做context业务的。
优点
用引用代替继承,类的关系更加灵活自由,不会出现子类爆炸
可以在运行过程中动态装饰,不用修改代码
缺点
装饰层次太深的话,会影响效率
适合改变外部表现,不适合改变内部,如果要改变内部,应该用策略模式

代理模式

代理分为动态代理和静态代理两种。
静态代理 以类为单位进行操作
我有一个接口IBiz,业务类BizA实现了接口函数,如果业务变动,希望在函数前后增加点逻辑,为了不修改业务类BizA,我们就做一个BizB的类,实现IBiz接口,并引用BizA,在实现的接口函数里,调用BizA的函数,并且在BizA的函数前后增加逻辑处理。
在调用的时候,我只要IBiz的实例,实际上创建一个BizB的实例,并给BizB传一个BizA的实例作为参数,这样,我用IBiz去发起调用,实际执行的是BizB的函数,在BizB执行函数过程中,会执行BizA的函数。实际上是BizB代理了BizA的业务,这就是代理模式。
因为BizB对BizA的代理是写死在BizB的代码里的,所以叫静态代理。
静态代理的问题在于,对每一个要扩展的业务类,虽然扩展内容一样,但是对每个类都要做一个对应的代理类,用工厂模式去生产。
静态代理和装饰模式的代码结构是一样的,但是使用目的不同。
JDK动态代理 以函数为单位进行操作
为了在代码中根据业务需要,动态地为函数添加逻辑,Java提供了动态代理机制。
动态代理是借助反射来实现的,核心是用java.lang.reflect的Proxy.newProxyInstance动态创建代理类,再用InvocationHandler去重写invoke函数,它其实分为四步:
1.定义好调用处理器
实现InvocationHandler接口,做一个函数调用处理器,编写要扩展的逻辑。因为要对被代理类进行扩展,所以需要把被代理类封装为Object传进来(构造函数或bind函数传入)
2.创建动态代理类
用反射的Proxy创建动态代理,需要被代理类的ClassLoader,以及这个被代理类的所有接口。(所以,要使用动态代理,就必须有对应的接口定义)
3.创建对应的构造函数
用反射获取动态代理类的Constructor构造函数,需要用InvocationHandler作为参数。
4.构造出动态代理类的实例
用构造函数new一个实例,把第1步中的函数调用处理器作为参数传入。
生成的动态代理类实现接口,接口函数实际上调用了函数调用处理器的invoke方法,在invoke方法中利用反射调用了被代理类的方法。
2、3、4步其实在Proxy中是newProxyInstance一个函数。

final Star star = new SuperStar();
        Star st = (Star) Proxy.newProxyInstance(Star.class.getClassLoader(), star.getClass().getInterfaces(), new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args)
                    throws Throwable {
                System.out.println("before---------");
                Object object = method.invoke(star, args);
                System.out.println("after---------");
                return object;
            }
        });
        st.singSong();

CGLib动态代理 修改字节码的方式
CGLibs在代码编写上和InterceptionHandler的实现类很像,它使用MethodInterceptor,并在intercept中实现逻辑扩展,不同的是,CGLib不需要通过接口实现。
但是Android不支持CGLib动态代理,因为android类文件和jdk类文件不一样(CGLib针对.class文件,Android的是优化后的.dex文件)
Java 动态代理作用是什么
彻底理解JAVA动态代理

外观模式

为复杂的子系统提供一个简单的接口,调用者直接访问Facade外观角色,Facade去调用子系统,但同时子系统也无需知道Facade外观角色。
优势
调用者不用关心子系统,而且用起来更容易
调用者和子系统互相不需要知道,松耦合
大型项目不再受子系统的编译、修改、移植的影响
缺点
用户仍可以直接访问子系统,不能屏蔽
子系统修改时,Facade和调用者有可能都要修改,违反开闭原则

组合模式

典型案例就是Android中View+ViewGroup的结构
优点
分层次的复杂对象可以清晰的定义和组合出来
仅靠leaf和composit两种构件,就可以递归组合成复杂树形结构
维护旧构件、扩展新构件很方便,调用方不用修改代码
调用者使用简单,整个组合结构或单个对象都可以一致地使用
缺点
对设计人员来说,如果业务规则很复杂,就很难实现,特别是composit构件很难focus在对leaf的处理

享元模式

为了减少对象的使用,FlyWeight享元模式可以共享相同或相似的对象,实现重用。
用一个Factory去提供享元对象,Factory里用Map管理和提供所有对象,如果要的对象在Map里已有,就提供重复对象。
享元模式里除了作为父类的抽象对象抽象享元,有单纯享元和复合享元两种:
单纯享元
享元全是内部状态,整个都可以共享。
复合享元
对象是composite复合对象,不能共享,需要从中剥离出单纯享元,仅对单纯享元共享。

//复合对象本身不能共享
class ConcreteCompositeFlyweight extends Flywight {
    Map<String, Flywight> list = new HashMap<>();//单纯享元,可以共享
    public void add(String state, Flywight flywight) {
        list.put(state, flywight);
    }
    @Override
    void operation(String externalState) {
        for (Map.Entry<String, Flywight> data : list.entrySet()) {
            data.getValue().operation(externalState);
        }
    }
}
class FlyweightFactory {
    HashMap<String, Flywight> map = new HashMap<>();
    public Flywight getFlyweight(List<String> states) {
        ConcreteCompositeFlyweight ccFlyweight = new ConcreteCompositeFlyweight();
        for (String state : states)
            ccFlyweight.add(state, getFlyweight(state));//复合对象中的单纯享元,使用享元模式
        return ccFlyweight;
    }
    public Flywight getFlyweight(String state) {
        Flywight flywight = map.get(state);
        if (flywight == null) {
            flywight = new ConcreteFlyweight(state);
            map.put(state, flywight);
        }
        return flywight;
    }
}

优点
大幅降低内存中重复对象的数量
缺点
系统更复杂
不能共享的外部状态会导致一定的性能损耗

*11种行为型模式

策略模式

实现算法的封装与切换

class Context {  
    private AbstractStrategy strategy; //维持一个对抽象策略类的引用  
    public void setStrategy(AbstractStrategy strategy) { //注入策略实例
        this.strategy= strategy;  
    }  
    public void algorithm() {  
        strategy.algorithm();  //调用策略类中的算法  
    }  
} 

其实就是通过各种方式(构造函数注入、set注入、反射+配置文件)等方式,动态调整策略实例
优点
满足开闭原则
可以替换继承关系,更灵活
避免长长的if else
缺点
会产生很多细小的策略类
调用者必须知道所有的策略
无法同时使用多个策略

模板方法

模板方法其实使用了多态的特性,通过具体方法和抽象方法的混合使用,在父类中处理算法的主要框架,但是用到的某些细节函数不在父类中实现,而是在子类中实现。
结合配置文件+反射,就能实现动态配置算法模板。
钩子方法
有一些特殊的模板方法,是在父类中做一些返回boolean值的函数,子类通过修改这些函数的返回值,就能控制业务逻辑的分支,这种做法叫做钩子方法。
优点
算法代码复用
不会改变算法模板的框架,执行次序都是模板决定的。
通过更换子类更换具体实现,符号单一职责和开闭。
采用钩子方法,能实现子类对父类的反向控制
缺点
如果模板中可更换的点很多,会导致子类出现很多,有时候要考虑改成桥接模式,减少子类。

命令模式

其实就是把请求封装起来,实现在发送者和接收者之间解耦,命令引用接收者,发送者引用命令,所以发送者和接收者之间是解耦的

Receiver receiver = new Receiver();//接收者真正处理业务,但谁也不引用
Command command = new ConcreteCommand(receiver);//命令引用接收者
Invoker invoker = new Invoker(command);//发送者引用命令
invoker.doInvokerAction();//trigger

请求命令作为对象,有很多可以操作的点。
可以把命令参数化注入,为发送者的参数注入不同的具体命令,就能让不同的接收者来处理
可以把命令排入队列,实现缓存和排序处理
可以撤销命令,就是在请求命令中执行一个相反的操作,如果使用命令集合,就能多次撤销。
可以序列化后储存起来,反序列化后再次执行操作
组合命令,命令模式和组合模式混用
就是在外层命令里维护一个命令列表,外层命令的一次执行,会遍历执行命令列表,实现对命令的批处理
优点
发送者与接收者解耦
容易增加新命令
容易实现队列、撤销、日志等操作
缺点
不能减少类的数量
可能出现大量具体命令类

访问者模式

其实就是在待处理的元素中,选择一个访问者,作为处理自己的业务类,这样可以通过更换访问者,更换对元素的处理方式

abstract class Visitor{  //访问者访问不同方法
    public abstract void visit(ConcreteElementA elementA);  
    public abstract void visit(ConcreteElementB elementB); 
...
class ConcreteElementA implements Element{ 
    public void accept(Visitor visitor)  {  //元素里选择不同的访问者
        visitor.visit(this);  //由访问者处理自己
    } 

访问者模式一般是在一个数据集合中遍历处理元素时使用。
双重分派
首先给元素的accept函数传参visitor
然后,给visitor的visit函数传参Element元素自己
最后,在visit函数里,还可以调用Element元素自己的函数
这就是双重分派
组合访问者
一般在处理元素时,使用迭代器来遍历地处理元素,如果元素分为两种,一种是leaf,一种是composite,在composite里继续遍历,就是访问者+组合模式
优点
对元素的处理抽象、封装为访问者,不是散落在元素里,单一职责,而且元素的复用性更好
扩展元素操作时,容易通过增加新的访问者,实现对元素的新的处理方法,符合开闭原则
缺点
难以增加新元素,不符合开闭,因为抽象访问者类要增加对应的方法
破坏迪米特,访问者需要知道元素的一些内部操作

状态模式

可以在环境类里动态更换状态类,环境类写的业务函数,是在状态类中调用的,所以动态更换状态类,就是动态更换业务行为
环境类引用状态类,抽象状态类引用环境类,当环境类做操作时,调用状态类的操作,状态类一方面反调环境类的业务操作,另一方面检查状态变化,为环境类更换状态类(或者不在状态类切换,而是在环境类切换)

//环境类
class Account {  
    private AccountState state; //维持一个对抽象状态对象的引用  
    public void withdraw(double amount) {  
        state.withdraw(amount); //调用状态对象的业务方法
    public void setBalance(int i){//真正的业务方法
        setState(new OtherState()) //(1.在环境类里切换状态)
...
//抽象状态类  
abstract class AccountState {  
    protected Account acc; 
...
//正常状态:具体状态类  
class NormalState extends AccountState {  
    public NormalState(Account acc) {  
    public void withdraw(double amount) {  //状态类的业务方法
        acc.setBalance(acc.getBalance() - amount); //仍然用环境类的方法
        stateCheck(); //检查状态变换(2.或者在状态类里切换状态)
    }   
    public void stateCheck() {  //状态转换
        if (acc.getBalance() > -2000 && acc.getBalance() <= 0) {  
            acc.setState(new OverdraftState(this));  
        } 

共享状态
如果同一个环境类的多个不同实例要共享状态,可以把多个状态定义为static对象,一个环境实例更换状态,其他实例也全部更换(更换时要使用环境类里的静态对象)
优点
把状态转换的规则抽离、封装、集中管理
状态行为全放进状态类里,通过设置不同状态,就能设置环境类的行为
避免使用庞大的条件语句
共享状态,减少对象
缺点
增加了类和对象
提升了系统复杂度,容易混乱
不符合开闭原则,增加新状态类,需要修改状态转换代码;修改旧状态类,需要修改状态类代码

观察者模式

核心思想是封装一批Observer对象,放进Observable对象的订阅队列里(注册),当Subject对象发生变化时,在notify函数里遍历地调用所有Observer对象的update方法(通知)。
Android中ListView在更新数据时刷新界面,就是使用了观察者模式,setAdapter时,会为传入的Adapter注册一个DataSetObserver(是一个AdapterView的子类AdapterDataSetObserver),当Adapter的数据变化时,这个observer就会去更新数据,更新当前显示列表项,更新焦点、刷新layout等。
基于观察者的委派事件模型
Java事件处理有三个要素:事件源对象、事件对象和事件处理对象。
把事件处理对象(eventlistener)注册到事件源对象,事件源对象把event事件委派给listener,实际上是个一对一的观察者模式
优势
在观察者和被观察者之间解耦(只维持抽象集合)
可以借此分离表示层和业务逻辑层
可以建立一个触发链
缺点
通知所有订阅者,有性能损耗
update函数会传递Observable对象,如果观察者借此引用了被观察者的某些特性,就可能需要修改观察者的代码,破坏开闭原则。

迭代器模式

其实就是把一批聚合对象封装为Iterator对象,迭代器iterator里用cursor游标实现对聚合对象的依次访问,然后在一个聚合类里把原始聚合数据如List列表变成Iterator对象。有时候迭代器是聚合类的内部类。

public abstract class AbstractList<E> extends AbstractCollection<E> implements List<E> {  
    private class Itr implements Iterator<E> {  
        int cursor = 0;  
        ......  
} 

优点
遍历从聚合类中剥离,很容易更换聚合类
只要实现Collection接口,就能实现迭代器模式,简化聚合类的开发
通过抽象层实现新的迭代器和聚合类,符合开闭原则
缺点
抽象迭代器很重要,但很难平衡性能和功能
新的聚合类不能自己实现遍历,可能需要新的迭代器,多需要一个类

责任链模式

其实就是一串Handler组成一个链,每个决定自己处理或者传递给下一个角色处理,责任链的每一环只能处理或不处理,不允许处理一部分再继续传递。
优点
可以动态地组织和分配责任
简化对象的相互连接,只要记住下一个,不需要记住全链路
缺点
不追踪处理结果,可能没有处理
链过长会影响性能,且调试不便

备忘录模式

其实就是在一个数据管理类中,管理Memento备忘数据(保存对象的历史状态),发起人只引用了Memento类,但不管理备忘数据,而是通过CareTaker数据管理类实现保存和恢复

caretaker.setMemento(originator.createMemento()); //向备忘录存数据
originator.restoreMemento(caretaker.getMemento()); //从备忘录取数据

如果要实现多状态多备份,就在Memento里维护一个map实现多状态,在CareTaker里维护一个map实现多数据。
优点
发起人不需要管理备份状态
缺点
备忘录对象和备忘录管理对象会消耗大量内存

中介者模式

其实就是把网状的交互抽象为星型的,让Mediator中介来统一负责交互,从多对多变成一对多,从而符合迪米特法则。
Mediator会引用每个Component组件,每个Component组件也引用Mediator中介,这样组件通过调用中介,中介再与其他组件交互。
优点
网状对象解耦
简化对象交互
在改变行为时,改变一个中介类,优于扩展大量的组件类
缺点
组件过多时,中介类会演变的非常复杂

解释器模式

就是用来创建和扩展自己的文法规则的,它是用类来解析文法的,解析基本分两部分interpret解释命令+execute执行命令
解释器模式在解析XML文件、正则表达式等场景中使用较多

String text = "LOOP 2 PRINT 杨过 SPACE SPACE PRINT 小龙女 BREAK END PRINT 郭靖 SPACE SPACE PRINT 黄蓉";  //重复处理的特定规则的语法文本
Context context = new Context(text);  //语法文本放进环境类,逐个解释处理
Node node = new ExpressionNode();  //把语法元素都转换为Node,遍历地+递归地解释处理
node.interpret(context);//解释为命令
node.execute(); //执行命令

其实就是用一个环境类,把要解析的文法放到环境类里,逐个解析文法中的内容,能逐个处理语法文本中的元素。
然后用一组文法解析类去处理,比如首先用一个ExpressionNode,把文法中的每个内容都包装为CommandNode,相当于把原始语言加载为解释器认识的Node列表。
然后每个CommandNode中分别处理递归命令和具体命令,比如语法中的Loop循环就交给专门的LoopNode处理(Loop中递归地交给ExpressionNode处理),具体命令交给PrimitiveNode处理
优点
能够方便地实现简单的语言
增加语言规则时,增加对应的表达式类即可,符合开闭原则
缺点
需要先把重复出现的问题抽象为语言,并建立抽象语法树
对于复杂文法,每条规则一个类,会类爆炸
大量循环和递归,导致效率低

引用

从Android代码中来记忆23种设计模式
史上最全设计模式导学目录(完整版)
设计模式汇总:创建型模式
设计模式汇总:结构型模型(上)
设计模式汇总:结构型模型(下)
设计模式总结之行为型模式

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,189评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,577评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,857评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,703评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,705评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,620评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,995评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,656评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,898评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,639评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,720评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,395评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,982评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,953评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,195评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,907评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,472评论 2 342

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,594评论 18 139
  • 设计模式汇总 一、基础知识 1. 设计模式概述 定义:设计模式(Design Pattern)是一套被反复使用、多...
    MinoyJet阅读 3,897评论 1 15
  • 工厂模式类似于现实生活中的工厂可以产生大量相似的商品,去做同样的事情,实现同样的效果;这时候需要使用工厂模式。简单...
    舟渔行舟阅读 7,717评论 2 17
  • 设计模式基本原则 开放-封闭原则(OCP),是说软件实体(类、模块、函数等等)应该可以拓展,但是不可修改。开-闭原...
    西山薄凉阅读 3,748评论 3 13
  • 春日偶成 程颢(宋) 云淡风轻近午天,傍花随柳...
    书嫄_九数解读师阅读 416评论 0 0