一天一个设计模式---原型模式
来源:互联网 发布:印刷报价软件下载 编辑:程序博客网 时间:2024/06/05 02:03
介绍:用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。这个模式相对简单,其实我们只需要掌握对象拷贝的知识。
场景:我们在使用对象的时候可能会通过下面的方式来创建新的对象。但是,这样只是将stu2引用指向stu1,而并非创建一个新的对象。在我们之后对stu2的属性改变时,也会造成stu1的改变。
Student stu2 = stu1;
一、对象拷贝的概念
我们在实现对象拷贝的时候,首先应该实现Cloneable接口,并重写clone()方法。
这里,我们不得不提到对象拷贝的概念—也就是浅拷贝和深拷贝。
浅拷贝:
对值类型的成员变量进行值的复制,对引用类型的成员变量只复制引用,不复制引用的对象。也就是说,如果拷贝的对象中还有对象类型的属性,那么它的在之后的变换中是会对所用的引用造成影响的。
深拷贝:
对值类型的成员变量进行值的复制,对引用类型的成员变量也进行引用对象的复制。这样就避免了上面的这种情况的发生。
二、浅拷贝
场景:小米买了个PSP,小明看到了也让小米帮忙买了一个。但是,小米买来的时候激活用的是自己的账号。小明在用了一段时间后想修改用户名密码,并且增加内存大小。内存是增加了,但是由于自己修改了账号,导致小米的账号不能用了。。。
账号
public class Account { private String name; private String password; @Override public String toString() { return "Acount name:" + name + ",Acount name:" + password; } // setter and getter}
PSP
public class PSP implements Cloneable { private String color; private double price; private Account account; private int ram; @Override protected Object clone() { PSP psp = null; try { psp = (PSP) super.clone(); } catch (CloneNotSupportedException e) { e.printStackTrace(); } return psp; } @Override public String toString() { return color + "," + ram + "," + price + "," + account; } // setter and getter}
测试
public static void main(String[] args) { PSP psp1 = new PSP(); Account acc = new Account(); acc.setName("小米"); acc.setPassword("123"); psp1.setAccount(acc); psp1.setColor("red"); psp1.setPrice(1600.0); psp1.setRam(8); System.out.println("小米:" + psp1.toString()); PSP psp2 = (PSP) psp1.clone(); System.out.println("小明:" + psp2.toString()); System.out.println("小明修改内存和账号=========="); psp2.getAccount().setName("小明"); psp2.getAccount().setPassword("555"); psp2.setRam(16); System.out.println("小米:" + psp1.toString()); System.out.println("小明:" + psp2.toString()); }
输出
小米:red,8,1600.0,Acount name:小米,Acount name:123小明:red,8,1600.0,Acount name:小米,Acount name:123小明修改内存和账号==========小米:red,8,1600.0,Acount name:小明,Acount name:555小明:red,16,1600.0,Acount name:小明,Acount name:555
可以看到,浅拷贝的方式,基本属性是进行复制,而对象类型则还是使用原来的引用(也可通过查看两者Account的hashCode来说明)。
三、深拷贝
实现深拷贝,我们可以借助序列化(Serialization),我们可以将对象序列化写入流中,然后通过反序列化再获取,这样就能得到一个完整的拷贝。这里需要注意,我们的类需要实现Serializable接口,否则会报java.io.NotSerializableException的异常。
账号
public class Account implements Serializable { private static final long serialVersionUID = -7747721962690262418L; private String name; private String password; @Override public String toString() { return "Acount name:" + name + ",Acount name:" + password; } // setter and getter}
PSP
public class PSP implements Cloneable, Serializable { private static final long serialVersionUID = 6401635201114419015L; private String color; private double price; private Account account; private int ram; @Override protected Object clone() { PSP psp = null; try { // 将对象写到流里 ByteArrayOutputStream bos = new ByteArrayOutputStream(); ObjectOutputStream oos; oos = new ObjectOutputStream(bos); oos.writeObject(this); // 从流里读回来 ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray()); ObjectInputStream ois = new ObjectInputStream(bis); psp = (PSP) ois.readObject(); } catch (IOException | ClassNotFoundException e) { e.printStackTrace(); } return psp; } @Override public String toString() { return color + "," + ram + "," + price + "," + account; } // setter and getter}
测试
public static void main(String[] args) { PSP psp1 = new PSP(); Account acc = new Account(); acc.setName("小米"); acc.setPassword("123"); psp1.setAccount(acc); psp1.setColor("red"); psp1.setPrice(1600.0); psp1.setRam(8); System.out.println("小米:" + psp1.toString()); PSP psp2 = (PSP) psp1.clone(); System.out.println("小明:" + psp2.toString()); System.out.println("小明修改内存和账号=========="); psp2.getAccount().setName("小明"); psp2.getAccount().setPassword("555"); psp2.setRam(16); System.out.println("小米:" + psp1.toString()); System.out.println("小明:" + psp2.toString()); }
输出
小米:red,8,1600.0,Acount name:小米,Acount name:123小明:red,8,1600.0,Acount name:小米,Acount name:123小明修改内存和账号==========小米:red,8,1600.0,Acount name:小米,Acount name:123小明:red,16,1600.0,Acount name:小明,Acount name:555
可以看到,这样小明修改账号,小明的账号密码都不会修改,这样就避免上面的这种情况。
更多模式: 一天一个设计模式—分类与六大原则
更多源码: https://github.com/oDevilo/Java-Base
- 一天一个设计模式---原型模式
- 一天一个设计模式(1): 代理模式
- 一天一个设计模式(2): 外观模式
- 一天一个设计模式(3):观察者模式
- 一天一个设计模式(4):适配器模式
- 一天一个设计模式---单例模式
- 一天一个设计模式---代理模式
- 一天一个设计模式---享元模式
- 一天一个设计模式---工厂方法模式
- 一天一个设计模式---抽象工厂模式
- 一天一个设计模式---装饰者模式
- 一天一个设计模式---观察者模式
- 一天一个设计模式---适配器模式
- 一天一个设计模式---状态模式
- 一天一个设计模式---策略模式
- 一天一个设计模式---模板方法模式
- 一天一个设计模式---生成器模式
- 一天一个设计模式---桥接模式
- Android 6.0 运行时权限处理完全解析
- [C++]MySQL数据库操作实例
- 特征匹配,sift,surf,orb,brisk,brief
- (译)LearnOpenGL实际案例Breakout(六):碰撞检测
- Tablayout 设置字体大小
- 一天一个设计模式---原型模式
- js线程
- UVA 202 循环小数
- C 冒泡排序
- 记录ccui.listView打开界面不置顶的问题
- UML中的事物
- maven 手工添加oracle 驱动jar 到本地仓库
- 基于阿里云的maven配置
- 一起来搭建像Qt一样的win32图形框架(2)