源码在我的githubgitee中获取

目录

java23种设计模式—— 一、设计模式介绍

java23种设计模式—— 二、单例模式

java23种设计模式——三、工厂模式

java23种设计模式——四、原型模式

java23种设计模式——四、原型模式

这种模式是实现了一个原型接口,该接口用于创建当前对象的克隆。当直接创建对象的代价比较大时,则采用这种模式。例如,一个对象需要在一个高代价的数据库操作之后被创建。我们可以缓存该对象,在下一个请求时返回它的克隆,在需要的时候更新数据库,以此来减少数据库调用。

举个例子,就是当我们需要给电脑安装win10系统时需要去官网上下载win10系统的安装包。而安装包的大小都是很耗时的,还需要另一台电脑来操作。如果我们下载了一个安装包放在我们的u盘里,之后需要安装win10时是不是就省去了中间寻找,下载等时间呢

原型模式的克隆分为浅克隆和深克隆,Java 中的 Object 类提供了浅克隆的 clone() 方法,具体原型类只要实现 Cloneable 接口就可实现对象的浅克隆,这里的 Cloneable 接口就是抽象原型类。其代码如下

浅克隆

新建一个实体类Sheep实现Cloneable 接口,重写clone()方法

/**
* @author codermy
* @createTime 2020/5/14
*/
public class Sheep implements Cloneable{
private String name;
private int age;
private String sex; public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} public int getAge() {
return age;
} public void setAge(int age) {
this.age = age;
} public String getSex() {
return sex;
} public void setSex(String sex) {
this.sex = sex;
} public Sheep(String name, int age, String sex) {
this.name = name;
this.age = age;
this.sex = sex;
} @Override
public String toString() {
return "Sheep{" +
"name='" + name + '\'' +
", age=" + age +
", sex='" + sex + '\'' +
'}';
}
//克隆该实例,使用默认的clone方法
@Override
protected Object clone() throws CloneNotSupportedException {
Sheep sheep =null;
sheep = (Sheep)super.clone();
return sheep;
}
}

测试

/**
* @author codermy
* @createTime 2020/5/14
*/
public class Client {
public static void main(String[] args) throws CloneNotSupportedException {
Sheep sheep = new Sheep("tom",1,"male");
Sheep sheep1 = (Sheep)sheep.clone();
System.out.println(sheep.hashCode());
System.out.println(sheep);
System.out.println(sheep1.hashCode());
System.out.println(sheep1);
sheep1.setAge(2);
System.out.println(sheep1);
System.out.println(sheep);
}
}

输出

1163157884
Sheep{name='tom', age=1, sex='male'}
1956725890
Sheep{name='tom', age=1, sex='male'}
Sheep{name='tom', age=2, sex='male'}
Sheep{name='tom', age=1, sex='male'}

在浅克隆中,被复制对象的所有普通成员变量都具有与原来对象相同的值,而所有的对其他对象的引用仍然指向原来的对象。也就是说,浅克隆仅仅复制所考虑的对象,不会复制它所引用的成员对象。

我们先新建一个Pearson类,作为对象属性

/**
* @author codermy
* @createTime 2020/7/24
*/
public class Person implements Cloneable{
String name; public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} public Person(){ }
public Person(String name){
this.name = name;
} @Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
'}';
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
} }

我们先给Sheep实体类种添加一个对象属性

/**
* @author codermy
* @createTime 2020/6/16
*/
public class Sheep implements Cloneable {
private String name;
private int age;
private String sex;
public Person owner;//对象引用 public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} public int getAge() {
return age;
} public void setAge(int age) {
this.age = age;
} public String getSex() {
return sex;
} public void setSex(String sex) {
this.sex = sex;
} public Person getOwner() {
return owner;
} public void setOwner(Person owner) {
this.owner = owner;
} public Sheep(String name, int age, String sex, Person owner) {
this.name = name;
this.age = age;
this.sex = sex;
this.owner = owner;
} @Override
public String toString() {
return "Sheep{" +
"name='" + name + '\'' +
", age=" + age +
", sex='" + sex + '\'' +
", owner=" + owner +
'}';
} //克隆该实例,使用默认的clone方法
@Override
protected Object clone() throws CloneNotSupportedException {
Sheep sheep =null;
sheep = (Sheep)super.clone();
return sheep;
}
}

测试类中测试

/**
* @author codermy
* @createTime 2020/6/16
*/
public class Client {
public static void main(String[] args) throws CloneNotSupportedException {
Person owner = new Person("马云");
Sheep sheep = new Sheep("tom",1,"male", owner);//新建sheep类 Sheep sheep1 = (Sheep)sheep.clone();//克隆该类
System.out.println(sheep.hashCode() + " " + sheep.owner.hashCode());
System.out.println(sheep + " "+ sheep.owner);
System.out.println(sheep1.hashCode()+ " " + sheep1.owner.hashCode());
System.out.println(sheep1 + " " + sheep1.owner);
sheep1.owner.setName("马化腾");
System.out.println(sheep.owner);
System.out.println(sheep1.owner);
}
}

