设计模式之原型模式
什么是原型模式
原型模式:通过new 产生一个对象需要非常繁琐的数据准备或访问权限,则可以使用原型模式
就是java中的克隆技术,以某个对象为原型,复制出新的对象,显新的对象具有原型对象的特点
克隆,类似于new,但是不同于new new创建的对象属性采取默认值,克隆出的对象属性和原型对象相同,并且克隆出的新的对象改变不会影响原型对象。
原型模式的实现,Cloneable接口和clone方法
原型模式怎么使用
我们以克隆羊多利为例实现浅复制
import java.util.Date;
public class Sheep implements Cloneable {
private String name;
private Date brithday;
public Sheep(String name, Date brithday) {
super();
this.name = name;
this.brithday = brithday;
}
public Sheep() {
super();
}
@Override
protected Object clone() throws CloneNotSupportedException {
Object object = super.clone(); // 调用object的clone 实现克隆
return object;
}
/**
* @return the name
*/
public String getName() {
return name;
}
/**
* @param name
* the name to set
*/
public void setName(String name) {
this.name = name;
}
/**
* @return the brithday
*/
public Date getBrithday() {
return brithday;
}
/**
* @param brithday
* the brithday to set
*/
public void setBrithday(Date brithday) {
this.brithday = brithday;
}
}
package Prototype;
import java.util.Date;
/**
* 原型模式,克隆模式(浅克隆)
*/
public class Client {
public static void main(String[] args) throws CloneNotSupportedException {
Date date = new Date();
Sheep sheep = new Sheep("多利的原型", date);
Sheep sheep2 = (Sheep) sheep.clone();
System.out.println(sheep);
System.out.println(sheep.getName());
System.out.println(sheep.getBrithday());
date.setTime(43243151543252L);
System.out.println(sheep.getBrithday());
sheep2.setName("多利");
System.out.println();
System.out.println("---------克隆后--------------");
System.out.println(sheep2);
System.out.println(sheep2.getName());
System.out.println(sheep2.getBrithday());
}
}
//Prototype.Sheep@2a139a55
//多利的原型
//Fri Apr 21 10:04:39 GMT+08:00 2017
//Wed Apr 27 18:32:23 GMT+08:00 3340
//
//---------克隆后--------------
//Prototype.Sheep@70dea4e
//多利
//Wed Apr 27 18:32:23 GMT+08:00 3340
//浅复制共用一个date对象,当date对象修改时克隆对象也被修改
深复制(将属性也进行克隆)
package Prototype;
import java.util.Date;
public class Sheep2 implements Cloneable{
private String name;
private Date brithday;
public Sheep2(String name, Date brithday) {
super();
this.name = name;
this.brithday = brithday;
}
public Sheep2() {
super();
}
@Override
protected Object clone() throws CloneNotSupportedException {
Object object = super.clone(); // 调用object的clone 实现克隆
Sheep2 sheep2 = (Sheep2) object;
sheep2.brithday = (Date) this.brithday.clone();//将date进行可克隆
return object;
}
/**
* @return the name
*/
public String getName() {
return name;
}
/**
* @param name
* the name to set
*/
public void setName(String name) {
this.name = name;
}
/**
* @return the brithday
*/
public Date getBrithday() {
return brithday;
}
/**
* @param brithday
* the brithday to set
*/
public void setBrithday(Date brithday) {
this.brithday = brithday;
}
}
package Prototype;
import java.util.Date;
/**
* 原型模式,(深复制)
*/
public class Client2 {
public static void main(String[] args) throws CloneNotSupportedException {
Date date = new Date();
Sheep2 sheep = new Sheep2("多利的原型", date);
Sheep2 sheep2 = (Sheep2) sheep.clone();
System.out.println(sheep);
System.out.println(sheep.getName());
System.out.println(sheep.getBrithday());
date.setTime(43243151543252L);
System.out.println(sheep.getBrithday());
sheep2.setName("多利");
System.out.println();
System.out.println("---------克隆后--------------");
System.out.println(sheep2);
System.out.println(sheep2.getName());
System.out.println(sheep2.getBrithday());
}
}
//Prototype.Sheep2@2a139a55
//多利的原型
//Fri Apr 21 10:13:18 GMT+08:00 2017
//Wed Apr 27 18:32:23 GMT+08:00 3340
//
//---------克隆后--------------
//Prototype.Sheep2@70dea4e
//多利
//Fri Apr 21 10:13:18 GMT+08:00 2017
//深复制,将date属性进行复制,改变date之后克隆对象的date不变,克隆之后为两个date对象
用序列化反序列化实现深克隆
package Prototype;
import java.io.Serializable;
import java.util.Date;
public class Sheep implements Cloneable,Serializable{
private String name;
private Date brithday;
public Sheep(String name, Date brithday) {
super();
this.name = name;
this.brithday = brithday;
}
public Sheep() {
super();
}
@Override
protected Object clone() throws CloneNotSupportedException {
Object object = super.clone(); // 调用object的clone 实现克隆
return object;
}
/**
* @return the name
*/
public String getName() {
return name;
}
/**
* @param name
* the name to set
*/
public void setName(String name) {
this.name = name;
}
/**
* @return the brithday
*/
public Date getBrithday() {
return brithday;
}
/**
* @param brithday
* the brithday to set
*/
public void setBrithday(Date brithday) {
this.brithday = brithday;
}
}
package Prototype;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.Date;
public class Client3 {
public static void main(String[] args) throws Exception {
Date date = new Date();
Sheep sheep = new Sheep("多利的原型", date);
System.out.println(sheep);
System.out.println(sheep.getName());
System.out.println(sheep.getBrithday());
//用序列化和反序列化实现深复制
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(sheep);
byte[] bytes = bos.toByteArray();
ByteArrayInputStream bis = new ByteArrayInputStream(bytes);
ObjectInputStream ois = new ObjectInputStream(bis);
Sheep sheep2 = (Sheep) ois.readObject();
date.setTime(43243151543252L);
System.out.println(sheep.getBrithday());
sheep2.setName("多利");
System.out.println();
System.out.println("---------克隆后--------------");
System.out.println(sheep2);
System.out.println(sheep2.getName());
System.out.println(sheep2.getBrithday());
}
}
//Prototype.Sheep@2a139a55
//多利的原型
//Fri Apr 21 10:30:14 GMT+08:00 2017
//Wed Apr 27 18:32:23 GMT+08:00 3340
//
//---------克隆后--------------
//Prototype.Sheep@677327b6
//多利
//Fri Apr 21 10:30:14 GMT+08:00 2017
/**
* 测试new方式和clone方式创建对象耗时
*
* 如果需要创建多个对象,并且创建的对象比较耗时,可以用原型模式。
*/
public class Client4 {
public static void main(String[] args) throws CloneNotSupportedException {
newtest(1000);
clonetest(1000);
}
public static void newtest(int size) {
long start = System.currentTimeMillis();
for (int i = 0; i < size; i++) {
computer c = new computer();
}
long end = System.currentTimeMillis();
System.out.println("new 的方式耗时" + (end - start));
}
public static void clonetest(int size) throws CloneNotSupportedException {
long start = System.currentTimeMillis();
computer c = new computer();
for (int i = 0; i < size; i++) {
computer c2 = (computer) c.clone();
}
long end = System.currentTimeMillis();
System.out.println("clone" + " 的方式耗时" + (end - start));
}
}
class computer implements Cloneable {
public computer() {
try {
Thread.sleep(10);
// 模拟创建对象耗时
} catch (InterruptedException e) {
e.printStackTrace();
}
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
//new 的方式耗时10188
//clone 的方式耗时10
什么时候用原型模式
开发中常见的场景:
一般和工厂方法模式一起出现,通过克隆的方式创建对象,然后由工厂提供给调用者
Spring的bean的创建就是单例模式和克隆模式。
创建型模式:都是用来创建对象的
单利模式:保证类只有一个对象,并且提供一个访问该实例的全局访问点。
工厂模式:
简单工厂模式:用来生产同一等级结构的任意产品(对于新的产品,秀要修改已有的代码)
工厂方法模式:用于生产同一等级结构中的固定产品。(支持增加新产品)
抽象工厂模式:用来生产不同产品族的全部产品。(对于增加新的产品无能为力)
建造者模式:
分离对象的子组建的单独构造(由builder负责)和装配(有Director负责)。从而可以构造出复杂的对象。
原型模式 :
通过new产生一个需要非常繁琐的数据准备或者访问权限,可以使用原型模式。