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. postgre 导出单表和导入

    pg除了可以通过dump的方式导入和导出.如果只是导出数据,可以直接使用copy 导出 COPY user TO '/tmp/data/test.csv' WITH csv; COPY user(na ...

  2. Ubuntu16.04上使用Anaconda3的Python3.6的pip安装UWSGI报错解决办法

    具体报错信息: lto1: fatal error: bytecode stream generated with LTO version 6.0 instead of the expected 4. ...

  3. PL/SQL学习笔记之记录

    一:记录 记录是一种高可以容纳不同数据类型的数据的数据结构. PL/SQL可以处理记录的以下几种类型: 基于数据表 基于游标的记录 用户自定义的记录 二:使用 %ROWTYPE属性 创建基于表格或基于 ...

  4. 详解CentOS设置163的yum源的过程

    转自启动CentOS系统,打开火狐浏览器,如下图所示: 2 登录“mirrors.163.com”,如下图所示: 3 点击centos后面的“centos使用帮助”,如下图所示: 4 可以看到设置和使 ...

  5. C# 读写文件摘要

    主要参考地址:https://www.cnblogs.com/chenyangsocool/p/7511161.html 首先下载微软提供的工具:DsoFile  (微软官网下载传送门) 读写自定义摘 ...

  6. CSA Enterprise Architecture图

    https://research.cloudsecurityalliance.org/tci/index.php/explore/

  7. python prettytable模块

    简介 Python通过PrettyTable模块可以将输出内容如表格方式整齐地输出. 安装 pip install prettytable 1 示例 from prettytable import P ...

  8. django admin upload 上传图片到oss Django Aliyun OSS2 Storage

    https://github.com/xiewenya/django-aliyun-oss2-storage Install pip install django-aliyun-oss2-storag ...

  9. Andorid开发(二十二)——获取上下文getApplicationContext()、Activity.this、 getBaseContext

    getApplicationContext() //返回应用的上下文,生命周期是整个应用,应用摧毁它才摧毁 Activity.this的context //返回当前activity的上下文,属于act ...

  10. Mysql字符串字段中是否包含某个字符串,用 find_in_set

    有这样一个需求,在Mysql数据库字符串字段(权限)中,有范围在 1 到 N 之间代表不同权限的值,分别被‘,’分开,现在要取出具有某权限的所有成员列表. 创建表:   1 CREATE TABLE ...