原型模式
原型模式的注意事項(xiàng)和細(xì)節(jié)
- 創(chuàng)建新的對(duì)象比較復(fù)雜時(shí)院喜,可以利用原型模式簡(jiǎn)化對(duì)象的創(chuàng)建過(guò)程烟央,同時(shí)也能提高效率
- 不用重新初始化對(duì)象岩臣,而是動(dòng)態(tài)的獲得對(duì)象運(yùn)行時(shí)的狀態(tài)
- 如果原始對(duì)象發(fā)生變化(增加俯萎、減少屬性)设易,其他克隆對(duì)象也會(huì)響應(yīng)的變化闷板,無(wú)需修改代碼
缺點(diǎn):需要為每個(gè)類配備一個(gè)克隆方法澎灸,對(duì)全新類來(lái)說(shuō)不難,但是對(duì)已有的類進(jìn)行改造時(shí)遮晚,需要修改源代碼性昭。違背了 OCP(開(kāi)閉原則)
一、不使用原型模式
在不使用原型模式時(shí)县遣,我們要實(shí)例化新的對(duì)象糜颠,需要不停的 new 才能得到新的對(duì)象
下面我們看一個(gè)案例
public class Sheep {
private String name;
private int age;
private String color;
private List<String> data;
public Sheep(String name, int age, String color) {
System.out.println("開(kāi)始實(shí)例化小羊....");
long start = System.currentTimeMillis();
this.name = name;
this.age = age;
this.color = color;
System.out.println("獲取小羊的科研數(shù)據(jù)");
this.data = this.request();
System.out.println("小羊的科研數(shù)據(jù)獲取成功");
long end = System.currentTimeMillis();
System.out.println("小羊?qū)嵗晒Α? + "用時(shí): " + ((end - start) / 1000) + "秒");
}
private long random(int max, int min) {
return (long) (Math.random() * (max - min) + min);
}
/**
* 獲取克隆小羊基本數(shù)據(jù)
*/
private List<String> request() {
List<String> data = new ArrayList<>();
data.add("眼睛: 深棕色");
data.add("身高: 166");
data.add("身體健康");
try {
Thread.sleep(random(5000, 1000));
} catch (InterruptedException e) {
e.printStackTrace();
}
return data;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
public List<String> getData() {
return data;
}
public void setData(List<String> data) {
this.data = data;
}
}
public class Main {
public static void main(String[] args) throws CloneNotSupportedException {
long start = System.currentTimeMillis();
int a = 5;
for (int i = 0; i < a; i++) {
Sheep sheep = new Sheep("小羊", 18, "white");
System.out.println(sheep.getName());
System.out.println(sheep.toString());
System.out.println("########################################");
}
long end = System.currentTimeMillis();
System.out.println("本次創(chuàng)建小羊汹族。" + a + "只,用時(shí): " + ((end - start) / 1000) + "秒");
}
}
console
開(kāi)始實(shí)例化小羊....
獲取小羊的科研數(shù)據(jù)
小羊的科研數(shù)據(jù)獲取成功
小羊?qū)嵗晒ζ湫恕S脮r(shí): 2秒
小羊
org.example.prototype.example1.Sheep@4554617c
########################################
開(kāi)始實(shí)例化小羊....
獲取小羊的科研數(shù)據(jù)
小羊的科研數(shù)據(jù)獲取成功
小羊?qū)嵗晒Χヂ鳌S脮r(shí): 4秒
小羊
org.example.prototype.example1.Sheep@74a14482
########################################
開(kāi)始實(shí)例化小羊....
獲取小羊的科研數(shù)據(jù)
小羊的科研數(shù)據(jù)獲取成功
小羊?qū)嵗晒ΑS脮r(shí): 4秒
小羊
org.example.prototype.example1.Sheep@1540e19d
########################################
開(kāi)始實(shí)例化小羊....
獲取小羊的科研數(shù)據(jù)
小羊的科研數(shù)據(jù)獲取成功
小羊?qū)嵗晒υS脮r(shí): 1秒
小羊
org.example.prototype.example1.Sheep@677327b6
########################################
開(kāi)始實(shí)例化小羊....
獲取小羊的科研數(shù)據(jù)
小羊的科研數(shù)據(jù)獲取成功
小羊?qū)嵗晒α裥臁S脮r(shí): 3秒
小羊
org.example.prototype.example1.Sheep@14ae5a5
########################################
本次創(chuàng)建小羊。5只匀归,用時(shí): 16秒Process finished with exit code 0
二坑资、使用原型模式 (淺拷貝)
實(shí)現(xiàn)
Cloneable
接口-
提供一個(gè) clone 方法
@Override protected Object clone() throws CloneNotSupportedException { return super.clone(); }
當(dāng)我們每次創(chuàng)建小羊都要去獲取小羊時(shí),我們每次都需要去獲取小羊的基本信息穆端。這將會(huì)非常的耗時(shí)袱贮。我們一共創(chuàng)建了 5 只羊,耗時(shí)了16秒徙赢。下面我們使用克隆的方式來(lái)直接克隆小羊
/**
* 小羊需要實(shí)現(xiàn) Cloneable 接口
* Cloneable 接口并沒(méi)有任何的方法
* <p> public interface Cloneable {} </p>
* 實(shí)現(xiàn)的目的僅僅是標(biāo)注 Sheep 類可以通過(guò) clone 來(lái)獲得新的小羊
*/
public class Sheep implements Cloneable{
private String name;
private int age;
private String color;
private List<String> data;
public Sheep(String name, int age, String color) {
System.out.println("開(kāi)始實(shí)例化小羊....");
long start = System.currentTimeMillis();
this.name = name;
this.age = age;
this.color = color;
System.out.println("獲取小羊的科研數(shù)據(jù)");
this.data = this.request();
System.out.println("小羊的科研數(shù)據(jù)獲取成功");
long end = System.currentTimeMillis();
System.out.println("小羊?qū)嵗晒Α? + "用時(shí): " + ((end - start) / 1000) + "秒");
}
private long random(int max, int min) {
return (long) (Math.random() * (max - min) + min);
}
/**
* 獲取克隆小羊基本數(shù)據(jù)
*/
private List<String> request() {
List<String> data = new ArrayList<>();
data.add("眼睛: 深棕色");
data.add("身高: 166");
data.add("身體健康");
try {
Thread.sleep(random(5000, 1000));
} catch (InterruptedException e) {
e.printStackTrace();
}
return data;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
public List<String> getData() {
return data;
}
public void setData(List<String> data) {
this.data = data;
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
public class Main {
public static void main(String[] args) throws CloneNotSupportedException {
long start = System.currentTimeMillis();
int a = 5;
Sheep sheep = new Sheep("小羊", 18, "white");
for (int i = 0; i < a; i++) {
Sheep clone = (Sheep) sheep.clone();
System.out.println(clone.getName());
System.out.println(clone.toString());
System.out.println("########################################");
}
long end = System.currentTimeMillis();
System.out.println("本次克隆小羊字柠。" + a + "只,用時(shí): " + ((end - start) / 1000) + "秒");
}
}
console
開(kāi)始實(shí)例化小羊....
獲取小羊的科研數(shù)據(jù)
小羊的科研數(shù)據(jù)獲取成功
小羊?qū)嵗晒拼汀S脮r(shí): 1秒
小羊
org.example.prototype.example1.Sheep@4554617c
########################################
小羊
org.example.prototype.example1.Sheep@74a14482
########################################
小羊
org.example.prototype.example1.Sheep@1540e19d
########################################
小羊
org.example.prototype.example1.Sheep@677327b6
########################################
小羊
org.example.prototype.example1.Sheep@14ae5a5
########################################
本次創(chuàng)建小羊窑业。5只,用時(shí): 1秒Process finished with exit code 0
通過(guò) console 可以觀察到枕屉,我們通過(guò) clone 出的羊都是不同的羊常柄。他們都不需要重新去走構(gòu)造方法,他們也都有名字搀擂。
不過(guò)隨后我們會(huì)發(fā)現(xiàn)西潘,我們的 clone 方法只能 clone 最基本的屬性,如果屬性變成了一個(gè)引用類型哨颂。那這個(gè)引用類型被修改的時(shí)候?qū)?huì)影響到其他的小羊喷市,這不是我們想要的
public class Main {
public static void main(String[] args) throws CloneNotSupportedException {
long start = System.currentTimeMillis();
int a = 5;
Sheep sheep = new Sheep("小羊", 18, "white");
Sheep clone = (Sheep) sheep.clone();
clone.setName("小羊羊");
List<String> data = clone.getData();
data.add("小羊羊擬人形態(tài)");
data.add("膚白貌美大長(zhǎng)腿");
System.out.println(clone.getName());
System.out.println(String.join(",", clone.getData()));
System.out.println("########################################");
Sheep clone2 = (Sheep) sheep.clone();
System.out.println(clone2.getName());
System.out.println(String.join("威恼,", clone2.getData()));
System.out.println("########################################");
long end = System.currentTimeMillis();
System.out.println("本次創(chuàng)建小羊品姓。" + a + "只,用時(shí): " + ((end - start) / 1000) + "秒");
}
}
console
開(kāi)始實(shí)例化小羊....
獲取小羊的科研數(shù)據(jù)
小羊的科研數(shù)據(jù)獲取成功
小羊?qū)嵗晒锎搿S脮r(shí): 2秒
小羊羊
眼睛: 深棕色腹备,身高: 166,身體健康斤蔓,小羊羊擬人形態(tài)植酥,膚白貌美大長(zhǎng)腿
########################################
小羊
眼睛: 深棕色,身高: 166,身體健康友驮,小羊羊擬人形態(tài)漂羊,膚白貌美大長(zhǎng)腿
########################################
本次創(chuàng)建小羊。5只喊儡,用時(shí): 2秒Process finished with exit code 0
我們更改了第一只小羊的名字拨与,它沒(méi)有影響到第二只小羊。但是我們更改它的引用對(duì)象數(shù)據(jù)的時(shí)艾猜。第二只小羊也被更改了买喧,這不是我們想要的
三、使用原型模式(深拷貝)
在這里匆赃,我們將要解決小羊的數(shù)據(jù)修改會(huì)影響其他小羊的問(wèn)題
/**
* 通過(guò)序列化實(shí)現(xiàn)深度克隆小羊淤毛。深度克隆方法不止一種,但是我只用了這一種簡(jiǎn)潔的方式實(shí)現(xiàn)
* 小羊需要實(shí)現(xiàn) Serializable, Cloneable 接口
* Serializable, Cloneable 接口并沒(méi)有任何的方法
* <p> public interface Serializable {} </p>
* <p> public interface Cloneable {} </p>
* 實(shí)現(xiàn)的目的僅僅是標(biāo)注 Sheep 類可以通過(guò) clone 來(lái)獲得新的小羊
*/
public class Sheep implements Serializable, Cloneable{
private static final long serialVersionUID = 1L;
private String name;
private int age;
private String color;
private List<String> data;
public Sheep(String name, int age, String color) {
System.out.println("開(kāi)始實(shí)例化小羊....");
long start = System.currentTimeMillis();
this.name = name;
this.age = age;
this.color = color;
System.out.println("獲取小羊的科研數(shù)據(jù)");
this.data = this.request();
System.out.println("小羊的科研數(shù)據(jù)獲取成功");
long end = System.currentTimeMillis();
System.out.println("小羊?qū)嵗晒Α? + "用時(shí): " + ((end - start) / 1000) + "秒");
}
private long random(int max, int min) {
return (long) (Math.random() * (max - min) + min);
}
/**
* 獲取克隆小羊基本數(shù)據(jù)
*/
private List<String> request() {
List<String> data = new ArrayList<>();
data.add("眼睛: 深棕色");
data.add("身高: 166");
data.add("身體健康");
try {
Thread.sleep(random(5000, 1000));
} catch (InterruptedException e) {
e.printStackTrace();
}
return data;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
public List<String> getData() {
return data;
}
public void setData(List<String> data) {
this.data = data;
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
/**
* 通過(guò)對(duì)象序列化實(shí)現(xiàn)深克隆
*/
public Object deepClone() {
/* 創(chuàng)建流對(duì)象*/
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)前對(duì)象一對(duì)象流的方式進(jìn)行輸出
// 反序列化
bis = new ByteArrayInputStream(bos.toByteArray());
ois = new ObjectInputStream(bis);
return ois.readObject();
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
} finally {
try {
if (bos != null ) bos.close();
if (oos != null ) oos.close();
if (bis != null ) bis.close();
if (ois != null ) ois.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return null;
}
}
public class Main {
public static void main(String[] args) throws CloneNotSupportedException {
long start = System.currentTimeMillis();
int a = 5;
Sheep sheep = new Sheep("小羊", 18, "white");
Sheep clone = (Sheep) sheep.deepClone();
clone.setName("小羊羊");
List<String> data = clone.getData();
data.add("小羊羊擬人形態(tài)");
data.add("膚白貌美大長(zhǎng)腿");
System.out.println(clone.getName());
System.out.println(String.join("算柳,", clone.getData()));
System.out.println("########################################");
Sheep clone2 = (Sheep) sheep.deepClone();
System.out.println(clone2.getName());
System.out.println(String.join("低淡,", clone2.getData()));
System.out.println("########################################");
long end = System.currentTimeMillis();
System.out.println("本次創(chuàng)建小羊。" + a + "只瞬项,用時(shí): " + ((end - start) / 1000) + "秒");
}
}
console
開(kāi)始實(shí)例化小羊....
獲取小羊的科研數(shù)據(jù)
小羊的科研數(shù)據(jù)獲取成功
小羊?qū)嵗晒φ崽!S脮r(shí): 2秒
小羊羊
眼睛: 深棕色,身高: 166囱淋,身體健康猪杭,小羊羊擬人形態(tài),膚白貌美大長(zhǎng)腿
########################################
小羊
眼睛: 深棕色妥衣,身高: 166皂吮,身體健康
########################################
本次創(chuàng)建小羊。5只税手,用時(shí): 3秒Process finished with exit code 0