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. [JS]两个常用的取随机整数的函数

    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/ ...

  2. Spark机器学习(5):SVM算法

    1. SVM基本知识 SVM(Support Vector Machine)是一个类分类器,能够将不同类的样本在样本空间中进行分隔,分隔使用的面叫做分隔超平面. 比如对于二维样本,分布在二维平面上,此 ...

  3. Tuxedo低版本客户端(Tuxedo 9)连接到高版本Tuxedo服务端(Tuxedo 12.1.3)的问题

    经过我实测,是没问题的.但是客户端的Tuxedo DLL必须全部是Tuxedo 9的DLL,不能混用.不然即使用Dependency Walker 分析DLL依赖完全正确,但是实际运行时结果也会出现奇 ...

  4. 编写SHELL脚本--编写简单脚本

    1.简单脚本文件hello.sh,内容如下 #!/bin/bash pwd ls -al 执行脚本:bash hello.sh  或者使用root命令:  ./hello.sh 2.接受用户参数 $0 ...

  5. String的split方法支持正则表达式

    String的split方法支持正则表达式: 1. 正则表达式\s表示匹配任何空白字符 2. +表示匹配一次或多次

  6. Redis高可用详解:持久化技术及方案选择

    文章摘自:https://www.cnblogs.com/kismetv/p/9137897.html 前言 在上一篇文章中,介绍了Redis的内存模型,从这篇文章开始,将依次介绍Redis高可用相关 ...

  7. 图文剖析自己定义View的绘制(以自己定义滑动button为例)

    自己定义View一直是横在Android开发人员面前的一道坎. 一.View和ViewGroup的关系 从View和ViewGroup的关系来看.ViewGroup继承View. View的子类.多是 ...

  8. [转]css实现左侧宽度自适应,右侧固定宽度

    原文地址:https://segmentfault.com/a/1190000008411418 页面布局中经常用会遇到左侧宽度自适应,右侧固定宽度,或者左侧宽度固定,右侧自适应.总之就是一边固定宽度 ...

  9. ssh-remote-port-forwarding

    1.ssh免密码登录(A登录到B) 1.1.在A上执行并在~/.ssh下生成id_rsa和id_rsa.pub两个文件 ssh-keygen -t rsa -P '' 1.2.拷贝id_rsa.pub ...

  10. CSS初始化示例代码

    CSS初始化示例代码 /* css reset www.admin10000.com */ body,div,dl,dt,dd,ul,ol,li,h1,h2,h3,h4,h5,h6,pre,code, ...