原型(Prototype)模式的定义如下:用一个已经创建的实例作为原型,通过复制该原型对象来创建一个和原型相同或相似的新对象。在这里,原型实例指定了要创建的对象的种类。用这种方式创建对象非常高效,根本无须知道对象创建的细节。原型模式包含以下主要角色。
深克隆与与浅克隆:Object类的clone方法只会克隆对象中的基本的数据类型,对于数组、容器对象、引用对象等都不会克隆,这就是浅克隆。如果要实现深克隆,必须将原型模式中的数组、容器对象、引用对象等另行克隆。
由于 Java 提供了对象的 clone() 方法,所以用 Java 实现原型模式很简单。
1、创建Prototype的成员属性:
/**
* @author FluffyCatkin
* @version 1.0
* @date 2021-03-31 0:12
* @description Prototype的成员变量
*/
public class Member implements Cloneable{
private String position;
public Member(String position) {
this.position = position;
}
public void setPosition(String position) {
this.position = position;
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
@Override
public String toString() {
return "Member{" +
"position='" + position + '\'' +
'}';
}
}
2、创建具体原型类Prototype:
import java.util.ArrayList;
public class Prototype implements Cloneable{
private String name ;
private int age;
private ArrayList<String> hobbies;
private Member member;
public Prototype(String name, int age, ArrayList<String> hobbies, Member member) {
this.name = name;
this.age = age;
this.hobbies = hobbies;
this.member = member;
System.out.println("通过构造方法创建对象。。。。。。");
}
/**
* 浅克隆
*/
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
/**
* 深克隆
*/
// @Override
// protected Object clone() throws CloneNotSupportedException {
// Prototype clone = (Prototype) super.clone();
// clone.setHobbies((ArrayList) clone.getHobbies().clone());
// clone.setMember((Member) clone.getMember().clone());
// return clone;
// }
public void setName(String name){
this.name = name;
}
public void setHobbies(ArrayList<String> hobbies) {
this.hobbies = hobbies;
}
public ArrayList<String> getHobbies() {
return hobbies;
}
public Member getMember() {
return member;
}
public void setMember(Member member) {
this.member = member;
}
@Override
public String toString() {
return "Prototype{" +
"name='" + name + '\'' +
", age=" + age +
", hobbies=" + hobbies +
", member=" + member +
'}';
}
}
3、创建测试类(访问类):
import java.util.ArrayList;
/**
* 原型模式
* 原型模式的定义与特点:
* 原型(Prototype)模式的定义如下:用一个已经创建的实例作为原型,通过复制该原型对象来创建一个和原型相同或相似的新对象。在这里,
* 原型实例指定了要创建的对象的种类。用这种方式创建对象非常高效,根本无须知道对象创建的细节。例如,Windows 操作系统的安装通常较耗时,
* 如果复制就快了很多。在生活中复制的例子非常多,这里不一一列举了。
* 原型模式的结构与实现由于 Java 提供了对象的 clone() 方法,所以用 Java 实现原型模式很简单。
* 模式的结构
* 原型模式包含以下主要角色。
* 抽象原型类:规定了具体原型对象必须实现的接口。 (Cloneable)
* 具体原型类:实现抽象原型类的 clone() 方法,它是可被复制的对象。 (Prototype)
* 访问类:使用具体原型类中的 clone() 方法来复制新的对象。 (Main.class)
*/
public class Main {
@Test
public void prototypeTest() throws CloneNotSupportedException {
Member initMember = new Member("c#");
ArrayList<String> initHobbies = new ArrayList<>();
initHobbies.add("play");
Prototype prototype = new Prototype("张三",18,initHobbies,initMember);
System.out.println("复制前");
System.out.println("被克隆对象:"+prototype);
Prototype prototype1 = (Prototype) prototype.clone();
System.out.println("复制后");
System.out.println("是否同一对象:"+(prototype==prototype1?"是":"否"));
System.out.println("修改被克隆对象属性:");
prototype.setName("李四");
initHobbies.add("eat");
initMember.setPosition("java");
System.out.println("被克隆对象:"+prototype);
System.out.println("克隆出的对象:"+prototype1);
}
}
运行结果:
通过构造方法创建对象。。。。。。
复制前
被克隆对象:Prototype{name='张三', age=18, hobbies=[play], member=Member{position='c#'}}
复制后
是否同一对象:否
修改被克隆对象属性:
被克隆对象:Prototype{name='李四', age=18, hobbies=[play, eat], member=Member{position='java'}}
克隆出的对象:Prototype{name='张三', age=18, hobbies=[play, eat], member=Member{position='java'}}
当修改被克隆对象hobbies与member属性的时候,克隆出来对象的hobbies与member属性也被修改,可见这两个属性都是同一对象引用,而String类型的name以及基础类型的age属性是不会被同时修改的,可见不是同一引用。浅克隆只复制对象的String类型属性以及一些基本类型属性,是不完全克隆。
运行结果:
通过构造方法创建对象。。。。。。
复制前
被克隆对象:Prototype{name='张三', age=18, hobbies=[play], member=Member{position='c#'}}
复制后
是否同一对象:否
修改被克隆对象属性:
被克隆对象:Prototype{name='李四', age=18, hobbies=[play, eat], member=Member{position='java'}}
克隆出的对象:Prototype{name='张三', age=18, hobbies=[play], member=Member{position='c#'}}
当修改被克隆对象name、age、hobbies以及member属性的时候,克隆出来对象的hobbies与member属性并未被修改,可见通过这种深克隆的方法,把所有的属性都创建一个新的内存对象,并使被克隆对象与克隆出的对象所有属性有不同的地址引用,深克隆的复制更加彻底。
注意:上面代码在执行克隆的时候并未打印构造方法中的:“通过构造方法创建对象。。。。。。”,因此可见,使用原型模式复制对象不会调用类的构造方法。因为对象的复制是通过调用Object类的clone方法来完成的,它直接在内存中复制数据,因此不会调用到类的构造方法。不但构造方法中的代码不会执行,甚至连访问权限都对原型模式无效。还记得单例模式吗?单例模式中,只要将构造方法的访问权限设置为private型,就可以实现单例。但是clone方法直接无视构造方法的权限,所以,单例模式与原型模式是冲突的,在使用时要特别注意。
原型模式通常适用于以下场景。
原型模式的优点:
原型模式的缺点:
代码地址:https://gitee.com/fluffycatkin/JavaDesignModel.git
原文出处:
https://blog.csdn.net/zhengzhb/article/details/7393528
http://c.biancheng.net/view/1343.html