【设计模式】——原型模式

【情景展示】

    某大学计算机毕业生小李,带着满腔热血和激情走进社会这个人生课堂。租好了房子,小李就准备上班了。早在大三的时候,学校就已经没有课程了,那时的小李就已经开始找工作。为了找到一个合适、专业对口的工作,小李下了很大的功夫重新恶补之前学过的计算机专业知识,如数据结构、计算机网络、软件工程、软件设计模式等等。功夫不负有心人,终于小李在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)同一个对象可能会供其他调用者同时调用访问时




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