输出

1163157884  1956725890
Sheep{name='tom', age=1, sex='male', owner=Person{name='马云'}} Person{name='马云'}
356573597 1956725890
Sheep{name='tom', age=1, sex='male', owner=Person{name='马云'}} Person{name='马云'}
Person{name='马化腾'}
Person{name='马化腾'}

我们可以看出浅克隆时对象的引用仅仅是指向了原空间,而并没有复制对象。

深克隆

在深克隆中,对值类型的成员变量进行值的复制,对引用类型的成员变量也进行引用对象的复制。

自定义clone过程实现深克隆

将上面Sheep类中的clone方法改写


@Override
protected Object clone() throws CloneNotSupportedException {
Sheep sheep =null;
sheep = (Sheep)super.clone();
sheep.owner = (Person) sheep.owner.clone();//引用对象的克隆方法
return sheep;
}

测试类测试

public class Client {
public static void main(String[] args) throws CloneNotSupportedException {
Person owner = new Person("马云");
Sheep sheep = new Sheep("tom",1,"male", owner); Sheep sheep1 = (Sheep)sheep.clone();
System.out.println(sheep.hashCode() + " " + sheep.owner.hashCode());
System.out.println(sheep + " "+ sheep.owner);
System.out.println(sheep1.hashCode()+ " " + sheep1.owner.hashCode());
System.out.println(sheep1 + " " + sheep1.owner);
sheep1.owner.setName("马化腾");
System.out.println(sheep.owner);
System.out.println(sheep1.owner);
}
}

输出

1163157884  1956725890
Sheep{name='tom', age=1, sex='male', owner=Person{name='马云'}} Person{name='马云'}
356573597 1735600054
Sheep{name='tom', age=1, sex='male', owner=Person{name='马云'}} Person{name='马云'}
Person{name='马云'}
Person{name='马化腾'}

这时候我们已经实现了深克隆,但是总觉得有点“浅浅克隆”的意思,如果person类中还有对象引用那不就是。。

禁止套娃

序列化实现深克隆

两个实体类实现序列化接口

Person类

public class Person implements Serializable {
String name; public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} @Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
'}';
} public Person(String name){
this.name = name;
} }

Sheep类

/**
* @author codermy
* @createTime 2020/6/16
*/
public class Sheep implements Serializable {
private String name;
private int age;
private String sex;
public Person owner;//对象引用 public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} public int getAge() {
return age;
} public void setAge(int age) {
this.age = age;
} public String getSex() {
return sex;
} public void setSex(String sex) {
this.sex = sex;
} public Person getOwner() {
return owner;
} public void setOwner(Person owner) {
this.owner = owner;
}
public Sheep() {
}
public Sheep(String name, int age, String sex, Person owner) {
this.name = name;
this.age = age;
this.sex = sex;
this.owner = owner;
} @Override
public String toString() {
return "Sheep{" +
"name='" + name + '\'' +
", age=" + age +
", sex='" + sex + '\'' +
", owner=" + owner +
'}';
} }

实现

**
* @author codermy
* @createTime 2020/7/24
*/
public class Client {
public static void main(String[] args) throws Exception {
Person owner = new Person("马云");
Sheep sheep = new Sheep("tom",1,"male", owner);
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(sheep);
ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(bos.toByteArray()));
Sheep sheep1 =(Sheep) ois.readObject();
bos.flush();oos.flush();
bos.close();oos.close();
ois.close();
System.out.println("Sheep: " + sheep);
System.out.println("Sheep1: " + sheep1);
System.out.println("================================");
System.out.println("Sheep: " + sheep.hashCode() + "++++++++++" + sheep.owner.hashCode());
System.out.println("Sheep1: " + sheep1.hashCode() + "++++++++++" + sheep1.owner.hashCode());
System.out.println("================================");
sheep1.owner.setName("马化腾");
System.out.println("Sheep: " + sheep.owner);
System.out.println("Sheep1: " + sheep1.owner);
}
}

输出

1163157884  1956725890
Sheep{name='tom', age=1, sex='male', owner=Person{name='马云'}} Person{name='马云'}
356573597 1735600054
Sheep{name='tom', age=1, sex='male', owner=Person{name='马云'}} Person{name='马云'}
Person{name='马云'}
Person{name='马化腾'}

原型模式的优缺点

优点:原型模式是在内存中二进制流的拷贝,要比new一个对象的性能要好,特别是需要产生大量对象时。

缺点:直接在内存中拷贝,构造函数是不会执行的。

