Java进阶篇设计模式之三 ----- 建造者模式和原型模式

前言

上一篇中咱们学习了工厂模式,介绍了简单工厂模式、工厂方法和抽象工厂模式。本篇则介绍设计模式中属于建立型模式的建造者模式和原型模式。html

建造者模式

简介

建造者模式是属于建立型模式。建造者模式使用多个简单的对象一步一步构建成一个复杂的对象。这种类型的设计模式属于建立型模式,它提供了一种建立对象的最佳方式。
简单的来讲就是将一个复杂的东西抽离出来,对外提供一个简单的调用,能够在一样的构建过程建立不一样的表示。和工厂模式很类似,不过相比而言更加注重组件的装配。数据库

这里用一个示例来进行说明。
咱们一天吃的食物有这些,煎饼、盒饭、拉面、豆浆、牛奶和果汁。分为三餐、早餐、午饭和晚餐,餐点主要包含吃的(俗称饭)和喝的(豆浆,果汁之类的),那么咱们能够把煎饼和豆浆做为早餐,盒饭和果汁做为午饭,这样咱们能够清楚的知道要吃早餐和午饭包含什么食物。设计模式

首先咱们定义一个食物类,有两个属性,吃的和喝的。ide

class Meal{
    private String food;
    private String drinks;
    
    public String getFood() {
        return food;
    }
    public void setFood(String food) {
        this.food = food;
    }
    
    public String getDrinks() {
        return drinks;
    }
    public void setDrinks(String drinks) {
        this.drinks = drinks;
    }
}

定义了食物时候,咱们在定义一个食物的标准接口,一份食物包含什么,其实也就是吃的和喝的。性能

interface IBuilderFood{
    void buildFood();
    void buildDrinks();
    Meal createMeal();
}

食物接口定义一个吃的和一个喝的组件,而后经过createMeal()方法返回咱们须要的食物。
那么如今咱们即可以定义一份早餐和午饭。
代码示例:学习

class Breakfast implements IBuilderFood{
    Meal meal;

    public Breakfast(){
        meal=new Meal();
    }
    
    @Override
    public void buildFood() {
        meal.setFood("煎饼");
    }

    @Override
    public void buildDrinks() {
        meal.setDrinks("豆浆");   
    }
    
    @Override
    public Meal createMeal() {
        return meal;
    }
}

class Lunch implements IBuilderFood{
    Meal meal;

    public Lunch(){
        meal=new Meal();
    }
    
    @Override
    public void buildFood() {
        meal.setFood("盒饭");
    }

    @Override
    public void buildDrinks() {
        meal.setDrinks("果汁");   
    }
    
    @Override
    public Meal createMeal() {
        return meal;
    }
}

定义完以后,建造早餐和午饭的的过程已经完毕了。可是这并非建造者模式,它有个核心的Director(导演者),它用来建立复杂对象的部分,对该部分进行完整的建立或者按照必定的规则进行建立。那么这里咱们能够建立一个Director,用来建立一份餐点。至于建立的是什么餐点,它不用知道,这一点由调用者来进行决定。测试

这里咱们就能够定义一个饭店,能够建立一份餐点,建立什么餐点有顾客决定。
代码示例:ui

class FoodStore{
    public Meal createBreakfast(IBuilderFood bf){
        bf.buildDrinks();
        bf.buildFood();
        return bf.createMeal();
    }
}

建立完成这个Director以后,咱们再来进行调用测试。this

代码示例:.net

public class BuilderTest {

    public static void main(String[] args) {
        FoodStore foodStore=new FoodStore();
        Meal meal=foodStore.createBreakfast(new Breakfast());
        Meal meal2=foodStore.createBreakfast(new Lunch());
        System.out.println("小明早上吃的是:"+meal.getFood()+",喝的饮料是:"+meal.getDrinks());
        System.out.println("小明中午吃的是:"+meal2.getFood()+",喝的饮料是:"+meal2.getDrinks()); 
    }

}

输出结果:

小明早上吃的是:煎饼,喝的饮料是:豆浆
小明中午吃的是:盒饭,喝的饮料是:果汁

