前言

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

建造者模式

简介

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

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

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

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,用来创建一份餐点。至于创建的是什么餐点,它不用知道,这一点由调用者来进行决定。

这里我们就可以定义一个饭店,可以创建一份餐点,创建什么餐点有顾客决定。
代码示例:

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

创建完成这个Director之后,我们再来进行调用测试。

代码示例:


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. 一个对象,有很多个修改者的时候;

优点::

可以提升性能。

缺点:

因为必须实现Cloneable 接口,所以用起来可能不太方便。

 接下来下一篇将会讲解适配器模式和桥接模式,有不好的地方请留言评论,相互学习,谢谢!

Java设计模式之三 ----- 建造者模式和原型模式的更多相关文章

  1. Java设计模式(五)Prototype原型模式

    一.场景描述 创建型模式中,从工厂方法模式,抽象工厂模式,到建造者模式,再到原型模式,我的理解是,创建对象的方式逐步从编码实现转向内存对象处理. 例如,在“仪器数据采集器”的子类/对象“PDF文件数据 ...

  2. Java 设计模式系列(五)原型模式

    Java 设计模式系列(五)原型模式 原型模式属于对象的创建模式.通过给出一个原型对象来指明所有创建的对象的类型,然后用复制这个原型对象的办法创建出更多同类型的对象.这就是选型模式的用意. 一.原型模 ...

  3. Java设计模式之三建造者模式和原型模式

    建造者模式 简介 建造者模式是属于创建型模式.建造者模式使用多个简单的对象一步一步构建成一个复杂的对象.这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式.简单的来说就是将一个复杂的东西 ...

  4. Java设计模式之(四)——原型模式

    1.什么是原型模式 Specify the kinds of objects to create using a prototypical instance,and create new object ...

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

    前言 在上一篇中我们学习了工厂模式,介绍了简单工厂模式.工厂方法和抽象工厂模式.本篇则介绍设计模式中属于创建型模式的建造者模式和原型模式. 建造者模式 简介 建造者模式是属于创建型模式.建造者模式使用 ...

  6. 折腾Java设计模式之建造者模式

    博文原址:折腾Java设计模式之建造者模式 建造者模式 Separate the construction of a complex object from its representation, a ...

  7. Java 设计模式之建造者模式(四)

    原文地址:Java 设计模式之建造者模式(四) 博客地址:http://www.extlight.com 一.前言 今天继续介绍 Java 设计模式中的创建型模式--建造者模式.上篇设计模式的主题为 ...

  8. 设计模式之第9章-原型模式(Java实现)

    设计模式之第9章-原型模式(Java实现) “快到春节了,终于快放假了,天天上班好累的说.”“确实啊,最近加班比较严重,项目快到交付了啊.”“话说一到过节,就收到铺天盖地的短信轰炸,你说发短信就发吧, ...

  9. java23种设计模式(二)-- 建造者模式和原型模式

    一.建造者模式 将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创造不同的表示. 特点: (1).在某些属性没有赋值之前,复杂对象不能作为一个完整的产品使用.比如汽车包括方向盘.车门.发动机 ...

随机推荐

  1. Ubuntu Docker版本的更新与安装

    突然发现自己的docker版本特别的低,目前是1.9.1属于古董级别的了,想更新一下最新版本,这样最新的一下命令就可以被支持.研究了半天都没有更新成功,更新后的版本始终都是1.9.1 :查阅了官网资料 ...

  2. js实现全选/全不选、反选

    <!doctype html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  3. 【翻译】WPF4.5新特性(MSDN的翻译读不太懂)

    我很在意WPF的发展,有人说微软不再维护WPF了,无所谓,随他去. MSDN上有简体版:http://msdn.microsoft.com/zh-cn/library/vstudio/bb613588 ...

  4. 异步加载CSS

    说到加载 CSS 这种事儿不是很简单吗?像这样咯: <link rel="stylesheet" href="cssfile.css"> 这不就完事 ...

  5. Linux 安装 JDK

    本篇博客用于记录一下在 Linux 系统下安装 Java 环境. 在大部分的 Linux 系统中都有安装 Open JDK,所以最好是先卸载 Open JDK 后在进行我们的 JDK 安装.Open ...

  6. Struts2学习(二)———— 表单参数自动封装和参数类型自动转换

    前篇文章对struts2的一个入门,重点是对struts2的架构图有一个大概的了解即可,之后的几篇文章,就是细化struts2,将struts2中的各种功能进行梳理,其实学完之后,对struts2的使 ...

  7. 单机安装Hadoop

    单机安装hadoop ------------------------------------------------------------------ 操作系统:centos7 64 位 hado ...

  8. 【Java】用注解实现分发器

    在C/S中,客户端会向服务器发出各种请求,而服务器就要根据请求做出对应的响应.实际上就是客户机上执行某一个方法,将方法返回值,通过字节流的方式传输给服务器,服务器找到该请求对应的响应方法,并执行,将结 ...

  9. 接触Java的15天,初步了解面向对象

    面向对象的三打特征:封装 ,继承 ,多态 . 图老师给的,叫我们好好看一看 对象(object):一个杯子,一台电脑,一个人,一件衣服  等,都可以称为对象. 类:类是对象的抽象的分类:比如,人类进行 ...

  10. WordPress 新版本中编辑器不好用, 使用原有编辑器

    将以下代码添加到当前主题的函数模板 functions.php 文件中即可. add_filter('use_block_editor_for_post', '__return_false'); re ...