Java 十一种设计模式深入理解

                                  `话不多说直奔主题。`
action.png

目录
一、工厂设计模式
二、抽象工厂模式
三、单例设计模式
四、建造者(Builder)模式
五、原型模式
六、适配器设计模式
七、桥接(Bridge)设计模式
八、责任链模式
九、迭代器设计模式
十、观察者模式
十一、策略设计模式


一、工厂设计模式

在工厂设计模式中,我们没有把创建对象暴露给客户端,而是通过接口的形式创建引入新的对象。接下来我将创建一个Product接口,写ABC三种产品类 实现接口,它们将会把信息传递给ProductFactory,通过ProductFactory来根据情况获取产品。

  • 1.1 创建一个接口
    Product.java
public interface Product {
    void product();
}
  • 1.2 创建ABC三种产品类 只写一个A,BC同理。实现Product接口
    ProductImplA.java
public class ProductImplA implements Product {
    @Override
    public void product() {
        System.out.println("this is ProductImplA");
    }
}
  • 1.3 创建工厂类
    ProductFactory.java 根据工厂指定的类型,生成对象。
public class ProductFactory {
    public Product getProduct(String productType) {
        if (TextUtils.isEmpty(productType)) {
            return null;
        }
        if ("A".equals(productType)) {
            return new ProductImplA();
        } else if ("B".equals(productType)) {
            return new ProductImplB();
        } else if ("C".equals(productType)) {
            return new ProductImplC();
        }
        return null;
    }
}
  • 1.4 使用工厂,通过传递的信息获取具体类的信息
private void FactoryDemo() {
        ProductFactory productFactory = new ProductFactory();
        productFactory.getProduct("A").product();
        productFactory.getProduct("B").product();
        productFactory.getProduct("C").product();
    }

-1.5 验证信息

I/System.out: this is ProductImplA
I/System.out: this is ProductImplB
I/System.out: this is ProductImplC

二、抽象工厂模式

抽象工厂是一个大厂,用来创建其他工厂,可以理解为工厂的工厂。

接下来我将创建两个小厂子Product与Color,与(一)工厂设计模式一样,接口并实现ABC。之后创建一个抽象工厂类AbstractFactory,将ProductFactory和ColorFactory定义成自扩展的AbstractFactory,之后在创建 工厂创建者FactoryProducer。

  • 2.1 照着(一)工厂设计模式写个Color,Product工厂直接拿来用。
    创建一个接口Color.java
public interface Color {
    void color();
}
  • 2.2 创建ABC三种产品颜色,只写个A,BC同理 实现Color接口
    ColorImplA.java
public class ColorImplA implements Color {
    @Override
    public void color() {
        System.out.println("class ColorImplA , method color");
    }
}
  • 2.3 创建抽象工厂
    AbstractFactory.java
public abstract class AbstractFactory {
    public abstract Color getColor(String colorType);
    public abstract Product getProduct(String productType);
}

-2.4 创建ColorFactory工厂 注意继承类,Product同理,但需要注意抽象方法
ColorFactory.java

public class ProductFactory extends AbstractFactory {
    @Override
    public Color getColor(String colorType) {
        return null;
    }

    @Override
    public Product getProduct(String productType) {
        if (TextUtils.isEmpty(productType)) {
            return null;
        }
        if ("productA".equals(productType)) {
            return new ProductImplA();
        } else if ("productB".equals(productType)) {
            return new ProductImplB();
        } else if ("productC".equals(productType)) {
            return new ProductImplC();
        }
        return null;
    }
}

-2.5 创建 创建工厂者, 根据传递信息获取具体工厂
FactoryProducer.java

public class FactoryProducer {

    public static AbstractFactory getType(String choice) {
        if ("color".equals(choice)) {
            return new ColorFactory();
        } else if ("product".equals(choice)) {
            return new ProductFactory();
        }
        return null;
    }
}
  • 2.6 使用
private void AbstractFactory() {
        AbstractFactory colorProducer = FactoryProducer.getType("color");
        colorProducer.getColor("colorA").color();
        colorProducer.getColor("colorB").color();
        colorProducer.getColor("colorC").color();

        AbstractFactory productProducer = FactoryProducer.getType("product");
        productProducer.getProduct("productA").product();
        productProducer.getProduct("productB").product();
        productProducer.getProduct("productC").product();
    }
  • 2.7验证信息
