目录
- 定义
- 解决的问题
- 核心要点
- 类图
- 浅复制与深复制的区别
- 代码实现
- 未使用设计模式
- 实现Cloneable接口
- 深复制-重写clone
- 深复制-通过对象序列化实现(推荐)
- 拓展
定义
用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。
原型模式其实就是从一个对象在创建另外一个可定制的对象,不需要知道任何创建的细节
解决的问题
在运行期建立和删除原型。
经常用于:
类初始化消耗资源较多
构造函数比较复杂
核心要点
1.实现cloneable 接口,重写Object的clone方法
2.利用已有的一个原型对象,快速地生成和原型对象一样的实例。
类图
浅复制与深复制的区别
浅复制:基本数据类型进行值传递、引用数据类型的指针仍是指向原来的对象(成员变量)。
深复制:基本数据类型进行值传递、引用数据类型开辟新的内存空间。
代码实现
需求:实现克隆羊
有一头羊,需要经过赋值再克隆出两头。
未使用设计模式
/** | |
* 克隆羊类 | |
* | |
* @author Promsing(张有博) | |
* @version 1.0.0 | |
* @since 2022/9/3 - 14:51 | |
*/ | |
public class Sheep { | |
private String name; | |
private Integer age; | |
private String color; | |
public String getName() { | |
return name; | |
} | |
public void setName(String name) { | |
this.name = name; | |
} | |
public Integer getAge() { | |
return age; | |
} | |
public void setAge(Integer age) { | |
this.age = age; | |
} | |
public String getColor() { | |
return color; | |
} | |
public void setColor(String color) { | |
this.color = color; | |
} | |
public Sheep() { | |
} | |
public Sheep(String name, Integer age, String color) { | |
this.name = name; | |
this.age = age; | |
this.color = color; | |
} | |
} |
Main方法
/** | |
* | |
* 传统模式 | |
* @author Promsing(张有博) | |
* @version 1.0.0 | |
* @since 2022/9/3 - 14:47 | |
*/ | |
public class Client { | |
public static void main(String[] args) { | |
//小羊 | |
Sheep sheep=new Sheep("小红",8,"红色"); | |
//克隆羊 | |
Sheep sheep2=sheep; | |
Sheep sheep3=sheep; | |
System.out.println("通过赋值,指针还是指向sheep"); | |
System.out.println(sheep); | |
System.out.println(sheep2); | |
System.out.println(sheep3); | |
} | |
} | |
//通过赋值,指针还是指向sheep | |
//com.promsing.creational.prototype.type1.Sheep@1b6d3586 | |
//com.promsing.creational.prototype.type1.Sheep@1b6d3586 | |
//com.promsing.creational.prototype.type1.Sheep@1b6d3586 |
实现Cloneable接口
Cloneable是标记型的接口,它们内部都没有方法和属性,实现 Cloneable来表示该对象能被克隆,能使用Object.clone()方法。
如果没有实现 Cloneable的类对象调用clone()就会抛出CloneNotSupportedException。
实现Cloneable默认是浅复制
/** | |
* 克隆羊 | |
* | |
* @author Promsing(张有博) | |
* @version 1.0.0 | |
* @since 2022/9/3 - 14:53 | |
*/ | |
public class Sheep implements Cloneable { | |
private String name; | |
private Integer age; | |
private String color; | |
/** | |
* 羊的朋友 | |
*/ | |
private Sheep friend; | |
public String getName() { | |
return name; | |
} | |
public void setName(String name) { | |
this.name = name; | |
} | |
public Integer getAge() { | |
return age; | |
} | |
public void setAge(Integer age) { | |
this.age = age; | |
} | |
public String getColor() { | |
return color; | |
} | |
public void setColor(String color) { | |
this.color = color; | |
} | |
public Sheep() { | |
} | |
public Sheep getFriend() { | |
return friend; | |
} | |
public void setFriend(Sheep friend) { | |
this.friend = friend; | |
} | |
public Sheep(String name, Integer age, String color) { | |
this.name = name; | |
this.age = age; | |
this.color = color; | |
} | |
/** | |
* 克隆该实例,调用object.clone的方法 | |
* @return | |
*/ | |
protected Sheep clone() { | |
Sheep sheep = null; | |
try { | |
sheep = (Sheep) super.clone(); | |
} catch (CloneNotSupportedException e) { | |
System.out.println(e.getMessage()); | |
e.printStackTrace(); | |
} | |
return sheep; | |
} | |
} |
Main方法
/** | |
* 浅复制:浅复制:基本数据类型进行值传递、引用数据类型的指针仍是指向原来的对象(成员变量)。 | |
*/ | |
public class ShallowClient { | |
public static void main(String[] args) { | |
Sheep sheep=new Sheep("小红",9,"红色"); | |
sheep.setFriend(new Sheep("小黑",10,"黑色")); | |
Sheep sheep1 = sheep.clone();//开辟了新的空间 | |
Sheep sheep2 = sheep.clone(); | |
//浅复制 | |
System.out.println("原型羊"+sheep); | |
System.out.println("克隆羊"+sheep1+"-朋友羊-"+sheep1.getFriend()); | |
System.out.println("克隆羊"+sheep2+"-朋友羊-"+sheep2.getFriend()); | |
//原型羊com.promsing.creational.prototype.type3.Sheep@1b6d3586 | |
//克隆羊com.promsing.creational.prototype.type3.Sheep@4554617c-朋友羊-com.promsing.creational.prototype.type3.Sheep@74a14482 | |
//克隆羊com.promsing.creational.prototype.type3.Sheep@1540e19d-朋友羊-com.promsing.creational.prototype.type3.Sheep@74a14482 | |
} | |
} |
一定要实现接口cloneable 否则报错:
Exception in thread "main" java.lang.CloneNotSupportedException: com.promsing.creational.prototype.type4.Sheep
at java.lang.Object.clone(Native Method)
at com.promsing.creational.prototype.type4.Sheep.clone(Sheep.java:76)
at com.promsing.creational.prototype.type4.DeepClient.main(DeepClient.java:14)
深复制-重写clone
羊类、房子类都需要实现Cloneable接口
房子类
/** | |
* 房子类 | |
* | |
* @author Promsing(张有博) | |
* @version 1.0.0 | |
* @since 2022/9/3 - 15:27 | |
*/ | |
public class House implements Cloneable { | |
//地址 | |
private String address; | |
//尺寸 | |
private Integer size; | |
public String getAddress() { | |
return address; | |
} | |
public void setAddress(String address) { | |
this.address = address; | |
} | |
public Integer getSize() { | |
return size; | |
} | |
public void setSize(Integer size) { | |
this.size = size; | |
} | |
/** | |
* 克隆的方法 | |
* @return | |
* @throws CloneNotSupportedException | |
*/ | |
protected Object clone() throws CloneNotSupportedException { | |
return super.clone(); | |
} | |
} |
羊类
/** | |
* 克隆羊-深拷贝 | |
* | |
* @author Promsing(张有博) | |
* @version 1.0.0 | |
* @since 2022/9/3 - 15:26 | |
*/ | |
public class Sheep implements Cloneable { | |
private String name; | |
private Integer age; | |
private String color; | |
/** | |
* 羊的房子:引用类型 | |
*/ | |
private House house; | |
public House getHouse() { | |
return house; | |
} | |
public void setHouse(House house) { | |
this.house = house; | |
} | |
public String getName() { | |
return name; | |
} | |
public void setName(String name) { | |
this.name = name; | |
} | |
public Integer getAge() { | |
return age; | |
} | |
public void setAge(Integer age) { | |
this.age = age; | |
} | |
public String getColor() { | |
return color; | |
} | |
public void setColor(String color) { | |
this.color = color; | |
} | |
public Sheep() { | |
} | |
public Sheep(String name, Integer age, String color) { | |
this.name = name; | |
this.age = age; | |
this.color = color; | |
} | |
/** | |
* 克隆该实例,调用object,clone的方法 | |
* | |
* @return | |
* @throws CloneNotSupportedException | |
*/ | |
protected Object clone() throws CloneNotSupportedException { | |
//对基本数据类型进行处理 | |
Sheep deep = null; | |
deep = (Sheep) super.clone(); | |
//对引用类型进行处理 | |
//进行再次克隆 | |
House clone = (House) deep.getHouse().clone(); | |
deep.setHouse(clone); | |
return deep; | |
} | |
} |
Main
/** | |
* 深复制:羊类、房子类都需要重写clone的接口,比较麻烦。不符合开闭 | |
* | |
* @author Promsing(张有博) | |
* @version 1.0.0 | |
* @since 2022/9/3 - 15:38 | |
*/ | |
public class DeepClient { | |
public static void main(String[] args) throws CloneNotSupportedException { | |
Sheep sheep=new Sheep("黑",90,"heisee"); | |
sheep.setHouse(new House()); | |
Sheep clone = (Sheep)sheep.clone(); | |
System.out.println("原本的对象"); | |
System.out.println(sheep); | |
System.out.println(sheep.getHouse()); | |
System.out.println("克隆的对象"); | |
System.out.println(clone); | |
System.out.println(clone.getHouse()); | |
//开辟了新的内存空间 | |
//原本的对象 | |
//com.promsing.creational.prototype.type4.Sheep@1b6d3586 | |
//com.promsing.creational.prototype.type4.House@4554617c | |
//克隆的对象 | |
//com.promsing.creational.prototype.type4.Sheep@74a14482 | |
//com.promsing.creational.prototype.type4.House@1540e19d | |
} | |
} |
深复制-通过对象序列化实现(推荐)
羊类、房子类都需要实现Serializable接口。注意这里可以不实现Cloneable了。
房子类
/** | |
* 房子类 | |
* | |
* @author Promsing(张有博) | |
* @version 1.0.0 | |
* @since 2022/9/3 - 15:27 | |
*/ | |
public class House implements Serializable{ | |
//地址 | |
private String address; | |
//尺寸 | |
private Integer size; | |
public String getAddress() { | |
return address; | |
} | |
public void setAddress(String address) { | |
this.address = address; | |
} | |
public Integer getSize() { | |
return size; | |
} | |
public void setSize(Integer size) { | |
this.size = size; | |
} | |
} |
羊类
/** | |
* 克隆羊-深拷贝 | |
* | |
* @author Promsing(张有博) | |
* @version 1.0.0 | |
* @since 2022/9/3 - 15:26 | |
*/ | |
public class Sheep implements Serializable { | |
private String name; | |
private Integer age; | |
private String color; | |
/** | |
* 羊的房子:引用类型 | |
*/ | |
private House house; | |
public House getHouse() { | |
return house; | |
} | |
public void setHouse(House house) { | |
this.house = house; | |
} | |
public String getName() { | |
return name; | |
} | |
public void setName(String name) { | |
this.name = name; | |
} | |
public Integer getAge() { | |
return age; | |
} | |
public void setAge(Integer age) { | |
this.age = age; | |
} | |
public String getColor() { | |
return color; | |
} | |
public void setColor(String color) { | |
this.color = color; | |
} | |
public Sheep() { | |
} | |
public Sheep(String name, Integer age, String color) { | |
this.name = name; | |
this.age = age; | |
this.color = color; | |
} | |
/** | |
* 序列化的方式:进行深复制 | |
* 写着麻烦:用着简单。支持开闭原则 | |
* @return | |
*/ | |
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) { | |
// TODO: handle exception | |
e.printStackTrace(); | |
return null; | |
} finally { | |
//关闭流 | |
try { | |
bos.close(); | |
oos.close(); | |
bis.close(); | |
ois.close(); | |
} catch (Exception e2) { | |
// TODO: handle exception | |
System.out.println(e2.getMessage()); | |
} | |
} | |
} | |
} |
Main
/** | |
* 深复制 | |
* | |
* @author Promsing(张有博) | |
* @version 1.0.0 | |
* @since 2022/9/3 - 15:38 | |
*/ | |
public class DeepClient { | |
public static void main(String[] args) throws CloneNotSupportedException { | |
Sheep sheep=new Sheep("黑",90,"heisee"); | |
sheep.setHouse(new House()); | |
Sheep clone = (Sheep)sheep.deepClone(); | |
System.out.println("原本的对象"); | |
System.out.println(sheep); | |
System.out.println(sheep.getHouse()); | |
System.out.println("克隆的对象"); | |
System.out.println(clone); | |
System.out.println(clone.getHouse()); | |
} | |
} |
拓展
Spring使用原型模式:@scope(“prototype”)
public static void main(String[] args) throws IOException { | |
//new一个容器 | |
AnnotationConfigWebApplicationContext context = | |
new AnnotationConfigWebApplicationContext(); | |
System.out.println("run success"); | |
OrderService bean = context.getBean(OrderService.class); | |
} | |
//根据getBean点进去 | |
public <T> T getBean(Class<T> requiredType) throws BeansException { | |
assertBeanFactoryActive(); | |
return getBeanFactory().getBean(requiredType); | |
} | |
public Object getBean(String name) throws BeansException { | |
return doGetBean(name, null, null, false); | |
} |
后续走到了。AbstractBeanFactory类中的doGetBean方法中里边代码做判断mbd.isPrototype()
protected <T> T doGetBean( | |
String name, Class<T> requiredType, Object[] args, boolean typeCheckOnly) | |
throws BeansException { | |
String beanName = transformedBeanName(name); | |
Object bean; | |
// Eagerly check singleton cache for manually registered singletons. | |
Object sharedInstance = getSingleton(beanName); | |
if (sharedInstance != null && args == null) { | |
//代码省略~~~~ | |
} | |
else { | |
//代码省略~~~~ | |
try { | |
//代码省略~~~~ | |
// Create bean instance. | |
//判断是否是单例 | |
if (mbd.isSingleton()) { | |
sharedInstance = getSingleton(beanName, () -> { | |
try { | |
return createBean(beanName, mbd, args); | |
} | |
catch (BeansException ex) { | |
destroySingleton(beanName); | |
throw ex; | |
} | |
}); | |
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd); | |
} | |
//判断是否是多例(原型) | |
//这里会创建一个新的对象 | |
else if (mbd.isPrototype()) { | |
// It's a prototype -> create a new instance. | |
Object prototypeInstance = null; | |
try { | |
beforePrototypeCreation(beanName); | |
prototypeInstance = createBean(beanName, mbd, args); | |
} | |
finally { | |
afterPrototypeCreation(beanName); | |
} | |
bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd); | |
} | |
else { | |
//代码省略~~~~ | |
} | |
} | |
catch (BeansException ex) { | |
cleanupAfterBeanCreationFailure(beanName); | |
throw ex; | |
} | |
} | |
//代码省略~~~~ | |
} | |
return (T) bean; | |
} |
ArrayList实现了Cloneable接口
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); | |
} | |
} |