定义
用原型实例指定创建对象的种类,通过拷贝创建新的对象。
不需要知道创建细节,不调用构造方法。
原型模式的核心是clone()方法。
UML类图
Prototype:原型类,声明一个克隆自己的接口。
ConcretePrototype1、ConcretePrototype2:具体的原型类。
public interface Prototype {
/**
* 克隆自身的方法
* @return
*/
public Prototype clone();
}
class ConcretePrototype1 implements Prototype{
@Override
public Prototype clone() {
Prototype prototype = new ConcretePrototype1();
return prototype;
}
}
class ConcretePrototype2 implements Prototype{
@Override
public Prototype clone() {
Prototype prototype = new ConcretePrototype1();
return prototype;
}
}
@AllArgsConstructor
class Client{
private Prototype prototype;
public void operation(){
Prototype newPrototype = prototype.clone();
}
}
适用场景
类的初始化消耗较多资源。
new一个对象需要非常繁琐的过程(数据准备、访问权限等)
构造函数比较复杂的时候。
特点
原型模式比直接new对象性能高。
当要创建的对象比较复杂的时候,简化了创建对象的过程。
但是必须有clone方法,注意深克隆、浅克隆。实现深克隆的时候可能需要比较复杂的代码。
示例1
public class Mail implements Cloneable{
private String name;
private String emailAddress;
private String content;
public Mail(){
System.out.println("Mail Class Constructor");
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getEmailAddress() {
return emailAddress;
}
public void setEmailAddress(String emailAddress) {
this.emailAddress = emailAddress;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
@Override
public String toString() {
return "Mail{" +
"name='" + name + '\'' +
", emailAddress='" + emailAddress + '\'' +
", content='" + content + '\'' +
'}'+super.toString();
}
@Override
protected Object clone() throws CloneNotSupportedException {
System.out.println("clone mail object");
return super.clone();
}
}
public class MailUtil {
public static void sendMail(Mail mail){
String outputContent = "向{0}同学,邮件地址:{1},邮件内容:{2}发送邮件成功";
System.out.println(MessageFormat.format(outputContent,mail.getName(),mail.getEmailAddress(),mail.getContent()));
}
public static void saveOriginMailRecord(Mail mail){
System.out.println("存储originMail记录,originMail:"+mail.getContent());
}
}
public class Test {
public static void main(String[] args) throws CloneNotSupportedException {
Mail mail = new Mail();
mail.setContent("初始化模板");
System.out.println("初始化mail:"+mail);
for(int i = 0;i < 10;i++){
Mail mailTemp = (Mail) mail.clone();
mailTemp.setName("姓名"+i);
mailTemp.setEmailAddress("姓名");
mailTemp.setContent("恭喜");
MailUtil.sendMail(mailTemp);
System.out.println("克隆的mailTemp:"+mailTemp);
}
MailUtil.saveOriginMailRecord(mail);
}
}
Java里的clone注意
存在浅拷贝和深拷贝。
浅拷贝:对于数据类型是基本类型的成员变量,浅拷贝会值传递给新的对象。
对于数据类型是引用类型的成员变量,浅拷贝会引用传递,clone前后的2个对象的引用类型的成员变量实际上是同一个。
可以通过重写clone方法或者对象序列化的方式实现深拷贝。如下:
public class Pig implements Cloneable,Serializable{
private String name;
private Date birthday;
public Pig(String name, Date birthday) {
this.name = name;
this.birthday = birthday;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
@Override
protected Object clone() throws CloneNotSupportedException {
Pig pig = (Pig)super.clone();
//下面的语句才能深克隆Date属性
pig.birthday = (Date) pig.birthday.clone();
return pig;
}
public Object deepClone() throws IOException, ClassNotFoundException {
/**
* 序列化
*/
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(this);
/**
* 反序列化
*/
ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bis);
Pig pig = (Pig) ois.readObject();
return pig;
}
@Override
public String toString() {
return "Pig{" +
"name='" + name + '\'' +
", birthday=" + birthday +
'}'+super.toString();
}
}
public static void main(String[] args) throws CloneNotSupportedException, NoSuchMethodException, InvocationTargetException, IllegalAccessException, IOException, ClassNotFoundException {
Date birthday = new Date(0L);
System.out.println("如果不修改pig类里的clone方法,pig的birthday是浅克隆,pig1和pig2的birthday一样");
Pig pig1 = new Pig("佩奇",birthday);
Pig pig2 = (Pig) pig1.clone();
System.out.println(pig1 == pig2); //false
System.out.println(pig1.getBirthday() == pig2.getBirthday());//false
Pig pig3 = (Pig) pig1.deepClone();
System.out.println(pig1 == pig3);//false
System.out.println(pig1.getBirthday() == pig3.getBirthday());//false
}
示例2
版本1:
@Data
@AllArgsConstructor
@NoArgsConstructor
class Sheep {
private String name;
private int age;
private String color;
}
/**
* 传统的表示克隆羊群的方法。易理解,号操作。
* 创建新的羊时,要不停的new,获取原始羊的属性,如果创建的对象比较复杂,效率较低
*/
class Test1{
public static void main(String[] args) {
List<Sheep> list = new ArrayList();
Sheep proto = new Sheep("tom", 1, "白色");
for (int i = 0; i < 10; i++) {
list.add(new Sheep(proto.getName(), proto.getAge(),proto.getColor()));
}
}
}
版本2:
@Data
@AllArgsConstructor
@NoArgsConstructor
class Sheep implements Cloneable{
private String name;
private int age;
private String color;
@Override
protected Object clone() {
Sheep sheep = null;
try {
sheep = (Sheep) super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return sheep;
}
}
/**
* Object里提供了clone()方法,可以将对象复制一份
*/
class Test1{
public static void main(String[] args) {
List<Sheep> list = new ArrayList();
Sheep proto = new Sheep("tom", 1, "白色");
for (int i = 0; i < 10; i++) {
list.add((Sheep) proto.clone());
}
}
}
示例3
Spring配置bean以原型模式创建:
<bean id="id01" class="com.Student" scope="prototype">
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Student {
private Integer id;
private String name;
}
public static void main(String[] args) {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");
Object bean = applicationContext.getBean("id01");
Object bean2 = applicationContext.getBean("id01");
System.out.println("bean2" + bean2);
System.out.println(bean == bean2); // false
}
Spring源码里关于原型模式的部分是:
class AbstractBeanFactory{
if(mbd.isSingleton()){
//略
}else if(mbd.isPrototype()){
Object prototypeInstance = null;
//略
prototypeInstance = createBean(beanName,mbd,args);
}
}