1、原型模式介紹html
原型模式:原型模式就是從一個對象再建立另一個可定製的對象,並且不須要知道任何建立的細節。java
所謂原型模式,就是java中的克隆技術,以某個對象爲原型。複製出新的對象。顯然新的對象具有原型對象的特色。效率高(避免了從新執行構造過程步驟)設計模式
克隆相似於new,但和new不一樣。new建立新的對象屬性採用的是默認值。克隆出來的對象的屬性值徹底和原型對象相同。而且克隆出的新對象不會影響原型對象,克隆後。還能夠再修改克隆對象的值。數組
要實現原型模式,必須實現Cloneable接口,而這個接口裏面是空的。框架
Cloneable接口是一個空接口,使用Cloneable接口都不用導入包。而clone方法是屬於Object對象的。若是要克隆某個對象的話必須實現Cloneable接口ide
1
2
3
4
5
6
7
|
*
@author
unascribed
*
@see
java.lang.CloneNotSupportedException
*
@see
java.lang.Object#clone()
*
@since
JDK1.
0
*/
public
interface
Cloneable {
}
|
重寫Object對象的clone方法,clone方法爲本地方法。效率比較高學習
1
|
protected
native
Object clone()
throws
CloneNotSupportedException;
|
若是咱們要克隆某個對象有淺克隆和深克隆測試
淺克隆:copy該對象,而後保留該對象原有的引用。也就是說不克隆該對象的屬性。this
深克隆:copy該對象,而且把該對象的全部屬性也克隆出一份新的。
spa
2、代碼實現
一、淺克隆代碼實現:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
|
/**
* 原型模式:淺克隆
* Cloneable是一個空接口(標記接口),是一個規範。可是若是要克隆這個類對象的話必須實現Cloneable接口
*/
public
class
Sheep
implements
Cloneable{
private
String sname;
private
Date birthday;
/**
* 重寫Object對象的clone方法
*/
@Override
protected
Object clone()
throws
CloneNotSupportedException {
//直接調用Object對象的clone方法
Object obj =
super
.clone();
return
obj;
}
//省略get,set方法和構造方法
}
/**
* 測試原型模式(淺克隆)
*/
public
class
Test {
public
static
void
main(String[] args)
throws
Exception {
Date date =
new
Date(1274397294739L);
Sheep s1 =
new
Sheep(
"原型羊"
,date);
Sheep s2 = (Sheep) s1.clone();
//克隆一個羊
System.out.println(s1);
System.out.println(s1.getSname());
System.out.println(
"原日期:"
+s1.getBirthday());
date.setTime(34732834827389L);
//改變原有date的值
System.out.println(
"改變後的日期:"
+date.toString());
//克隆羊的信息
System.out.println(
"---------------------------------"
);
System.out.println(s2);
System.out.println(s2.getSname());
System.out.println(s2.getBirthday());
//此時的birthday日期使用的是改變後的日期對象引用
}
}
|
最後的結果爲:克隆的對象仍然保留了原有對象的引用,值隨着改變而改變
1
2
3
4
5
6
7
8
|
com.fz.prototype.Sheep
@153f67e
原型羊
原日期:Fri May
21
07
:
14
:
54
CST
2010
改變後的日期:Mon Aug
22
17
:
40
:
27
CST
3070
---------------------------------
com.fz.prototype.Sheep
@18f51f
原型羊
Mon Aug
22
17
:
40
:
27
CST
3070
|
二、深克隆代碼實現:克隆對象的同時,把該對象的屬性也連帶着克隆出新的。
深克隆只須要在clone方法中將該對象的屬性也克隆便可
1
2
3
4
5
6
7
8
9
10
11
12
|
/**
* 重寫Object對象的clone方法
*/
@Override
protected
Object clone()
throws
CloneNotSupportedException {
//直接調用Object對象的clone方法
Object obj =
super
.clone();
//深克隆:把對象下的全部屬性也克隆出來
Sheep22 s = (Sheep22) obj;
s.birthday = (Date)
this
.birthday.clone();
return
s;
}
|
測試代碼不變,結果則會變了。克隆了以後把原來的日期改變後,克隆的對象2的屬性則不會被影響。
1
2
3
4
5
6
7
8
|
com.fz.prototype.Sheep2
@15bdc50
原型羊
原日期:Fri May
21
07
:
14
:
54
CST
2010
改變後的日期:Mon Aug
22
17
:
40
:
27
CST
3070
---------------------------------
com.fz.prototype.Sheep2
@18f51f
原型羊
Fri May
21
07
:
14
:
54
CST
2010
|
三、經過序列化和反序列化來實現深克隆對象:序列化須要原型對象實現Serializable接口
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
|
import
java.io.ByteArrayInputStream;
import
java.io.ByteArrayOutputStream;
import
java.io.ObjectInputStream;
import
java.io.ObjectOutputStream;
import
java.util.Date;
/**
* 測試原型模式(利用序列化和反序列化實現深克隆)
*/
public
class
Test3 {
public
static
void
main(String[] args)
throws
Exception {
Date date =
new
Date(1274397294739L);
Sheep s1 =
new
Sheep(
"原型羊"
,date);
// Sheep s2 = (Sheep) s1.clone();//克隆一個羊
//使用序列化和反序列化實現深複製
//一、將s1對象序列化爲一個數組
//經過ObjectOutputStream流將s1對象讀出來給ByteArrayOutputStream流
ByteArrayOutputStream bos =
new
ByteArrayOutputStream();
ObjectOutputStream oos =
new
ObjectOutputStream(bos);
oos.writeObject(s1);
//ByteArrayOutputStream流將對象信息轉成byte數組,這樣byte數組裏就包含了對象的數據
byte
[] bytes = bos.toByteArray();
//二、將字節數組中的內容反序列化爲一個Sheep對象
//經過ByteArrayInputStream流讀入bytes字節數組中數據,而後傳給ObjectInputStream對象輸入流
ByteArrayInputStream bis =
new
ByteArrayInputStream(bytes);
ObjectInputStream ois =
new
ObjectInputStream(bis);
//經過ObjectInputStream返回一個Sheep對象
Sheep s2 = (Sheep) ois.readObject();
//原型羊的信息
System.out.println(s1);
System.out.println(
"原日期:"
+s1.getBirthday());
date.setTime(34732834827389L);
//改變原有date的值
System.out.println(
"改變後的日期:"
+date.toString());
//克隆羊的信息
System.out.println(
"---------------------------------"
);
System.out.println(s2);
System.out.println(s2.getBirthday());
}
}
|
經過序列化和反序列化的結果,最終結果仍是和深克隆同樣。
1
2
3
4
5
6
7
8
9
10
11
|
com.fz.prototype.Sheep
@1a116c9
原日期:Fri May
21
07
:
14
:
54
CST
2010
改變後的日期:Mon Aug
22
17
:
40
:
27
CST
3070
---------------------------------
com.fz.prototype.Sheep
@7eb6e2
Fri May
21
07
:
14
:
54
CST
2010
|
3、測試克隆對象的效率
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
|
package
com.fz.prototype;
/**
* 測試clone對象的效率
*/
public
class
TestClone {
//new 對象
public
static
void
testNew(
int
size){
long
start = System.currentTimeMillis();
for
(
int
i =
0
; i < size; i++) {
Laptop l =
new
Laptop();
}
long
end = System.currentTimeMillis();
System.out.println(
"new 對象耗時:"
+(end-start));
}
//clone 對象
public
static
void
testClone(
int
size){
long
start = System.currentTimeMillis();
Laptop l =
new
Laptop();
for
(
int
i =
0
; i < size; i++) {
try
{
Laptop temp = (Laptop) l.clone();
}
catch
(CloneNotSupportedException e) {
e.printStackTrace();
}
}
long
end = System.currentTimeMillis();
System.out.println(
"clone 對象耗時:"
+(end-start));
}
public
static
void
main(String[] args) {
testNew(
1000
);
testClone(
1000
);
}
}
class
Laptop
implements
Cloneable{
public
Laptop() {
//模擬建立Laptop對象的時候比較耗時
try
{
Thread.sleep(
10
);
}
catch
(InterruptedException e) {
e.printStackTrace();
}
}
@Override
protected
Object clone()
throws
CloneNotSupportedException {
return
super
.clone();
}
}
|
最後結果爲:
new 對象耗時:10063
clone 對象耗時:10
4、使用場景
原型模式適用場景:若是某個對象new的過程當中很耗時,則能夠考慮使用原型模式。
Spring框架中bean對象的建立就兩種模式:單例模式或者原型模式
參考資料:
大話設計模式(帶目錄完整版).pdf
HEAD_FIRST設計模式(中文版).pdf
尚學堂_高淇_java300集最全視頻教程_【GOF23設計模式】