一文帶你了解Java設(shè)計(jì)模式之原型模式
定義
用原型實(shí)例指定創(chuàng)建對象的種類,并且通過拷貝這些原型創(chuàng)建新的對象。
原型模式其實(shí)就是從一個對象在創(chuàng)建另外一個可定制的對象,不需要知道任何創(chuàng)建的細(xì)節(jié)

解決的問題
在運(yùn)行期建立和刪除原型。
經(jīng)常用于:
類初始化消耗資源較多
構(gòu)造函數(shù)比較復(fù)雜
核心要點(diǎn)
1.實(shí)現(xiàn)cloneable 接口,重寫Object的clone方法
2.利用已有的一個原型對象,快速地生成和原型對象一樣的實(shí)例。
類圖

淺復(fù)制與深復(fù)制的區(qū)別
淺復(fù)制:基本數(shù)據(jù)類型進(jìn)行值傳遞、引用數(shù)據(jù)類型的指針仍是指向原來的對象(成員變量)。
深復(fù)制:基本數(shù)據(jù)類型進(jìn)行值傳遞、引用數(shù)據(jù)類型開辟新的內(nèi)存空間。
代碼實(shí)現(xiàn)
需求:實(shí)現(xiàn)克隆羊
有一頭羊,需要經(jīng)過賦值再克隆出兩頭。
未使用設(shè)計(jì)模式
/**
* 克隆羊類
*
* @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方法
/**
*
* 傳統(tǒng)模式
* @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
實(shí)現(xiàn)Cloneable接口
Cloneable是標(biāo)記型的接口,它們內(nèi)部都沒有方法和屬性,實(shí)現(xiàn) Cloneable來表示該對象能被克隆,能使用Object.clone()方法。
如果沒有實(shí)現(xiàn) Cloneable的類對象調(diào)用clone()就會拋出CloneNotSupportedException。
實(shí)現(xiàn)Cloneable默認(rèn)是淺復(fù)制
/**
* 克隆羊
*
* @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;
}
/**
* 克隆該實(shí)例,調(diào)用object.clone的方法
* @return
*/
@Override
protected Sheep clone() {
Sheep sheep = null;
try {
sheep = (Sheep) super.clone();
} catch (CloneNotSupportedException e) {
System.out.println(e.getMessage());
e.printStackTrace();
}
return sheep;
}
}
Main方法
/**
* 淺復(fù)制:淺復(fù)制:基本數(shù)據(jù)類型進(jìn)行值傳遞、引用數(shù)據(jù)類型的指針仍是指向原來的對象(成員變量)。
*/
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();
//淺復(fù)制
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
}
}
一定要實(shí)現(xiàn)接口cloneable 否則報(bào)錯:
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)
深復(fù)制-重寫clone
羊類、房子類都需要實(shí)現(xiàn)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
*/
@Override
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;
}
/**
* 克隆該實(shí)例,調(diào)用object,clone的方法
*
* @return
* @throws CloneNotSupportedException
*/
@Override
protected Object clone() throws CloneNotSupportedException {
//對基本數(shù)據(jù)類型進(jìn)行處理
Sheep deep = null;
deep = (Sheep) super.clone();
//對引用類型進(jìn)行處理
//進(jìn)行再次克隆
House clone = (House) deep.getHouse().clone();
deep.setHouse(clone);
return deep;
}
}Main
/**
* 深復(fù)制:羊類、房子類都需要重寫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());
//開辟了新的內(nèi)存空間
//原本的對象
//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
}
}
深復(fù)制-通過對象序列化實(shí)現(xiàn)(推薦)
羊類、房子類都需要實(shí)現(xiàn)Serializable接口。注意這里可以不實(shí)現(xiàn)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;
}
/**
* 序列化的方式:進(jìn)行深復(fù)制
* 寫著麻煩:用著簡單。支持開閉原則
* @return
*/
public Object deepClone() {
//創(chuàng)建流對象
ByteArrayOutputStream bos = null;
ObjectOutputStream oos = null;
ByteArrayInputStream bis = null;
ObjectInputStream ois = null;
try {
//序列化
bos = new ByteArrayOutputStream();
oos = new ObjectOutputStream(bos);
oos.writeObject(this); //當(dāng)前這個對象以對象流的方式輸出
//反序列化
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 {
//關(guān)閉流
try {
bos.close();
oos.close();
bis.close();
ois.close();
} catch (Exception e2) {
// TODO: handle exception
System.out.println(e2.getMessage());
}
}
}
}
Main
/**
* 深復(fù)制
*
* @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);
}
//根據(jù)getBean點(diǎn)進(jìn)去
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);
}
后續(xù)走到了。AbstractBeanFactory類中的doGetBean方法中里邊代碼做判斷mbd.isPrototype()
protected <T> T doGetBean(
String name, @Nullable Class<T> requiredType, @Nullable 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);
}
//判斷是否是多例(原型)
//這里會創(chuàng)建一個新的對象
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實(shí)現(xiàn)了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);
}
}到此這篇關(guān)于一文帶你了解Java設(shè)計(jì)模式之原型模式的文章就介紹到這了,更多相關(guān)Java原型模式內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
詳解SpringBoot中5種類型參數(shù)傳遞和json數(shù)據(jù)傳參的操作
當(dāng)涉及到參數(shù)傳遞時,Spring?Boot遵循HTTP協(xié)議,并支持多種參數(shù)傳遞方式,這些參數(shù)傳遞方式可以根據(jù)請求的不同部分進(jìn)行分類,2023-12-12
Spring中bean的初始化和銷毀幾種實(shí)現(xiàn)方式詳解
這篇文章主要介紹了Spring中bean的初始化和銷毀幾種實(shí)現(xiàn)方式詳解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-11-11
java設(shè)置session過期時間的實(shí)現(xiàn)方法
這篇文章主要介紹了java設(shè)置session過期時間的實(shí)現(xiàn)方法,以實(shí)例形式詳細(xì)講述了具體實(shí)現(xiàn)過程,非常具有參考借鑒價值,需要的朋友可以參考下2014-10-10

