【設計模式】——原型模式

【情景展示】

    某大學計算機畢業生小李,帶着滿腔熱血和激情走進社會這個人生課堂。租好了房子,小李就準備上班了。早在大三的時候,學校就已經沒有課程了,那時的小李就已經開始找工作。爲了找到一個合適、專業對口的工作,小李下了很大的功夫重新惡補之前學過的計算機專業知識,如數據結構、計算機網絡、軟件工程、軟件設計模式等等。功夫不負有心人,終於小李在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)同一個對象可能會供其他調用者同時調用訪問時




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章