java23种设计模式——四、原型模式的更多相关文章

  1. 二十四种设计模式:原型模式(Prototype Pattern)

    原型模式(Prototype Pattern) 介绍用原型实例指定创建对象的种类,并且通过拷贝这个原型来创建新的对象.示例有一个Message实体类,现在要克隆它. MessageModel usin ...

  2. c# 24种设计模式5原型模式(Prototype)

    前言 原型模式其实C# Object中已经提供了一个Clone( )方法,平时很少用到,最近读Retrofit源码时候看到有这种使用方式. 定义 原型模式就是在系统clone()标记的基础上,对Clo ...

  3. java23种设计模式之四:建造者模式

    在软件开发过程中有时需要创建一个复杂的对象,这个复杂对象通常由多个子部件按一定的步骤组合而成.例如:在新招收一个员工时,对个人信息对象的创建,在不同的阶段,需要个人信息的内容也不一样,姓名.性别.年龄 ...

  4. 【Unity与23种设计模式】原型模式(Prototype)

    GoF中定义: "使用原型对象来产生指定类的对象,所以产生对象时,是使用复制原型对象来完成." Unity中 开发者可以组装游戏对象 它可以包括复杂的组件 组装好了之后,就可以将其 ...

  5. 23种设计模式之原型模式(Prototype)

    在系统开发过程中,有时候有些对象需要被频繁创建,原型模式通过给出一个原型对象来指明所要创建的对象的类型,然后通过复制这个原型对象的办法,创建出更多同类型的对象.原型模式是一种对象创建型模式,用原型实例 ...

  6. 二十三种设计模式之原型模式的C#实现

    原型模式就是通过拷贝快速创建一个新的对象 本例UML如图 ColorBase [Serializable] public abstract class ColorBase { public int R ...

  7. 23种设计模式之原型模式(Prototype Pattern)

    原型模式 使用原型实例指定待创建对象的类型,并且通过复制这个原型来创建新的对象 分析: 孙悟空:根据自己的形状复制(克隆)出多个身外身 软件开发:通过复制一个原型对象得到多个与原型对象一模一样的新对象 ...

  8. php设计模式四 ---- 原型模式

    1.简介 用于创建重复的对象,同时又能保证性能.这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式 意图:用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象. 主要解决:在运 ...

  9. Java--23种设计模式之decorator模式

    装饰模式:装饰模式以对客户端透明的方式扩展对象的功能,是继承关系的一个替代方案,提供比继承更多的灵活性.动态给一个对象增加功能,这些功能可以再动态的撤消.增加由一些基本功能的排列组合而产生的非常大量的 ...

随机推荐

  1. ajax模拟表单提交,后台使用npoi实现导入操作 方式二

    页面代码: <form id="form1" enctype="multipart/form-data"> <div style=" ...

  2. JavaScript正则表达式相关方法

    一.正则表达式方法 var str="abcdefabcdef"; (1)reg.test(str); 查看字符串是否有满足正则表达式的内容,并返回一个布尔值true/false ...

  3. MySql大表分页(附独门秘技)

    问题背景 MySql(InnoDB)中的订单表需要按时间顺序分页查询,且主键不是时间维度递增,订单表在百万以上规模,此时如何高效地实现该需求? 注:本文并非主要讲解如何建立索引,以下的分析均建立在有合 ...

  4. Mybatis insert 获取主键自增id

    Mybatis insert 返回自增主键 mysql 准备一张带有自增主键的表users 字段:id,name,phone sql <!--插入记录并获取刚插入记录的主键--> < ...

  5. cocos2d-x_下载游戏引擎并创建第一个项目

    我是一名小白. 下载并创建游戏项目 第一步:去官网下载cocos2d-x http://www.cocos.com/download 第二步:将安装包里边的 setup.py 拖进命令行点击回车键 , ...

  6. 铁大树洞与市面上现有APP对比

    写在前面 铁大树洞这款APP严格来说并没有可以参照的对象,但如果非要说的话也可以有.这里我们选取百度贴吧进行对比. 百度贴吧 可以看到,百度贴吧的贴吧首页排版要更加好看,且在首页添加了各种分类.也许我 ...

  7. 用 Python 写个坦克大战

    坦克大战是一款策略类的平面射击游戏,于 1985 年由 Namco 游戏公司发布,尽管时至今日已经有了很多衍生类的游戏,但这款游戏仍然受到了相当一部分人的欢迎,本文我们看一下如何使用 Python 来 ...

  8. mogilefs 安装与配置

    安装步骤 配置yum 的epel源 yum install perl-Sys-Syslog perl-IO-AIO perl-Net-Netmask -y # 安装依赖的包 取得mogilefs的rp ...

  9. Java环境变量,jdk和jre的区别,面向对象语言编程

    什么是java? java是一门面向对象的编程语言,包括java SE, java ME, Java EE . 广泛使用的是作为后端语言的Java EE开发, 面向对象和面向过程? java,C++ ...

  10. 微信公众号如何将PDF上传到公众号?

    微信公众号如何将PDF上? 我们都知道创建一个微信公众号,在公众号中发布一些文章是非常简单的,但公众号添加附件下载的功能却被限制,如今可以使用小程序“微附件”进行在公众号中添加附件. 以下是公众号添加 ...