What

Prototype:用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。

Why

Prototype适用于在一个类的实例有几种不同的状态组合的一种时,建立相应的数目的原型并克隆她们,要比每次使用合适的状态创建它们方便一些,或者为了避免创建一个与产品类层次平行的工厂类层次时,要实例化一的类在运行时动态指定时。

How

假设如下场景:有一个复杂的报表,创建过程非常复杂,需要把报表发给两个领导,其中只有报表少了属性不同,其他属性相同。

首先讨论一下java中的基础知识

java的clone()方法:

clone方法将对象复制一份并返回给调用者。一般满足如下条件:

1、对于任何对象a,都有a.clone()!=x,克隆对象和源对象是不同的对象

2、对于任何对象a,都有a.clone().getClass()==a.getClass(),克隆对象和源对象类型一样

3、如果对象a的equals()方法定义恰当,那么a.clone().equals(a)成立。

java中对象克隆的实现:

可以利用Object类的clone()方法

1、对象类实现Coneable接口

2、覆盖实现clone()方法

3、调用super.clone(),实现克隆。

以上场景实现代码如下:

public class Product implements Cloneable{

    private String name;

    private int model;

    public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} public int getModel() {
return model;
} public void setModel(int model) {
this.model = model;
} @Override
protected Object clone() {
try {
return super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return null;
}
}
public class Report implements Cloneable{

    private String name;

    private Product product;

    public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} public Product getProduct() {
return product;
} public void setProduct(Product product) {
this.product = product;
} @Override
protected Object clone() {
try {
return super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return null;
}
}

客户端调用

public class App {
public static void main( String[] args ){
Report report=new Report();
Product product=new Product();
product.setModel(1);
product.setName("productName");
report.setName("某某产品报表");
report.setProduct(product);
System.out.println(report.getName()+"|"+report.getProduct().getName());
Report report1=(Report)report.clone();
report1.setName("某某产品报表组1");
report1.getProduct().setName("产品1");
System.out.println(report1.getName()+"|"+report1.getProduct().getName());
}
}

以上代码类图如下:

Discuss

深拷贝VS浅拷贝

以上的例子我们的运行结果如下:

某某产品报表|productName
某某产品报表组1|产品1

我们在加一行代码,在最后一行打印report的信息

System.out.println(report.getName()+"|"+report.getProduct().getName());

我们的运行结果如下:

某某产品报表|productName
某某产品报表组1|产品1
某某产品报表|产品1

我们可以看出,第二次打印的结果出了问题,report中的产品名字已经被改变了。

在Report中,其中product属性,我们引用其他对象,在clone方法中,我们的实现只复制了它的引用,只负责了它的指针,没有复制它所指向的堆空间里的属性,所以在这行代码report1.getProduct().setName("产品1");也改变了report中product属性中的name属性的值,这种拷贝是浅拷贝。

我们修改下report的clone()方法,改为如下:

    @Override