I/System.out: class ColorImplA , method color
I/System.out: class ColorImplB , method color
I/System.out: class ColorImplC , method color
I/System.out: class ProductImplA , method product
I/System.out: class ProductImplB , method product
I/System.out: class ProductImplC , method product

三、单例设计模式

Java中最简单的设计模式之一,这种模式只涉及一个类,它负责创建一个对象,同时保证只有一个对象,这个类提供一种方法来访问它的唯一对象,可以直接访问而不需要实例化对象,实例化对象也只有一次。

  • 3.1 饿汉式单例
public class SingleClass {

    private static SingleClass singleClass = new SingleClass();

    public static SingleClass getInstance() {
        return singleClass;
    }
}
  • 3.2懒汉式单例
public class SingleClass {
    private static SingleClass singleClass;

    public static SingleClass getInstance() {
        if (null == singleClass) {
            singleClass = new SingleClass();
        }
        return singleClass;
    }
}

四、建造者(Builder)模式

  • 建造者模式的UML直观图


    image.png

    核心思想:将复杂对象的构造与表现分离,使同样的构造可以产生不同的表现。

  • 4.1 创建核心抽象类 , 主要就是说把小步骤给抽象出来,通过调用方法来确定都生成什么表现。
    AbstractBuilder.java
public abstract class AbstractBuilder {

    abstract void InstallStudio();

    abstract void DownLoadSDK();

    abstract void BuildProject();

    public abstract Project getProject();
}
  • 4.2 创建Project类, 在这里写数据逻辑
    Project.java
public class Project {

    private List<String> step = new ArrayList<>();

    public void add(String info) {
        step.add(info);
    }

    public void show() {
        for (int i = 0; i < step.size(); i++) {
            Log.e("step" + (i + 1), "show: " + step.get(i));
        }
        Log.e("step", "show: 安装完成!!!");
    }

}
  • 4.3 为了更直观表达建造者模式,我把业务层写到了一起。
    Controller.java
public class Controller extends AbstractBuilder {

    private Project project;

    public Controller() {
        project = new Project();
    }

    @Override
    void InstallStudio() {
        project.add("安装Studio");
    }

    @Override
    void DownLoadSDK() {
        project.add("下载SDK");
    }

    @Override
    void BuildProject() {
        project.add("build项目");
    }


    @Override
    public Project getProject() {
        return project;
    }

    public static class Builder {

        private AbstractBuilder abstractBuilder;

        public Builder(AbstractBuilder abstractBuilder) {
            this.abstractBuilder = abstractBuilder;
        }

        public Builder create() {
            abstractBuilder.InstallStudio();
            abstractBuilder.DownLoadSDK();
            abstractBuilder.BuildProject();
            return this;
        }


        public Builder getProject() {
            abstractBuilder.getProject();
            return this;
        }

        public Builder show() {
            abstractBuilder.getProject().show();
            return this;
        }
    }
}
  • 4.4 调用
Controller.Builder builder = new Controller.Builder(new Controller());
        builder.create().getProject().show();
  • 4.5 验证信息
step1: show: 安装Studio
step2: show: 下载SDK
step3: show: build项目
step: show: 编译完成!!!

五、原型模式

核心思想:复制粘贴都用过,复制的文件跟原文件没有一点差别。
概念:用原型实例 指定创建对象的种类,并通过拷贝这些原型创建新的对象。

  • 5.1 浅拷贝
    只拷贝对象中的基本数据类型(8种),对于数组、容器、引用对象等都不会拷贝
  • 5.1.1浅拷贝的代码实现 创建附件类
    AttachType.java
public class AttachType {
    **get,set,tostring方法隐藏,但实际有
    private String attach;
}
  • 5.1.2 定义抽象原型
    Student.java
public class Student implements Cloneable {
    **get,set,tostring方法隐藏,但实际有
    private AttachType attachType;
    private String name;
  
    public Student clone() {
        Student student = null;
        try {
            student = (Student) super.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return student;
    }
}

