设计模式-创建型-原型模式
原型模式
原型模式(Prototype Pattern)是指原型实例指定创建对象的种类,并且通过复制这些原型创建新的对象
原型模式适用场景:
-
类初始化消耗资源较多
-
使用new生成一个对象需要非常繁琐的过程(数据准备、访问权限)
-
构造函数比较复杂
-
在循环体中产生大量对象
1、浅克隆
一个标准的原型模式应该这样设计,首先创建一个原型Prototype接口
/**
* 原型Prototype接口
* @author ss_419
*/
public interface Prototype {
Prototype clone();
}
创建具体需要克隆的类ConcretePrototypeA:
/**
* TODO 具体需要克隆的类
*
* @author ss_419
* @version 1.0
* @date 2023/9/1 11:02
*/
public class ConcretePrototypeA implements Prototype{
private int age;
private String name;
private List hobbies;
/**
* 实现Prototype原型类的clone方法
* 注意:这里的克隆是浅克隆,对引用对象克隆的是地址,而不是全新的值
* @return
*/
@Override
public ConcretePrototypeA clone() {
// 原型模式:指定原型实例指定创建对象的种类,并且通过复制这些原型创建新的对象
ConcretePrototypeA concretePrototype = new ConcretePrototypeA();
// 设置该对象原型类的属性
concretePrototype.setAge(this.getAge());
concretePrototype.setName(this.getName());
concretePrototype.setHobbies(this.getHobbies());
// 返回复制实例
return concretePrototype;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List getHobbies() {
return hobbies;
}
public void setHobbies(List hobbies) {
this.hobbies = hobbies;
}
}
创建Client类:
/**
* TODO 在客户端类中进行克隆操作-生成对象
*
* @author ss_419
* @version 1.0
* @date 2023/9/1 11:18
*/
public class Client {
// 注入原型对象
private Prototype prototype;
public Client(Prototype prototype) {
this.prototype = prototype;
}
/**
* 开始克隆,该方法只需指定克隆对象的类型即可
* @return
*/
public Prototype startClone(Prototype concretePrototype){
return (Prototype)concretePrototype.clone();
}
}
测试代码:
public class PrototypeTest {
public static void main(String[] args) {
// 创建一个具体的需要克隆的对象
ConcretePrototypeA concretePrototype = new ConcretePrototypeA();
// 填充属性,方便测试
concretePrototype.setAge(19);
concretePrototype.setName("ukyo");
List hobbies = new ArrayList<String>();
hobbies.add("xxxx1");
hobbies.add("xxxx2");
hobbies.add("xxxx3");
concretePrototype.setHobbies(hobbies);
System.out.println("concretePrototype = " + concretePrototype);
// 创建client对象,准备开始克隆s
Client client = new Client(concretePrototype);
ConcretePrototypeA clone =
// 这里的克隆仅仅对当前对象的值进行的复制
(ConcretePrototypeA) client.startClone(concretePrototype);
System.out.println("clone = " + clone);
/***
* 因为是浅拷贝,所以对象中的引用地址没有重新分配内存空间,就算进行了克隆,它们还是指向同一块内存空间
* 可以看出,hobbies的引用地址是相同的,意味着复制的不是值,而是引用的地址
*
* 浅克隆只是完整复制了值类型数据,没有赋值引用对象
*/
System.out.println("克隆对象中的引用类型地址:" + clone.getHobbies());
System.out.println("原对象中的引用类型地址:" + concretePrototype.getHobbies());
System.out.println("对象地址比较 => "+(concretePrototype.getHobbies() == clone.getHobbies()));
}
}
2、深拷贝
/**
* TODO 原型猴子类Monkey
*
* @author ss_419
* @version 1.0
* @date 2023/9/1 11:28
*/
public class Monkey {
public int height;
public int weight;
public Date birthday;
}
public class JinGuBang implements Serializable {
public float h = 100;
public float d = 10;
public void big(){
this.d *= 2;
this.h *= 2;
}
public void small(){
this.d /= 2;
this.h /= 2;
}
}
public class QiTianDaSheng extends Monkey implements Cloneable, Serializable {
public JinGuBang jinGuBang;
public QiTianDaSheng() {
// 只是初始化
this.birthday = new Date();
this.jinGuBang = new JinGuBang();
}
@Override
protected Object clone() throws CloneNotSupportedException {
return this.deepClone();
}
/**
* 创建深拷贝方法
*/
public Object deepClone() {
try {
// 创建字节输出流
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(this);
ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bis);
// 读取输入流中的对象,并强转
QiTianDaSheng copy = (QiTianDaSheng) ois.readObject();// 生成一个全新的copy对象
copy.birthday = new Date();
return copy;
} catch (Exception e) {
e.printStackTrace();
// 克隆失败返回null
return null;
}
}
/**
* 浅拷贝
*
*/
public QiTianDaSheng shallowClone(QiTianDaSheng target){
QiTianDaSheng qiTianDaSheng = new QiTianDaSheng();
// 从目标对象中拷贝值
qiTianDaSheng.height = target.height;
qiTianDaSheng.weight = target.weight;
// 拷贝引用对象,这里很明显可以看出指向同一块内存空间
qiTianDaSheng.jinGuBang = target.jinGuBang;
qiTianDaSheng.birthday = new Date();
return qiTianDaSheng;
}
}
深拷贝测试:
/**
* TODO 深拷贝测试
*
* @author ss_419
* @version 1.0
* @date 2023/9/1 11:39
*/
public class DeepTest {
public static void main(String[] args) {
QiTianDaSheng qiTianDaSheng = new QiTianDaSheng();
// 深拷贝
try{
QiTianDaSheng clone =
(QiTianDaSheng) qiTianDaSheng.clone();
System.out.println("通过序列化操作进行深拷贝 => "+ (clone.jinGuBang == qiTianDaSheng.jinGuBang));
}catch (Exception e){
e.printStackTrace();
}
// 浅拷贝
QiTianDaSheng q = new QiTianDaSheng();
QiTianDaSheng n = q.shallowClone(q);
System.out.println("浅克隆 => "+ (q.jinGuBang == n.jinGuBang));
}
}
posted on 2023-09-01 13:43 JavaCoderPan 阅读(9) 评论(0) 编辑 收藏 举报