protected Object clone() {
Report report;
try {
report=(Report) super.clone();
report.setProduct((Product)product.clone());
return report;
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return null;
}

我们再看下运行结果

某某产品报表|productName
某某产品报表组1|产品1
某某产品报表|productName

这次结果正确了,在以上代码中,我们对product属性,也进行了一次clone,所以report1和report的product属性指向了不同的堆空间,所以我们改变product中的属性值,不会相互影响,这个拷贝就是深拷贝。

设计模式学习--Prototype的更多相关文章

  1. 设计模式学习系列6 原型模式(prototype)

    原型模式(prototype)用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象.允许一个对象再创建另外一个新对象的时候根本无需知道任何创建细节,只需要请求圆形对象的copy函数皆可. 1 ...

  2. [学习笔记]设计模式之Prototype

    写在前面 为方便读者,本文已添加至索引: 设计模式 学习笔记索引 在笔记Builder模式中,我们曾见到了最初用于创建平行世界的函数createWorld,并且它是Mage类的成员函数(毕竟是专属于魔 ...

  3. python之路,Day24 常用设计模式学习

    python之路,Day24 常用设计模式学习   本节内容 设计模式介绍 设计模式分类 设计模式6大原则 1.设计模式介绍 设计模式(Design Patterns) --可复用面向对象软件的基础 ...

  4. Java设计模式学习记录-GoF设计模式概述

    前言 最近要开始学习设计模式了,以前是偶尔会看看设计模式的书或是在网上翻到了某种设计模式,就顺便看看,也没有仔细的学习过.前段时间看完了JVM的知识,然后就想着JVM那么费劲的东西都看完了,说明自己学 ...

  5. swift设计模式学习 - 原型模式

    移动端访问不佳,请访问我的个人博客 设计模式学习的demo地址,欢迎大家学习交流 原型模式 用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象. 定义 用原型实例指定创建对象的种类,并且通 ...

  6. C#大话设计模式学习总结

    如有雷同,不胜荣欣,如转载,请注明 C#大话设计模式学习总结 一.工厂模式 面向对象的三个特性:封装,继承和多态 1.封装 Class Operate { privatedouble _numberA ...

  7. 7 种 Javascript 常用设计模式学习笔记

    7 种 Javascript 常用设计模式学习笔记 由于 JS 或者前端的场景限制,并不是 23 种设计模式都常用. 有的是没有使用场景,有的模式使用场景非常少,所以只是列举 7 个常见的模式 本文的 ...

  8. Java-马士兵设计模式学习笔记-总结

    <马士兵设计模式学习>学习了以下模式: 1.装饰者模式(例子:水管工,木工) 2.策略模式(例子:老师用职称比大小.学生用成绩比大小) 3.简单工厂模式(例子:VechileFactory ...

  9. Java设计模式学习资源汇总

    本文记录了Java设计模式学习书籍.教程资源.此分享会持续更新: 1. 设计模式书籍 在豆瓣上搜索了一把,发现设计模式贯穿了人类生活的方方面面.还是回到Java与程序设计来吧. 打算先归类,再浏览,从 ...

随机推荐

  1. DHCP服务原理与搭建(Linux系统+路由器,二选一方案)

    大家都知道上网的最基本前提是要在终端上设置IP.子网掩码.网关.DNS等地址信息,在家里或者在办公室很多时候打开电脑后发现就可以上网,并没有手动设置IP.掩码.DNS地址也能上网,这是什么原因呢?其实 ...

  2. AutoMapperExtension

    using System; using System.Collections.Generic; using System.Linq; using AutoMapper; using System.Co ...

  3. Sequel Pro for Mac(MySQL 数据库管理工具)破解版安装

    1.软件简介    Sequel Pro 是一款管理 Mysql 的工具,界面简洁易用. 2.功能特色 FULL MYSQL SUPPORT Sequel Pro is a fast, easy-to ...

  4. 应用程序默认安装在C盘后启动时提示权限不足想起的。。。

    最近不少经销商用户反映,在使用win 7的系统的电脑上安装我们的软件后,开启系统时提示权限不足,无法启动软件. 而在xp系统下则没有这个问题,原因在于我们将系统的默认安装路径选择在了C盘了,而win ...

  5. fft ocean注解

    针对这两篇教程: http://www.keithlantz.net/2011/10/ocean-simulation-part-one-using-the-discrete-fourier-tran ...

  6. Atitit 视图参数解决方案 oracle版和mysql版本 attilax总结.docx

    Atitit 视图参数解决方案 oracle版和mysql版本 attilax总结.docx 1.1. Package机制1 1.2. 全局变量机制1 1.3. 临时表模式,oracle mysql都 ...

  7. [docker]docker网络-直接路由模式

    linux namespace连接参考: http://www.cnblogs.com/iiiiher/p/8057922.html docker网络-直接路由模式 参考: https://www.y ...

  8. 推荐几个Windows工具软件: ASuite - 便携的程序启动器

    主页: http://asuite.sourceforge.net 下载: http://sourceforge.net/projects/asuite/ ASuite is a lightweigh ...

  9. [转]JSTL 自定义方法报错Invalid syntax for function signature in TLD.

    Apache Tomcat/6.0.18 ${my:splitApply(apply)} <function> <name>splitApply</name> &l ...

  10. 【Unity】UGUI无法修改UI元素的Pivot锚点位置

    如下图,要点击切换左边的Toggle按钮变为Pivot才可以编辑Pivot!   参考: https://answers.unity.com/questions/871238/cant-change- ...