设计模式——原型模式
一、原型模式介绍
原型设计模式(Prototype Pattern)是指原型实例指定创建对象的种类,并且通过复制这些原型以创建新的对象。
二、原型模式分类
1、浅克隆
2、深克隆
三、原型模式代码实例
场景实例
现有一只羊Dolly,年龄为1,颜色为白色,它的伴侣羊名为Jack,年龄为2,颜色为黑色。
1)浅拷贝
浅拷贝介绍
(1)对于基本数据类型的成员变量,浅拷贝会直接进行至传递,将该属性复制一份给新的对象。(堆里产生新的对象)
(2)对于引用数据类型的成员变量(数组、类的对象),浅拷贝进行引用传递,即将该成员变量的引用值(内存地址)复制给一份新的对象(此时堆中未产生新的对象)。在此情况下,对该成员变量的修改会影响到另一个成员变量的值。
(3)浅拷贝一般使用默认的clone()方法实现。
浅拷贝实现多利羊克隆
//1.饿汉式(静态变量)
//原型类
public class Sheep implements Cloneable {
private String name;
private int age;
private String color;
public Sheep friend;
public Sheep(String name, int age, String color) {
this.name = name;
this.age = age;
this.color = color;
}
/*getter,setter方法*/
@Override
public String toString() {
return "Sheep{" +
"name='" + name + '\'' +
", age=" + age +
", color='" + color + '\'' +
", friend=" + friend +
'}';
}
//克隆该实例,使用默认克隆方法完成
@Override
public Object clone() throws CloneNotSupportedException{
Sheep sheep = null;
try{
sheep = (Sheep) super.clone();//默认clone()方法
}catch (Exception e){
System.out.println(e.getMessage());
}
return sheep;
}
}
public class Client {
public static void main(String[] args) throws Exception{
//传统方法
Sheep sheep = new Sheep("Dolly",1,"白色");
sheep.setFriend(new Sheep("jack",2,"黑色"));
Sheep sheep1 = (Sheep) sheep.clone();
Sheep sheep2 = (Sheep) sheep.clone();
Sheep sheep3 = (Sheep) sheep.clone();
Sheep sheep4 = (Sheep) sheep.clone();
System.out.println(sheep.hashCode()+" friend"+sheep.getFriend().hashCode());
System.out.println(sheep1.hashCode()+" friend"+sheep1.getFriend().hashCode());
System.out.println(sheep2.hashCode()+" friend"+sheep2.getFriend().hashCode());
System.out.println(sheep3.hashCode()+" friend"+sheep3.getFriend().hashCode());
System.out.println(sheep4.hashCode()+" friend"+sheep4.getFriend().hashCode());
...
}
}
1554874502 friend1846274136
1639705018 friend1846274136
1627674070 friend1846274136
1360875712 friend1846274136
1625635731 friend1846274136
...
优缺点
(1)优点:基本属性均实现克隆。
(2)缺点:引用类型未实现克隆。
2)深拷贝
深拷贝基本介绍
(1)将整个对象,包括对象的引用类型进行拷贝。
(2)实现方法: 1)重写clone()方法;2)对象序列化
(1)重写clone()方法实现多利羊克隆
//重写clone()方法
public class Sheep implements Cloneable {
private String name;
private int age;
private String color;
public Sheep friend;
public Sheep(String name, int age, String color) {
this.name = name;
this.age = age;
this.color = color;
}
public Sheep getFriend() {
return friend;
}
public void setFriend(Sheep friend) {
this.friend = friend;
}
@Override
public String toString() {
return "Sheep{" +
"name='" + name + '\'' +
", age=" + age +
", color='" + color + '\'' +
", friend=" + friend +
'}';
}
//克隆该实例,使用默认克隆方法调用默认克隆方法,对引用类型重写克隆方法
@Override
public Object clone() throws CloneNotSupportedException{
Object deep = null;
deep = super.clone();
//对引用类型的属性进行单独处理
Sheep sheep = (Sheep) deep;
if(friend != null) {
sheep.friend = (Sheep) friend.clone();
return sheep;
}else{
return sheep;
}
}
}
public class Client {
public static void main(String[] args) throws Exception{
//传统方法
Sheep sheep = new Sheep("Dolly",1,"白色");
sheep.setFriend(new Sheep("Jack",2,"黑色"));
Sheep sheep1 = (Sheep) sheep.clone();
Sheep sheep2 = (Sheep) sheep.clone();
Sheep sheep3 = (Sheep) sheep.clone();
Sheep sheep4 = (Sheep) sheep.clone();
System.out.println("sheep:"+sheep.hashCode()+" friend:"+sheep.getFriend().hashCode());
System.out.println("sheep:"+sheep1.hashCode()+" friend:"+sheep1.getFriend().hashCode());
System.out.println("sheep:"+sheep2.hashCode()+" friend:"+sheep2.getFriend().hashCode());
System.out.println("sheep:"+sheep3.hashCode()+" friend:"+sheep3.getFriend().hashCode());
System.out.println("sheep:"+sheep4.hashCode()+" friend:"+sheep4.getFriend().hashCode());
...
}
}
//结果
sheep:1554874502 friend:1846274136
sheep:1639705018 friend:1627674070
sheep:1360875712 friend:1625635731
sheep:1580066828 friend:491044090
sheep:644117698 friend:1872034366
(2)对象序列化实现多利羊克隆
public class Sheep implements Serializable {
private static final long serialVersionUID = 1L;
private String name;
private int age;
private String color;
public Sheep friend;
public Sheep(String name, int age, String color) {
this.name = name;
this.age = age;
this.color = color;
}
public Sheep getFriend() {
return friend;
}
public void setFriend(Sheep friend) {
this.friend = friend;
}
@Override
public String toString() {
return "Sheep{" +
"name='" + name + '\'' +
", age=" + age +
", color='" + color + '\'' +
", friend=" + friend +
'}';
}
public Object deepClone(){
//创建流对象
ByteArrayOutputStream bos = null;
ObjectOutputStream oos = null;
ByteArrayInputStream bis = null;
ObjectInputStream ois = null;
try{
//序列化
bos = new ByteArrayOutputStream();
oos = new ObjectOutputStream(bos);
oos.writeObject(this); //当前这个对象以对象流的方式输出
//反序列化
bis = new ByteArrayInputStream(bos.toByteArray());
ois = new ObjectInputStream(bis);
Sheep copyObj = (Sheep) ois.readObject();
return copyObj;
}catch (Exception e){
e.printStackTrace();
return null;
}finally {
try{
bos.close();
oos.close();
bis.close();
ois.close();
//可用try-with语句避免xxx.close()的步骤,具体操作请自行查阅
}catch (Exception e){
e.printStackTrace();
}
}
}
}
public class Client {
public static void main(String[] args) throws Exception{
//传统方法
Sheep sheep = new Sheep("Dolly",1,"白色");
sheep.setFriend(new Sheep("Jack",2,"黑色"));
Sheep sheep1 = (Sheep) sheep.deepClone();
Sheep sheep2 = (Sheep) sheep.deepClone();;
Sheep sheep3 = (Sheep) sheep.deepClone();;
Sheep sheep4 = (Sheep) sheep.deepClone();;
System.out.println("sheep:"+sheep.hashCode()+" friend:"+sheep.getFriend().hashCode());
System.out.println("sheep:"+sheep1.hashCode()+" friend:"+sheep1.getFriend().hashCode());
System.out.println("sheep:"+sheep2.hashCode()+" friend:"+sheep2.getFriend().hashCode());
System.out.println("sheep:"+sheep3.hashCode()+" friend:"+sheep3.getFriend().hashCode());
System.out.println("sheep:"+sheep4.hashCode()+" friend:"+sheep4.getFriend().hashCode());
}
}
//结果
sheep:491044090 friend:1670675563
sheep:2093176254 friend:1854731462
sheep:317574433 friend:885284298
sheep:1389133897 friend:1534030866
sheep:664223387 friend:824909230
优缺点
(1)优点:如果原始对象变化,其克隆对象也会发生相应变化,无需修改代码
(2)缺点:实现深拷贝可能需要比较复杂的代码;对已有拷贝类进行改造时需要修改器源代码,违背了OCP原则
四、深克隆破坏单例模式
若克隆对象是单例对象,则深拷贝会破坏单例模式。为防止此情况,1)单例类不实现Cloneable接口 2)重写clone()方法,让其返回单例对象即可
@Override
protected Object Clone() throws CloneNotSupportedException{
return INSTANCE;
}
四、原型模式在实际中的运用
Spring中的原型模式
//beans.xml
...
<!-- scope="prototype" 即 原型模式来创建 -->
<bean id="id01" class="com.atguigu.spring.bean.Sheep"
scope="prototype"/>
...
public static void main(String[] args) {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");
//通过id获取Sheep
Object bean = applicationContext.getBean("id01");
System.out.println("bean" + bean);
Object bean2 = applicationContext.getBean("id01");
System.out.println("bean2" + bean2);
System.out.println(bean == bean2); // false
}
JDK中的原型模式
//ArrayList实现clone()方法的重写
/**
*
* @return 返回ArrayList实例的拷贝
*/
public Object clone() {
try {
ArrayList<?> v = (ArrayList<?>) super.clone();
v.elementData = Arrays.copyOf(elementData, size);
v.modCount = 0;
return v;
} catch (CloneNotSupportedException e) {
// this shouldn't happen, since we are Cloneable
throw new InternalError(e);
}
}
...
}
五、原型模式的使用场景
1)类初始化消耗资源过多
2)使用new生成一个对象需要非常繁琐的过程(数据准备,访问权限等)
3)构造函数比较复杂
4)循环体中产生大量对象