简单的介绍了下建造者模式的运做原理,能够概况为这4点:

  1. Builder:指定一个抽象的接口,规定该产品所需实现部件的建立,并不涉及具体的对象部件的建立。

  2. ConcreteBuilder:需实现Builder接口,而且针对不一样的逻辑,进行不一样方法的建立,最终提供该产品的实例。

  3. Director:用来建立复杂对象的部分,对该部分进行完整的建立或者按照必定的规则进行建立。

  4. Product:示被构造的复杂对象。

使用场景:
适用一些基本组件不便,可是组合常常变化的时候。好比超市促销的大礼包。

优势:

  1. 建造者独立,易扩展。
  2. 便于控制细节风险。

缺点

  1. 内部结构复杂,不易于理解。
  2. 产品直接须要有共同点,范围有控制。

原型模式

原型模式(Prototype Pattern)是用于建立重复的对象,同时又能保证性能。这种类型的设计模式属于建立型模式,它提供了一种建立对象的最佳方式。

通常来讲咱们在建立对象的时候是直接建立的,可是建立该对象的代价很大的时候,重复的二次建立就有些不划算,这时咱们就可使用原型模式。
打个比方,咱们都发送过邮件,在节日的时候通常发送的是祝福语句,在这些祝福语句中,通常除了名字不同以外,大部分都是同样的。这时咱们就能够利用该模式来进行相应出建立。

这里仍是用一个的简单的示例来讲明。
小明和小红在同一天生日,而后咱们须要给他们发送邮件进行祝福,可是因为比较懒,祝福语除了名字以外都是同样的。这时咱们就能够先完成祝福语的编写,而后克隆该祝福语,最后根据不一样的名称进行发送。不过这里就从简了,只是简单的打印下而已。

代码示例:

public class PrototypeTest {

    public static void main(String[] args) {
        Mail mail=new Mail();
        mail.setMsg("生日快乐!");
        Mail mail2=(Mail) mail.clone();
        mail.setName("小明");
        mail2.setName("小红");
        System.out.println(mail.toString());
        System.out.println(mail2.toString());
    }
}

 class Mail implements Cloneable {
    private String name;
    private String msg;
    
    public String getName() {
        return name;
    }

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

    public void setMsg(String msg) {
        this.msg = msg;
    }
    public Object clone() {
        Object clone = null;
        try {
            clone = super.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return clone;
    }

    @Override
    public String toString() {
        return name + ":" + msg ;
    }
    
}

输出结果:

小明:生日快乐!
小红:生日快乐!

看完原型模式的建立,是否是感受就是和Java中克隆即为相似呢?
实际上它的核心也就是克隆。
克隆有两种,浅克隆和深克隆,本文主要介绍的是浅克隆。
浅克隆:

在浅克隆中,若是原型对象的成员变量是值类型,将复制一份给克隆对象;若是原型对象的成员变量是引用类型,则将引用对象的地址复制一份给克隆对象,也就是说原型对象和克隆对象的成员变量指向相同的内存地址。
简单来讲,在浅克隆中,当对象被复制时只复制它自己和其中包含的值类型的成员变量,而引用类型的成员对象并无复制。
实现Cloneable接口并重写Object类中的clone()方法;

深克隆:

在深克隆中,不管原型对象的成员变量是值类型仍是引用类型,都将复制一份给克隆对象,深克隆将原型对象的全部引用对象也复制一份给克隆对象。

简单来讲,在深克隆中,除了对象自己被复制外,对象所包含的全部成员变量也将复制。
实现Serializable接口,经过对象的序列化和反序列化实现克隆,能够实现真正的深度克隆。

使用场景:

  1. 类初始化的时候须要消耗大量资源的时候;
  2. 获取数据库链接繁琐的时候;
  3. 一个对象,有不少个修改者的时候;

优势:
1.能够提高性能;

缺点:
1.由于必须实现Cloneable 接口,因此用起来可能不太方便。

其它

音乐推荐

原创不易,若是感受不错,但愿给个推荐!您的支持是我写做的最大动力! 版权声明: 做者:虚无境 博客园出处:http://www.cnblogs.com/xuwujing CSDN出处:http://blog.csdn.net/qazwsxpcm     我的博客出处:http://www.panchengming.com 原创不易,转载请标明出处,谢谢!

相关文章
相关标签/搜索