- 1、原型模式
- 1.1、传统方式实现
- 1.2、原型模式实现克隆
- 1.3、Spring中原型模式的使用
- 1.4、浅拷贝与深拷贝
- 1.5、总结
原型模式也属于创建型模式,所以其本质也是在于类的创建。原型模式指对类进行克隆。
以克隆羊为例:
1.1、传统方式实现我们看看传统的写法
羊类:
public class Sheep {
private String name;
private int age;
private String color;
//...构造方法,toString方法,get、set
}
我们传统的写法对它怎么进行克隆呢
public class Client {
public static void main(String[] args) {
Sheep sheep = new Sheep("肖恩", 12, "红色");
Sheep sheep1 = new Sheep(sheep.getName(), sheep.getAge(), sheep.getColor());
Sheep sheep2 = new Sheep(sheep.getName(), sheep.getAge(), sheep.getColor());
Sheep sheep3 = new Sheep(sheep.getName(), sheep.getAge(), sheep.getColor());
Sheep sheep4 = new Sheep(sheep.getName(), sheep.getAge(), sheep.getColor());
System.out.println(sheep.toString());
System.out.println(sheep1.toString());
System.out.println(sheep2.toString());
System.out.println(sheep3.toString());
System.out.println(sheep4.toString());
}
在传统的方式中,我们使用原有的这个对象,进行重复new新对象,并每次获取原有对象,进行克隆。
优点:比较好理解,简单易操作
缺点:
- 每次需要获取原有对象,若对象比较复杂,则效率很低。
- 总是需要初始化对象,而不是动态的获得对象运行时状态,不够灵活
Java中Object内是所有类的根类,Object类提供了一个clone()方法,该方法可以将一个Java对象进行克隆,但是实现clone()方法必须实现Cloneable接口,该接口表示该类能够复制且具有复制的能力。这就会用到原型模式。
public class Sheep1 implements Cloneable {
private String name;
private int age;
private String color;
//...构造方法,toString方法,get、set
@Override
protected Object clone() {
Sheep1 sheep = null;
try {
sheep = (Sheep1)super.clone();
} catch (CloneNotSupportedException e) {
System.out.println(e.getMessage());
}
return sheep;
}
}
实现Cloneable方法,并且重写了clone方法。
public class Client1 {
public static void main(String[] args) {
Sheep1 sheep = new Sheep1("肖恩", 12, "红色");
Sheep1 sheep1 = (Sheep1)sheep.clone();
Sheep1 sheep2 = (Sheep1)sheep.clone();
Sheep1 sheep3 = (Sheep1)sheep.clone();
Sheep1 sheep4 = (Sheep1)sheep.clone();
System.out.println(sheep.toString());
System.out.println(sheep1.toString());
System.out.println(sheep2.toString());
System.out.println(sheep3.toString());
System.out.println(sheep4.toString());
System.out.println(sheep1==sheep);//false
}
}
具体的clone方法可以去源代码内去看。原型模式实现克隆羊就完成了,这样我们改初始化属性或者添加新属性后也不用管任何地方,clone()方法都可以。他是创建一个新对象,不是说他还是原对象。
1.3、Spring中原型模式的使用Spring中bean的创建其实就是原型模式的应用。
在bean.xml中创建bean我们可以指定scope为原型模式。
在我们创建bean后,调用applicationContext.getBean()方法时其实就等同于刚才写的clone()方法,都是属于原型模式的应用。
1.4、浅拷贝与深拷贝先看一下,在拷贝过程中,我们拷贝的属性都是常用类型,那如果属性是对象呢?
public class Sheep implements Cloneable {
private String name;
private int age;
private String color;
public Sheep friend;
//...构造方法,toString方法,get、set
@Override
protected Object clone() {
Sheep sheep = null;
try {
sheep = (Sheep)super.clone();
} catch (CloneNotSupportedException e) {
System.out.println(e.getMessage());
}
return sheep;
}
}
对象加了一个属性,friend,然后我们对其进行克隆,看一看他的属性是重新克隆还是只是改了引用。
public class Client {
public static void main(String[] args) {
Sheep sheep = new Sheep("jack", 12, "红色");
sheep.friend = new Sheep("tom",11,"黑色");
Sheep sheep1 = (Sheep)sheep.clone();
Sheep sheep2 = (Sheep)sheep.clone();
Sheep sheep3 = (Sheep)sheep.clone();
Sheep sheep4 = (Sheep)sheep.clone();
System.out.println(sheep.toString());
System.out.println(sheep1.toString());
System.out.println(sheep2.toString());
System.out.println(sheep3.toString());
System.out.println(sheep4.toString());
System.out.println(sheep1.friend==sheep.friend);//true
}
}
可以看出他只是将引用拿过来,并没有对其中的对象进行重新创建。这就是浅拷贝,只是对对象进行一个拷贝,没有对其属性也进行拷贝。
所有引入深拷贝,不仅对对象进行拷贝,并且对对象的所有属性进行克隆拷贝。
实现方式:
-
重写clone()方法
public class Sheep implements Cloneable { private String name; private int age; private String color; public Sheep friend; //...构造方法,toString方法,get、set @Override protected Object clone() throws CloneNotSupportedException{ Object sheep = null; sheep = super.clone(); Sheep sheep1 = (Sheep)sheep; if(friend==null){ return sheep1; } sheep1.friend = (Sheep) friend.clone(); return sheep1; } }Sheep sheep = new Sheep("jack", 12, "红色"); sheep.friend = new Sheep("tom",11,"黑色"); Sheep sheep1 = (Sheep)sheep.clone(); System.out.println(sheep1.friend==sheep.friend);//false -
使用序列化实现
public class Sheep implements Serializable { private String name; private int age; private String color; public Sheep friend; //...构造方法,toString方法,get、set public Object sheepClone(){ 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 sheep = (Sheep) ois.readObject(); return sheep; }catch (Exception e){ e.printStackTrace(); return null; }finally { try{ bos.close(); oos.close(); bis.close(); ois.close(); }catch (Exception e){ System.out.println(e.getMessage()); } } } }Sheep sheep = new Sheep("jack", 12, "红色"); sheep.friend = new Sheep("tom",11,"黑色"); Sheep sheep1 = (Sheep) sheep.sheepClone(); System.out.println(sheep1==sheep);//false System.out.println(sheep1.friend==sheep.friend);//false这样通过序列化反序列化进行了克隆,推荐使用这种方法。
原型模式最主要就是对对象的拷贝,拷贝的对象与原对象不同,是一个新对象。
1.5、总结优点:
- 可以利用原型模式简化对象的创建过程,尤其是对一些创建过程繁琐,包含对象层级比较多的对象来说,使用原型模式可以节约系统资源,提高对象生成的效率。
- 可以很方便得通过改变值来生成新的对象:有些对象之间的差别可能只在于某些值的不同;用原型模式可以快速复制出新的对象并手动修改值即可。
缺点:
- 对象包含的所有对象都需要配备一个克隆的方法,这就使得在对象层级比较多的情况下,代码量会很大,也更加复杂。