  • 5.1.3 模拟实现
private void catalog() {
        Student student1 = new Student();
        AttachType attachType = new AttachType("aaa");
        student1.setName("张三");
        student1.setAttachType(attachType);

        Student student2 = student1.clone();
        student2.setName("李四");
        student2.getAttachType().setAttach("bbb");

        System.out.println(">>>s1" + student1.toString());
        System.out.println(">>>s2" + student2.toString());
    }

-5.1.4 输出结果

I/System.out: >>>s1Student{attachType=AttachType{attach='bbb'}, name='张三'}
I/System.out: >>>s2Student{attachType=AttachType{attach='bbb'}, name='李四'}

可以看到只改动了name,AttachType对象,并没有分离出来。

  • 5.2深克隆
    拷贝对象中的基本数据类型(8种),对于数组、容器、引用对象等都会拷贝。
    深克隆需要注意的是,所有的类,都要实现Cloneable,并且在宿主bean做处理。
  • 5.2.1创建附件类
    AttachType_2.java
public class AttachType_2 implements Cloneable {
    ** get,set,tostring方法隐藏,但实际有
    private String attach;

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}

-5.2.2定义抽象原型
Student_2.java

public class Student_2 implements Cloneable {
    ** get,set,tostring方法隐藏,但实际有
    private AttachType attachType;
    private String name;

    public Student_2 clone() {
        Student_2 student_2 = null;
        try {
            student_2 = (Student_2) super.clone();
            student_2.setAttachType((AttachType) student_2.getAttachType().clone());
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return (Student_2) student_2;
    }
}
  • 5.3调用同步5.1.2
  • 5.4验证结果
I/System.out: >>>s1Student{attachType=AttachType{attach='aaa'}, name='张三'}
I/System.out: >>>s2Student{attachType=AttachType{attach='bbb'}, name='李四'}

处理之后,AttachType_2也被拷贝了。
在某种情况下,合理使用可节省避免不必要的开支。


六、适配器设计模式

概念:负责连接独立或不兼容的接口。
可分为对象适配和类适配模式。
三个角色,目标接口或类、适配类或接口、适配器

  • 对象适配
  • 6.1 简单目标类
    目标类处理将语言都转换成英文,属于独立的类。
    ConvertEnglish.java
public class ConvertEnglish {

    void convertToEnglish(String info) {
        System.out.println(">>>转换成英文 : " + info);
    }
}
  • 6.1.2 简单适配接口
    需要将我说的汉语都转换成英语
public interface SpeakChinese {
    void speakChinese(String chinese);
}
  • 6.1.3 适配器
    将功能委托给目标来完成实现。
public class TransformationAdapter implements SpeakChinese {

    private ConvertEnglish convertEnglish;

    public TransformationAdapter(ConvertEnglish convertEnglish) {
        this.convertEnglish = convertEnglish;
    }

    @Override
    public void speakChinese(String chinese) {
        convertEnglish.convertToEnglish(chinese);
    }
}
  • 6.1.4 使用
TransformationAdapter adapter = new TransformationAdapter(new ConvertEnglish());
        adapter.speakChinese("我需要转换成英文");

I/System.out: >>>转换成英文 : 我需要转换成英文

对象适配器可以传入多个不同的对象,用来帮忙处理。

  • 类适配
  • 6.2.1 还是刚才的类,只需要改动适配器即可
public class TransformationAdapter extends ConvertEnglish implements SpeakChinese {
    @Override
    public void speakChinese(String chinese) {
        super.convertToEnglish(chinese);
    }
}

可以看到是通过extends的方式来获取目标类的属性,但是java中不支持多继承,所以在使用类适配的时候,每一个目标类需要单独写一个。


七、桥接模式

概念:使得具体实现类和接口实现类独立。

  • 7.1 需要一个接口
    Animation.java
public interface Animation {
    void onDraw(int radius, int x, int y);
}
  • 7.2声明两个接口实现类
    RotateImpl.java 和 TranslationImpl.java
public class RotateImpl implements Animation {
    @Override
    public void onDraw(int radius, int x, int y) {
        System.out.println(">>>DrawingRotate:" + radius + "," + x + "," + y);
    }
}

public class TranslationImpl implements Animation {
    @Override
    public void onDraw(int radius, int x, int y) {
        System.out.println(">>>DrawingTranslation:" + radius + "," + x + "," + y);
    }
}
  • 7.3 桥梁抽象类
    AbstractShape.java
public abstract class AbstractShape {

    protected Animation animation;

    public AbstractShape(Animation animation) {
        this.animation = animation;
    }

    abstract void onDraw();
}
  • 7.4 桥梁具体实现类
    ShapeImpl.java
public class ShapeImpl extends AbstractShape {

