java设计模式-原型模式
来源:互联网 发布:青牛软件怎么样 编辑:程序博客网 时间:2024/05/29 04:17
原型模式,顾名思义就是对现有的一个对象进行复制克隆出一个全新的对象。被复制的对象就叫做原型对象,复制出来的克隆对象和原型对象具有相同的属性和方法。
在一下情况我们一般会考虑使用原型模式来创建对象:
- 将对象交给外部处理的时候,为了防止外部操作对象修改数据导致其他地方受影响(实际传递的都是对象的引用,所以如果多个地方引用了该对象可能会造成不必要的麻烦),所以可以考虑使用原型模式来克隆出一个新的对象,及我们明确需要一个全新的对象。
- 如果在创建一个新对象的时候,初始化的资源非常的多,可以考虑使用原型模式来对一个现有的对象进行克隆。
下面我们看看原型模式的UML图:
- Prototype:可以是一个接口或者抽象类,声明了clone的能力
- ConcretePrototype:实际上具备clone能力的类
- Client:使用clone功能的客户端。
我们先看个例子来感受一下原型模式的使用。
public class Person implements Cloneable{ private String name; private int age; public Person(String name,int age) { this.name = name; this.age = age; } public void run() { System.out.println("run ......"); } @Override public Object clone() throws CloneNotSupportedException { return super.clone(); } @Override public String toString() { return "Person{" + "name='" + name + '\'' + ", age=" + age + '}' + super.toString(); }}public class Test { public static void main(String[] args) { Person p = new Person("zhangshan",34); p.run(); System.out.println(p); try { Person pClone = (Person) p.clone(); pClone.run(); System.out.println(pClone); } catch (CloneNotSupportedException e) { e.printStackTrace(); } }}
运行结果:
run ......Person{name='zhangshan', age=34}designpattern.prototype.Person@1b6d3586run ......Person{name='zhangshan', age=34}designpattern.prototype.Person@4554617c
可以看到,克隆的是一个全新的对象,内容和原型对象一模一样。
我们先讨论下两个概率:浅拷贝和深拷贝。
浅拷贝:
在克隆一个对象的时候,如果对象中有引用型数据,那么只会拷贝该数据的引用地址,并不会将引用数据对象全部拷贝。
深拷贝:
与浅拷贝不同,在拷贝引用型数据的时候,会完完全全的将引用型数据对象全部拷贝。
举个例子看下它们的区别:
class Data implements Cloneable{ private String title; private ArrayList<String> contents = new ArrayList<>(); public void setTitle(String title) { this.title = title; } public void addContent(String content) { contents.add(content); } @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); } @Override public String toString() { return "Data{" + "title='" + title + '\'' + ", contents=" + contents + '}'; }}public class Test { public static void main(String[] args) { Data data = new Data(); data.setTitle("呵呵"); data.addContent("呵呵大大"); System.out.println("原数据:" + data); try { Data clone = (Data) data.clone(); System.out.println("克隆数据:" + clone); System.out.println("-------------修改克隆数据---------------"); clone.setTitle("么么"); clone.addContent("么么哒"); System.out.println("修改后原数据:" + data); System.out.println("修改后克隆数据:" + clone); } catch (CloneNotSupportedException e) { e.printStackTrace(); } }}
打印结果:
原数据:Data{title='呵呵', contents=[呵呵大大]}克隆数据:Data{title='呵呵', contents=[呵呵大大]}-------------修改克隆数据---------------修改后原数据:Data{title='呵呵', contents=[呵呵大大, 么么哒]}修改后克隆数据:Data{title='么么', contents=[呵呵大大, 么么哒]}
从结果看到,尽管克隆了一个新对象,但是原型对象的contents和克隆对象的contents的内容是一样的。
怎么解决呢?就需要使用到了深拷贝。
稍稍做一些修改
class Data implements Cloneable{ private String title; private ArrayList<String> contents = new ArrayList<>(); public void setTitle(String title) { this.title = title; } public void addContent(String content) { contents.add(content); } @Override protected Object clone() throws CloneNotSupportedException { Data data = (Data) super.clone(); data.contents = (ArrayList<String>) contents.clone(); return data; } @Override public String toString() { return "Data{" + "title='" + title + '\'' + ", contents=" + contents + '}'; }}
再看看打印:
原数据:Data{title='呵呵', contents=[呵呵大大]}克隆数据:Data{title='呵呵', contents=[呵呵大大]}-------------修改克隆数据---------------修改后原数据:Data{title='呵呵', contents=[呵呵大大]}修改后克隆数据:Data{title='么么', contents=[呵呵大大, 么么哒]}
原型对象和克隆对象的数据不一样了。
所以在clone对象的时候,如果遇到了引用型数据,需用调用引用型数据的clone()来重新克隆一份新的数据,而不是引用地址。
我们也是建议如果需要clone对象的话尽量使用深拷贝,除非你确定你的对象都是数值型数据。
在java中如果想使用原型模式来创建对象,首先必须是要实现Cloneable接口,这只是一个标记接口,里面啥也没有,然后覆写clone()方法即可。
阅读全文
0 0
- java 原型设计模式
- Java原型设计模式
- java设计模式(原型模式)
- java设计模式---原型模式
- java设计模式---原型模式
- java设计模式---原型模式
- Java设计模式---原型模式
- JAVA设计模式:原型模式
- java设计模式----原型模式
- JAVA 设计模式 - 原型模式
- 《Java设计模式》 原型模式
- Java设计模式 -- 原型模式
- Java设计模式--原型模式
- Java 设计模式-原型模式
- JAVA设计模式--原型模式
- java设计模式-原型模式
- Java设计模式--原型模式
- java设计模式,原型模式
- java设计模式-Builder建造者模式
- JMS消息确认模式
- 字符编码
- DNS解析原理
- [Linux移植一]ubuntu搭建samba服务器
- java设计模式-原型模式
- Linux进程地址空间 && 进程内存布局
- 菜鸡的Django学习笔记(三)完成一个博客
- Github使用指南
- 重定义容器排序方式
- 共用体
- java设计模式-策略模式
- 测试人员在敏捷测试中的关注点
- 经验积累2017-12-2