【情景展示】
某大學計算機畢業生小李,帶着滿腔熱血和激情走進社會這個人生課堂。租好了房子,小李就準備上班了。早在大三的時候,學校就已經沒有課程了,那時的小李就已經開始找工作。爲了找到一個合適、專業對口的工作,小李下了很大的功夫重新惡補之前學過的計算機專業知識,如數據結構、計算機網絡、軟件工程、軟件設計模式等等。功夫不負有心人,終於小李在X城市找到了一份軟件開發的工作,在XX軟件股份有限公司任職,待遇在同行業來說還是比較好的(看來,臨時抱佛腳還是有點效果的),就是離小李租住的地方有點遠,不過幸好有公交車直達公司。
對於剛畢業的大學生來說,第一份工作都是比較重要的,因爲第一份工作是你踏進社會的一個橋樑,你可以通過它來慢慢步入社會,而不至於迷茫得不知所措,因爲,你還有足夠的時間思考下一步該怎麼走。小李很珍惜這份工作,工作很勤奮,認真,也充滿了工作的熱情。小李每天生活得很有規律:早上7:00起牀(當然,年輕人總是愛個睡懶覺,早上總是賴牀,有時也會拖到7:15起牀),7:30準時離開家去坐公交車,8:30到公司附近的公交站下車,經過路旁的早餐車會順便買好早餐一起帶到公司,中午飯在公司附近的小餐館解決,然後再辦公室的座椅上小憩一會兒,13:30又開始了下午的工作。
下午17:30準時下班。下班回家之後,小李隨便在哪裏解決一下晚飯(反正是一人吃飽,全家不餓,很省心啊),然後就是晚上的娛樂時間了,上上網,看看電影,有時也學習學習。
時間如白駒過隙,小李就這樣日復一日地在公司待了一年。面對整日重複同樣的工作、生活,小李感覺就像每天都在循環中度過,而且這個循環不知道什麼時候爲止。哎,實在是讓人有點麻木,才工作一年的小李就已經生出厭煩的心態了。對於心高氣傲的年輕人來說,最怕的就是這種心態,一定要學會淡定,從容地對待生活和工作,要保持平和的心態,靜下心來仔細地想一想,自己工作中的得與失,學會讓自己思考問題,學會去面對,讓自己變得成熟起來。理想和現實總是存在着一定的距離,我們要努力奮鬥逐漸縮短理想和現實之間的差距,生活就會越來越美好。小李是一個聰明的小夥子,他想明白這一點。於是,他開始學習新的知識,擴大自身的專業素養和工作能力,不再像之前那樣沒有目標地向前走了,小李的生活也越發變得充實、豐富多彩起來,不再覺得那麼無聊了。
“溫故而知新”,小李先開始對之前的專業知識進行鞏固學習,這次不再像找工作時的臨時突擊式的學習了,而是系統地學習,增強自身的專業知識。設計模式是小李最琢磨不透的一門計算機知識,他感覺設計模式很抽象,很難懂。但是,小李還是堅持學習了一些設計模式方面的知識,所謂熟能生巧,看的多了自然就領悟的多了,也就會有一些心得。小李開始對設計模式感興趣起來,當他看到關於原型設計模式的介紹的時候,想想自己每天的經歷,不由得哈哈大笑:“生活——學習……原來最好的學習課本就隱藏在我們的日常生活中……”
【模式定義】
原型模式(Prototype Pattern),用原型實例指定創建對象的種類,並且通過複製這些原型創建新的對象。
這個模式有個最大的特點就是克隆一個現有的對象,這個克隆的結果有兩種,一種是淺複製,一種是深複製
通過原型模式可以快速地創建一個對象而不需要提供專門的new()操作。
原型模式的核心是一個clone方法。
【靜態建模】
原型模式結構圖:
小李生活結構圖:
DayLife —— 原型類
ILifeFactory —— 生成原型的工廠
LifeFactoryImpl —— 原型工廠實現類
Client —— 客戶端應用程序
【模式實現】
工程結構圖:
1、原型的建立——DayLife
package com.prototype.pojo;
public class DayLife implements Cloneable{
//構造方法
public DayLife(){
System.out.println("-----執行構造方法了-------");
}
//起牀
private String getUp;
//坐公交
private String byBus;
//下車,買早點
private String getFood;
//中午小憩
private String noon;
//下午開始工作
private String afternoonWork;
//下班回家
private String goHome;
//晚上休閒
private String night;
public String getGetUp() {
return getUp;
}
public void setGetUp(String getUp) {
this.getUp = getUp;
}
public String getByBus() {
return byBus;
}
public void setByBus(String byBus) {
this.byBus = byBus;
}
public String getGetFood() {
return getFood;
}
public void setGetFood(String getFood) {
this.getFood = getFood;
}
public String getNoon() {
return noon;
}
public void setNoon(String noon) {
this.noon = noon;
}
public String getAfternoonWork() {
return afternoonWork;
}
public void setAfternoonWork(String afternoonWork) {
this.afternoonWork = afternoonWork;
}
public String getGoHome() {
return goHome;
}
public void setGoHome(String goHome) {
this.goHome = goHome;
}
public String getNight() {
return night;
}
public void setNight(String night) {
this.night = night;
}
/**
* 打印輸出日常生活信息
*/
public void print(){
System.out.println(this.getUp);
System.out.println(this.getByBus());
System.out.println(this.getGetFood());
System.out.println(this.getNoon());
System.out.println(this.getAfternoonWork());
System.out.println(this.getGoHome());
System.out.println(this.getNight());
}
/**
* clone方法
*/
@Override
public DayLife clone(){
try {
//調用超類的clone方法
return (DayLife) super.clone();
}catch (Exception e){
}
return null;
}
}
2、創建生成原型對象的工廠
2.1 抽象工廠——ILifeFactory工廠類
package com.prototype.factory;
import com.prototype.pojo.DayLife;
/**
* 工廠類
*/
public interface ILifefactory {
/**
* 生產DayLife對象
*/
public DayLife getNewInstance();
}
2.2 具體工廠——LifeFactoryImpl工廠實現類
package com.prototype.factory.impl;
import com.prototype.factory.ILifefactory;
import com.prototype.pojo.DayLife;
/**
* 工廠實現類
*/
public class LifeFactoryImpl implements ILifefactory{
//DayLife對象實例用於初始化
private static DayLife dayLife = null;
/**
* getNewInstance方法實現:
* 首先判斷dayLife是否爲null
* 如果是null,則使用new創建一個DayLife對象,同時設置初始內容,並
* 賦值給dayLife對象實例,然後返回;
* 如果不是null,則使用dayLife的clone方法產生一個新對象並複製給
* dayLife對象,然後返回
*/
@Override
public DayLife getNewInstance() {
//判斷dayLife是否爲null
if (dayLife == null){
//如果爲null
//輸出是使用new產生的對象。注意:new這個只使用一次!
System.out.println("new DayLife !");
//設置dayLife內容
dayLife = new DayLife();
dayLife.setGetUp("7:00 起牀");
dayLife.setByBus("7:30 坐公交車");
dayLife.setGetFood("8:30 到公司附近的公交站下車,經過路旁的" +
"早餐車時買好早點一起帶到公司");
dayLife.setNoon("午餐在公司附近的小餐館解決,然後在辦公室的" +
"座椅上小憩一會兒");
dayLife.setAfternoonWork("13:30 開始了下午的工作");
dayLife.setGoHome("17:30 準時下班");
dayLife.setNight("晚上休閒娛樂");
}else{
//如果不爲null
//輸出是使用clone方法產生的對象
System.out.println("clone DayLife !");
//將clone對象賦值給dayLife,返回
dayLife = dayLife.clone();
}
return dayLife;
}
}
3、大學生初入社會的生活展現——Client
package com;
import com.prototype.factory.ILifefactory;
import com.prototype.factory.impl.LifeFactoryImpl;
import com.prototype.pojo.DayLife;
/**
* 主應用程序
*/
public class Client {
public static void main(String[] args){
//創建工廠
ILifefactory lifefactory = new LifeFactoryImpl();
//打印輸出DayLife默認內容
lifefactory.getNewInstance().print();
//再次獲得DayLife,修改GetUp內容後輸出內容
System.out.println("------------------------");
DayLife dayLife = lifefactory.getNewInstance();
dayLife.setGetUp("早上賴牀了!7:15才起牀!");
dayLife.print();
//再次獲得DayLife,修改GetUp內容後輸出內容
System.out.println("------------------------");
DayLife dayLife2 = lifefactory.getNewInstance();
dayLife2.setGetUp("早上賴牀了!7:30才起牀!");
dayLife2.print();
}
}
4、運行效果
【深複製&淺複製】
package com;
import java.util.ArrayList;
public class Test implements Cloneable{
//私有屬性
private ArrayList<String> nameList = new ArrayList<String >();
//添加內容
public void add(String s){
this.nameList.add(s);
}
//獲得ArrayList對象
public ArrayList<String> get() {
return this.nameList;
}
//clone方法
@Override
public Test clone(){
try{
//---------淺複製-------------
// return (Test) super.clone();
//---------淺複製-------------
//---------深複製-------------
Test test = (Test) super.clone();
test.nameList = (ArrayList<String>) this.nameList.clone();
return test;
//---------深複製-------------
}catch (CloneNotSupportedException e){
e.printStackTrace();
}
return null;
}
/**
* @param args
*/
public static void main(String[] args){
//創建test對象
Test test = new Test();
//設置test對象內容
test.add("aa");
test.add("bb");
//打印顯示test中的nameList內容
System.out.println("test:" + test.get());
//克隆test對象生成test2對象
Test test2 = test.clone();
//添加“cc”內容到test2對象中
test2.add("cc");
//打印顯示test2中的nameList內容
System.out.println("test2:" + test2.get());
System.out.println("test:" + test.get());
}
}
1、淺複製效果:
Object類的clone方法只是複製本對象的原始數據類型,如int,float,String等,對於數組和對象應用等是不會複製的。因此,淺複製是有風險的。
2、深複製效果:
深複製是指對於對象中的數組和對象引用也做複製的行爲,從而達到將對象完全複製的效果。
【小結】
1、原型模式
用原型實例指定創建對象的種類,並且通過複製這些原型創建新的對象。
2、注意事項
(1)克隆對象時,原始對象的構造方法不被執行。
(2)淺複製:淺複製只是複製本對象的原始數據類型,如int,float,String等,對於數組和對象應用等是不會複製的。因此,淺複製是有風險的。
(3)深複製:不但對原始數據類型做複製,對於對象中的數組和對象引用也做複製的行爲,從而達到將對象完全複製的效果。
3、設計原則
(1)考慮產生對象的複雜度和類複用;
(2)結合系統結構考慮使用淺複製還是深複製。
4、使用場合
(1)產生對象過程比較複雜,初始化需要許多資源時;
(2)希望框架原型和產生對象分開時;
(3)同一個對象可能會供其他調用者同時調用訪問時。