设计模式之原型模式(Prototype Design Pattern)

原型模式,可以理解为克隆模式,就是对一个已创建的对象(原型)进行克隆。原型对象必须提供克隆的方法。

我们先看一个简单的例子:

//实现Cloneable ,重写clone方法,使用对象提供克隆的能力
public class Article implements Cloneable {

    public Article(){
        System.out.println("初始化");
    }

    public Article clone() {
        System.out.println("clone ...");
        Article clone = null;
        try {
            clone = (Article)super.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return clone;
    }
}

//使用
Article article = new Article();
article.clone();


//打印结果
初始化
clone ...

上面例子可以知道,克隆并不会调用构造函数。实际上这是克隆与new不同的地方,因此当初始化很耗时的时候或要占用过多资源的时候,可以在已有对象上使用克隆。

那除了初始化的原因,我们知道很多对象在new之前需要做很多准备工作,比如需要读取配置文件、查询数据库、访问redis、授权才可以使用等,这些工作重复且耗时,因此这时用克隆更方便且快速。

什么时候使用克隆,总结起来就是两点:

  • new初始化很耗时的时候或要占用过多资源
  • new之前需要做很多准备工作,比如需要读取配置文件、查询数据库、访问redis、授权才可以使用等

知道何时使用,再来看克隆两个很重要的方式:浅拷贝和深拷贝。

先看浅拷贝例子:

//实现Cloneable,调用Object的clone方法实现浅拷贝
public class Article implements Cloneable {

    private String title;

    private String content;

    //引用其他文章
    private Article quotedArticle;

    public Article(String title,String content,Article quotedArticle){
        this(title,content);
        this.quotedArticle = quotedArticle;
    }
    public Article(String title,String content){
        this.title = title;
        this.content = content;
    }

    public Article clone() {
        System.out.println("clone ...");
        Article clone = null;
        try {
            clone = (Article)super.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return clone;
    }
    public void print(){
        System.out.println(title + ":" + content);
    }

    public Article getQuotedArticle() {
        return quotedArticle;
    }

    public void setContent(String content) {
        this.content = content;
    }
}


public class Demo {
    public static void main(String[] args) {
        Article article = new Article("关于原型模式例子","关于原型模式的内容", new Article("rel","被引用文章"));
        article.print();
        article.getQuotedArticle().print();

        Article clone = article.clone();//克隆

        System.out.println("----------克隆结果与原型一样----------");
        clone.print();//结果与原型一样
        clone.getQuotedArticle().print();//结果与原型一样

        System.out.println("----------修改克隆----------");
        clone.setContent("修改内容");//修改克隆的内容
        clone.getQuotedArticle().setContent("修改引用文章");//修改克隆引用文章的内容
        article.print(); //修改克隆的内容,原型的内容没有变化
        article.getQuotedArticle().print(); //注意:修改克隆引用文章的内容,原型引用文章的内容也跟着变化
    }
}

//运行结果
关于原型模式例子:关于原型模式的内容
rel:被引用文章
clone ...
----------克隆结果与原型一样----------
关于原型模式例子:关于原型模式的内容
rel:被引用文章
----------修改克隆----------
关于原型模式例子:关于原型模式的内容
rel:修改引用文章

上面例子可以看出,克隆的对象并没有克隆引用的文章对象,只是克隆引用的文章对象的引用。这就是所谓的浅拷贝,只会拷贝String型、基本数据类型及引用对象引用,并不会拷贝引用对象。

如果要进行深拷贝,直接Object的clone方法实现,可以重写clone方法用对象的序列化和反序列化的方法实现深拷贝。

//实现Serializable 接口,对象才可以被序列化
public class Article implements Serializable {

    private String title;

    private String content;

    //引用其他文章
    private Article quotedArticle;

    public Article(String title,String content,Article quotedArticle){
        this(title,content);
        this.quotedArticle = quotedArticle;
    }
    public Article(String title,String content){
        this.title = title;
        this.content = content;
    }

    public Article clone() {
        Article clone = null;
        ByteArrayOutputStream bo = null;
        ObjectOutputStream oo = null;
        ByteArrayInputStream bi = null;
        ObjectInputStream oi = null;
        try {
            //先序列化
            bo = new ByteArrayOutputStream();
            oo = new ObjectOutputStream(bo);
            oo.writeObject(this);
            //再反序列化
            bi = new ByteArrayInputStream(bo.toByteArray());
            oi = new ObjectInputStream(bi);
            clone = (Article)oi.readObject();
        } catch (IOException | ClassNotFoundException e) {
            e.printStackTrace();
        } finally {
            closeStream(bo);
            closeStream(oo);
            closeStream(bi);
            closeStream(oi);
        }
        return clone;
    }

    private void closeStream(Closeable stream){
        if (stream != null) {
            try {
                stream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    public void print(){
        System.out.println(title + ":" + content);
    }

    public Article getQuotedArticle() {
        return quotedArticle;
    }

    public void setContent(String content) {
        this.content = content;
    }
}


public class Demo {
    public static void main(String[] args) {
        Article article = new Article("关于原型模式例子","关于原型模式的内容", new Article("rel","被引用文章"));
        article.print();
        article.getQuotedArticle().print();

        Article clone = article.clone();

        System.out.println("----------克隆结果与原型一样----------");
        clone.print();//结果与原型一样
        clone.getQuotedArticle().print();//结果与原型一样

        System.out.println("----------修改克隆----------");
        clone.setContent("修改内容");//修改克隆的内容
        clone.getQuotedArticle().setContent("修改引用文章");//修改克隆引用文章的内容
        article.print(); //修改克隆的内容,原型的内容没有变化
        article.getQuotedArticle().print(); //注意:修改克隆引用文章的内容,原型引用文章的内容不跟着变化,引用的文章也被克隆了
    }

}

//运行结果
关于原型模式例子:关于原型模式的内容
rel:被引用文章
----------克隆结果与原型一样----------
关于原型模式例子:关于原型模式的内容
rel:被引用文章
----------修改克隆----------
关于原型模式例子:关于原型模式的内容
rel:被引用文章

原型模式的目的,除了创建对像的方便,最重要的是提升创建对象性能。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值