    private int radius, x, y;

    public ShapeImpl(int radius, int x, int y, Animation animation) {
        super(animation);
        this.radius = radius;
        this.x = x;
        this.y = y;
    }

    @Override
    public void onDraw() {
        animation.onDraw(radius, x, y);
    }
}
  • 7.5使用
ShapeImpl rotate = new ShapeImpl(9, 100, 100, new RotateImpl());
ShapeImpl translate = new ShapeImpl(15, 200, 300, new TranslationImpl());
rotate.onDraw();
translate.onDraw();

···
log
>>>DrawingRotate:9,100,100
>>>DrawingTranslation:15,200,300

使得具体实现类与接口实现类解耦,两种类都可以在结构上发生改变并且互不影响。


八、责任链模式

概念:将同一请求形成一条链,由链进行传递,能处理的处理,处理不了的继续传递。

  • 8.1 写个请求bean,用来处理同一类请求
    RequestBean.java
public class RequestBean {
   ** 省略了get set
    //小于18岁   大约18岁小于30岁  大于30岁小于60岁的
    private String name;
    private int age;
    private String remark;
{
  • 8.2责任链抽象类
    AbstractHandler.java
public abstract class AbstractHandler {

    protected String handlerName;//当前处理的是谁
    protected AbstractHandler nextMessage;//捆绑

    public AbstractHandler(String handlerName) {
        this.handlerName = handlerName;
    }

    public void setNextMessage(AbstractHandler nextMessage) {
        this.nextMessage = nextMessage;
    }

    public abstract void handlerRequest(RequestBean requestBean);//子类核心处理方法

}
  • 8.3 员工ABC 三条处理
    StaffA.java
public class StaffA extends AbstractHandler {

    public StaffA(String handlerName) {
        super(handlerName);
    }

    @Override
    public void handlerRequest(RequestBean requestBean) {
        if (requestBean.getAge() < 18) {
            System.out.println(">>>由" + this.handlerName + "处理了:" + requestBean.getAge() + "," + requestBean
                    .getName() + "," + requestBean.getRemark());
        } else {
            if (this.nextMessage != null) {
                this.nextMessage.handlerRequest(requestBean);
            }
        }
    }
}

-8.4 员工B
StaffB.java

public class StaffB extends AbstractHandler {

    public StaffB(String handlerName) {
        super(handlerName);
    }

    @Override
    public void handlerRequest(RequestBean requestBean) {
        if (18 < requestBean.getAge() && requestBean.getAge() < 30) {
            System.out.println(">>>由" + this.handlerName + "处理了:" + requestBean.getAge() + "," + requestBean
                    .getName() + "," + requestBean.getRemark());
        } else {
            if (this.nextMessage != null) {
                this.nextMessage.handlerRequest(requestBean);
            }
        }
    }
}

员工C同理,此处不写了。

  • 8.5 责任关联
private void startChain() {
        AbstractHandler a = new StaffA("张三");
        AbstractHandler b = new StaffB("李四");
        AbstractHandler c = new StaffC("王五");
        
        a.setNextMessage(b);
        b.setNextMessage(c);
        
        RequestBean request = new RequestBean();
        request.setAge(25);
        request.setName("赵二");
        request.setRemark("无");
        a.handlerRequest(request);
    }
  • 8.6 验证结果
I/System.out: >>>由李四处理了:25,赵二,无

九、迭代器设计模式

概念:不需要暴露内部结构的同时,可以让外部遍历数据。

  • 9.1 构建迭代接口
    MyIterator.java 和 Container.java
    因为是遍历我肯定需要知道还有没有下一条数据。
public interface MyIterator {
    boolean hasNext();//判定是否有下一条

    Object next();
}

public interface Container {
    MyIterator getMyIterator();
}
  • 9.2迭代类
public class ContainerImpl implements Container {

    private String[] strings = new String[]{"aa", "bb", "cc", "dd", "ee"};

    @Override
    public MyIterator getMyIterator() {
        return new Iterator();
    }

    class Iterator implements MyIterator {

        private int index;

        @Override
        public boolean hasNext() {
            if (index < strings.length) {
                return true;
            }
            return false;
        }

        @Override
        public Object next() {
            if (this.hasNext()) {
                return strings[index++];
            }
            return null;
        }
    }
}

hasNext处理我是否还有下一条数据,在有的前提下我才可以在next方法中return出去,至于为啥要++,next方法肯定在循环中呗。

  • 9.3使用
ContainerImpl container = new ContainerImpl();
for (MyIterator myIterator = container.getMyIterator(); myIterator.hasNext(); ) {
            String next = (String) myIterator.next();
            System.out.println(">>>next" + next);
}
  • 9.4验证信息
I/System.out: >>>nextaa
I/System.out: >>>nextbb
I/System.out: >>>nextcc
I/System.out: >>>nextdd
I/System.out: >>>nextee

十、观察者模式

概念:如果一个对象被修改,它的依赖对象将会被自动通知。
自动通知其实就是在 合理的时间调用通知接口,直接上代码。

  • 10.1 抽象类
    MyObserver.java
    依赖对象会被自动通知?所以 抽象肯定有一个依赖类,一个通知接口
public abstract class MyObserver {

    protected Subscriber subscriber;

    abstract void update();

}
  • 10.2 依赖类
public class Subscriber {

    private MyObserver myObserver;

    private int state;

    public int getState() {
        return state;
    }

    public void setState(int state) {
        this.state = state;
        notifyAllObserver();
    }

    //绑定
    public void attach(MyObserver myObserver) {
        this.myObserver = myObserver;
    }

    //通知
    public void notifyAllObserver() {
        myObserver.update();
    }
}

可以看到,引入MyObserver抽象类,通过调用MyObserver.update来做通知,所以合理的地方调用notifyAllObserver很重要。

  • 10.3 抽象具体类
    ObserverImpl.java
public class ObserverImpl extends MyObserver {

    public ObserverImpl(Subscriber subscriber) {
        this.subscriber = subscriber;
        this.subscriber.attach(this);
    }

    @Override
    public void update() {
        System.out.println(">>>this update now");
    }
}
  • 10.4 使用
private Subscriber subscriber;//成员变量,点击的时候做通知

subscriber = new Subscriber();
        new ObserverImpl(subscriber);

btn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                subscriber.setState(1);
            }
        });

subscriber 写成了成员变量,在click view的时候,做了setState值更新。更新就是通知该 调用update接口了。
-10.5 验证信息

