JAVA的23种设计模式之原型模式
程序员文章站
2022-06-13 07:55:31
...
原型模式:
- 通过new 产生一个对象需要非常繁琐的数据准备或者访问权限,则可以使用原型模式
- 就是Java中的克隆技术,以某个对象为原型,复制出新的对象,显然新的对象具备原型对象的特点。
- 优势有:效率高于new 方式
- 克隆类似于new ,但是不同于new, 使用new创建的新对象的属性是采用的默认值。克隆出的对象属性和原型对象相同。并且克隆出的新对象改变不会影响原型对象。然后在修改克隆对象的值。
原型模式实现:
- Cloneable接口和clone方法
- Prototype 模式中实现起来最困难的地方就是内存复制操作。所幸 JAVA中提供了clone()方法替我们做了绝大部分事情。
测试原型模式 浅克隆:
创建需要克隆的类:
package cn.fllday.prototype;
import java.util.Date;
/**
* 创建需要克隆的对象。 实现原型模式
* 如果需要克隆,就必须实现Cloneable 接口
* @author gssznb
*
*/
public class Sheep implements Cloneable {
private String name;
private Date date;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Date getDate() {
return date;
}
public void setDate(Date date) {
this.date = date;
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
@Override
public String toString() {
return "Sheep [name=" + name + ", date=" + date + "]";
}
}
测试原型模式:浅克隆
package cn.fllday.prototype;
import java.util.Date;
/**
* 测试原型模式 浅克隆
* @author gssznb
*
*/
public class Client01 {
/**
* 浅克隆: 直接使用clone 克隆一个对象。如果该对象中含有其他对象 比如 Date(); 如果我修改了Date的值
* 但是 克隆的对象和被克隆的对象都指向到了 该 Date() 对象。 所以 两个对象的Date 都会进行改变。
* @param args
* @throws Exception
*/
public static void main(String[] args) throws Exception {
Date date = new Date(1111111111111L);
Sheep sheep = new Sheep();
sheep.setName("多利");
sheep.setDate(new Date());
Sheep clone = (Sheep) sheep.clone();
date.setTime(55555555555L);
System.out.println(sheep);
System.out.println(clone);
}
}
原型模式深克隆:
创建需要深克隆的对象
package cn.fllday.prototype;
import java.util.Date;
/**
* 创建需要克隆的对象。 实现原型模式
* 如果需要克隆,就必须实现Cloneable 接口
* @author gssznb
*
*/
public class Sheep02 implements Cloneable {
private String name;
private Date date;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Date getDate() {
return date;
}
public void setDate(Date date) {
this.date = date;
}
/**
* 实现深复制 需要 重新实现clone 方法
* 对 该对象中的对象 执行一个clone方法 并且 设置给 需要返回的对象
*/
@Override
protected Object clone() throws CloneNotSupportedException {
Object obj = super.clone();
Sheep02 sheep = (Sheep02) obj;
Date clone = (Date)sheep.getDate().clone();
sheep.setDate(clone);
return sheep;
}
@Override
public String toString() {
return "Sheep [name=" + name + ", date=" + date + "]";
}
}
测试原型模式:深克隆
package cn.fllday.prototype;
import java.util.Date;
/**
* 原型模式 : 深复制
* @author gssznb
*
*/
public class Client03 {
public static void main(String[] args) throws CloneNotSupportedException {
Date date = new Date(1111111111111L);
Sheep02 sheep = new Sheep02();
sheep.setName("多利");
sheep.setDate(date);
Sheep02 clone = (Sheep02) sheep.clone();
date.setTime(55555555555L);
System.out.println(sheep);
System.out.println(clone);
}
}
通过序列化实现原型模式:
package cn.fllday.prototype;
import java.io.Serializable;
import java.util.Date;
/**
* 创建需要克隆的对象。 实现原型模式
* 如果需要克隆,就必须实现Cloneable 接口
* @author gssznb
*
*/
public class Sheep04 implements Cloneable,Serializable {
private String name;
private Date date;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Date getDate() {
return date;
}
public void setDate(Date date) {
this.date = date;
}
@Override
public String toString() {
return "Sheep [name=" + name + ", date=" + date + "]";
}
}
使用序列化 实现原型模式深克隆:
package cn.fllday.prototype;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.Date;
/**
* 通过反序列化 实现深复制。
* 反序列化过来的对象 直接就是不同的对象。
* @author gssznb
*
*/
public class Client04 {
public static void main(String[] args) throws IOException, ClassNotFoundException {
Date date = new Date(555555555L);
Sheep04 s1 = new Sheep04();
s1.setName("多礼");
s1.setDate(date);
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(s1);
byte[] bytes = bos.toByteArray();
ByteArrayInputStream bis = new ByteArrayInputStream(bytes);
ObjectInputStream ois = new ObjectInputStream(bis);
Sheep04 s2 = (Sheep04)ois.readObject();
date.setTime(999999999999L);
System.out.println(s1);
System.out.println(s2);
}
}
测试使用克隆和new的差距
package cn.fllday.prototype;
import java.util.ArrayList;
import java.util.List;
/**
* 测试普通new 方法和 clone 方法的效率差异
* 如果需要短时间内创建大量的对象。并且new的时间比较耗时。就可以考虑使用原型模式
* 如果new的时间越长,那么 效率差异越来越大
* @author gssznb
*
*/
public class Clent05 {
public static void main(String[] args) throws CloneNotSupportedException {
testClone(1000);
testNew(1000);
}
public static void testNew(int size) {
long start = System.currentTimeMillis();
for (int i = 0; i < size; i++) {
new Apple();
}
long end = System.currentTimeMillis();
System.out.println("使用new的方式:" + (end - start));
}
public static void testClone(int size) throws CloneNotSupportedException {
Apple apple = new Apple();
long start = System.currentTimeMillis();
List<Apple> apples = new ArrayList<>();
for (int i = 0; i < size; i++) {
Apple clone = (Apple) apple.clone();
apples.add(clone);
}
long end = System.currentTimeMillis();
System.out.println("使用clone的方式:" + (end - start));
}
}
class Apple implements Cloneable{
String name;
public Apple() {
// TODO Auto-generated constructor stub
try {
// 使用sleep沉睡十毫秒。 模拟创建对象比较复杂
Thread.sleep(10);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
@Override
protected Object clone() throws CloneNotSupportedException {
// TODO Auto-generated method stub
return super.clone();
}
}
测试结果:
使用clone的方式:0
使用new的方式:10608
哈哈 就是这么快