博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
一起了解原型模式
阅读量:6250 次
发布时间:2019-06-22

本文共 2974 字,大约阅读时间需要 9 分钟。

原型模式

原型模式,用起来其实就是做clone操作,clone一个对象,越过构造器,在特定使用场景下增加效率。

UML

使用场景:

  1. 类初始化需要消耗很多资源,比较耗时。
  2. new方式非常繁琐,还涉及到权限之类的。用clone就减少操作。
  3. 一个对象需要提供给其他对象使用,而且各个使用都可能改到值,可以考虑用原型模式,做保护性拷贝。

先说说原型模式主要的浅拷贝和深拷贝:

浅拷贝:

可被clone的对象:

  • 实现 Cloneable接口
  • 重写clone方法
  • 先clone,再给参数赋值
public class Document implements Cloneable {    private String mText;    private ArrayList
list = new ArrayList<>(); public String getmText() { return mText; } public void setmText(String mText) { this.mText = mText; } @Override protected Document clone() throws CloneNotSupportedException { Document document = (Document) super.clone(); document.mText = this.mText; document.list = this.list; return document; }}复制代码

深拷贝:

对于上面ArrayList,它自身实现类cloneable接口的,所以它本身也是可以clone的,对于对象,赋值后,是指向同一个地址的,对于浅拷贝来说,如果改了list对象,那么原有的对象list也会被修改到。所以对于list对象,我们也需要拷贝一下,修改如下。

public class Document implements Cloneable {    private String mText;    private ArrayList
list = new ArrayList<>(); public String getmText() { return mText; } public void setmText(String mText) { this.mText = mText; } @Override protected Document clone() throws CloneNotSupportedException { Document document = (Document) super.clone(); document.mText = this.mText; document.list = (ArrayList
) this.list.clone(); return document; }}复制代码

检验

首先:对于浅拷贝

  • 我们用下面一段代码来做检验:
Document document = new Document();        document.setmText("11111100000");        document.getList().add("00");        System.out.println("内容原始:" + document.toString());        Document document1 = document.clone();        document1.setmText("111111");        document1.getList().add("111");        System.out.println("内容修改:" + document1.toString());        System.out.println("内容原始:" + document.toString());复制代码
  • 输出:
内容原始:Document{mText='11111100000', list=[00]}内容修改:Document{mText='111111', list=[00, 111]}内容原始:Document{mText='11111100000', list=[00, 111]}复制代码

这里很明显的能看到,我们改了String类型,也改了list对象。但是输出后,原始的String类型的text没变,但是list却被改变了。 这是为什么呢?

原因其实是: String类型是不可变类型,所以我们不推荐在for循环中使用+号来拼接一样,因为每+一次就会创建一块内存来装。同理,这里的虽然拷贝了string类型,但是第二个对象修改的时候,string的text是指向了新的地址而不是把原地址数据给改了,所以原对象的text并没被改。但list就不一样了,改的是原对象地址的数据 所以我们才会需要深拷贝。

然后我们再检验一次深拷贝的:

输出内容:

内容原始:Document{mText='11111100000', list=[00]}内容修改:Document{mText='111111', list=[00, 111]}内容原始:Document{mText='11111100000', list=[00]}复制代码

我们使用深拷贝的时候,将对象list也clone了,就没有指向的不再是原有地址了,所以改动也就影响不到原来数据咯。

另外:实现Cloneable接口只是一种方式。要实现clone也不一定非要实现这个接口(使用Object来重写clone方法的话一定要实现,不然会抛出异常)。

如果使用new的方式并不耗资源等,clone的时候我们传入自己,用new的效率或许会更高:

public Document(Document document) {        this.mText = document.getmText();        this.list = document.getList();    }@Override    public Document clone() throws CloneNotSupportedException {        Document document = new Document(this);        return document;    }复制代码

总结:原型模式在copy资源非常方便,当然拷贝不一定比new快,所以需要评估测试再考虑是否不用new

转载于:https://juejin.im/post/5b9893f9f265da0aa528f351

你可能感兴趣的文章
js之放大镜效果
查看>>
Cocos2d之Node类详解之节点树(一)
查看>>
023-请你说一说你知道的自动化测试框架
查看>>
response (响应对象)
查看>>
java.lang.StringBuilder源码分析
查看>>
php中的单引号与双引号详解
查看>>
java代码继承super
查看>>
Eclipse远程调试应用程序
查看>>
openj9
查看>>
继承现有的控件
查看>>
装逼语录:
查看>>
PHP函数
查看>>
[Leetcode]414. Third Maximum Number
查看>>
UTC引发时区配置和Linux系统时间和bios时间问题
查看>>
C语言32个关键字
查看>>
图像处理之canny---求梯度
查看>>
OpenGL编程轻松入门之一个简单的例子
查看>>
MVC控制器返回重定向操作
查看>>
LINUX总结
查看>>
编译php5.4的时候出现错误----configure: error: in `/usr/local/src/php540/php-5.4.0':
查看>>