 I/System.out: >>>this update now

十一、策略设计模式

概念:针对一组算法,将每一种算法都封装到具有共同接口的独立的类中,从而是它们可以相互替换。策略模式的最大特点是使得算法可以在不影响客户端的情况下发生变化,从而改变不同的功能。

  • 11.1 定义共有接口类
    IStrategy.java
    共有接口类,计算不同的a,b参数处理方式
public interface IStrategy {
    void strategyType(int a, int b);
}
  • 11.2 共有接口类ab计算,策略之一
    StrategyA.java 加法
public class StrategyA implements IStrategy {

    @Override
    public void strategyType(int a, int b) {
        //处理算法。
        int sum = a + b;
        System.out.println(">>>sum" + sum);
    }
}
  • 11.3共有接口类ab计算,策略之一
    StrategyB.java 乘法
public class StrategyB implements IStrategy {

    @Override
    public void strategyType(int a, int b) {
        //处理算法。
        int sum = a * b;
        System.out.println(">>>sum" + sum);
    }
}

还写了个减法,同步上面都一样。主要是为了表现策略之一。

  • 11.4 策略调用类
    StrategyImpl.java
public class StrategyImpl {

    private IStrategy iStrategy;

    public StrategyImpl(IStrategy iStrategy) {
        this.iStrategy = iStrategy;
    }

    public void strategyType(int a, int b) {
        iStrategy.strategyType(a, b);
    }

}
  • 11.5使用
private void strategy() {
        int a = 10;
        int b = 5;
        StrategyImpl strategy = new StrategyImpl(new StrategyA());
        strategy.strategyType(a, b);

        StrategyImpl strategy2 = new StrategyImpl(new StrategyB());
        strategy2.strategyType(a, b);

        StrategyImpl strategy3 = new StrategyImpl(new StrategyC());
        strategy3.strategyType(a, b);
    }
  • 11.6验证信息
 I/System.out: >>>sum15
 I/System.out: >>>sum50
 I/System.out: >>>sum5

策略模式的好处是 实现可以自由切换,扩展性也比较好,阅读代码很直观。

结语
设计模式 真的是可以规范代码,并且提高对源码的理解。

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