java-设计模式(创建型)-【原型模式】
1.Prototype(原型模式)
定义:用原型实例指定创建对象的种类,并且通过克隆这些原型创建新的对象。
注意:这里的“克隆”,指的是通过调用Object类的clone方法来完成的,它直接在内存中复制数据,
因此不会调用到类的构造方法。不但构造方法中的代码不会执行,甚至连访问权限都对原型模式无效
使用场景:
原型模式本质上就是对象的拷贝,使用对象拷贝代替对象创建的原因有很多。比如对象的初始化构造非常复杂,
消耗资源巨大;运行时对象状态变化不可重现;无法获得对象的成员的运行时值等
使用原型模式创建对象比直接new一个对象在性能上要好的多,因为Object类的clone方法是一个本地方法,
它直接操作内存中的二进制流,特别是复制大对象时,性能的差别非常明显。
克隆满足的条件:
clone()方法将对象复制了一份并返还给调用者。所谓“复制”的含义与clone()方法是怎么实现的。一般而言,clone()方法满足以下的描述:
(1)对任何的对象x,都有:x.clone()!=x。换言之,克隆对象与原对象不是同一个对象。
(2)对任何的对象x,都有:x.clone().getClass() == x.getClass(),换言之,克隆对象与原对象的类型一样。
(3)如果对象x的equals()方法定义其恰当的话,那么x.clone().equals(x)应当成立的。
在JAVA语言的API中,凡是提供了clone()方法的类,都满足上面的这些条件。JAVA语言的设计师在设计自己的clone()方法时,
也应当遵守着三个条件。一般来说,上面的三个条件中的前两个是必需的,而第三个是可选的
浅克隆和深克隆:
浅复制:将一个对象复制后,基本数据类型的变量都会重新复制创建,而引用类型,指向的还是原对象所指向的。
深复制:将一个对象复制后,不论是基本数据类型还有引用类型,都是重新创建的即引用类型的对象还会复制多一份。
注意这里涉及到复制的深度问题,你要复制多深,即引用对象的深度。
2.原型模式与抽象工厂模式区别
采用工厂模式:为每一个具体子类定义一个与其等级平行的工厂类,这样会变得重复累赘。
采用原型模式:将对象本身当做工厂,通过clone方法克隆出自己的副本。
3.浅克隆和深克隆
/* * 一个原型类,只需要实现Cloneable接口,覆写clone方法, * 此处clone方法可以改成任意的名称,因为Cloneable接口是个空接口, * 你可以任意定义实现类的方法名,如cloneA或者cloneB, * 因为此处的重点是super.clone()这句话,super.clone()调用的是Object的clone()方法, * */ public class Prototype implements Cloneable { //浅复制:需要用public修饰符覆写clone方法 public Object clone() throws CloneNotSupportedException { Prototype proto=(Prototype)super.clone(); return proto; } //深复制:将对象序列化入内存,再复制反序列化对象出来。 public Object deepclone() throws IOException, ClassNotFoundException { //使用ByteArray输入输出流(节点流)写入内存(目的地)里, //使用Object输入输出流(处理流)将对象(源目标)写入。 //写入当前对象的二进制流 ByteArrayOutputStream bos=new ByteArrayOutputStream();//目的地 ObjectOutputStream oos=new ObjectOutputStream(bos); oos.writeObject(this);//源头写入 //读取二进制流产生的新对象 byte[] buf=new byte[1024]; ByteArrayInputStream bis=new ByteArrayInputStream(bos.toByteArray()); ObjectInputStream ois=new ObjectInputStream(bis); Prototype pro=(Prototype)ois.readObject(); return pro; } }
4.图解
4.1 颜色原型及实现子类
//原型(接口)类,实现clonealbe接口 //指关心方法 public interface Prototype extends Cloneable{ public Prototype clonenew()throws CloneNotSupportedException; public void display(); } //颜色类,包含所有颜色,由初始化时定义该颜色和颜色值 class ColorProto implements Prototype { private String colorName; public String getColorName() { return colorName; } public void setColorName(String colorName) { this.colorName = colorName; } private int r; private int g; private int b; public ColorProto (String colorName,int r,int g,int b) { this.colorName=colorName; this.r=r; this.g=g; this.b=b; } //克隆自己 @Override public ColorProto clonenew() throws CloneNotSupportedException { // TODO Auto-generated method stub ColorProto cp=(ColorProto) super.clone(); return cp; } //显示自己的颜色名和值 @Override public void display() { // TODO Auto-generated method stub System.out.println(colorName+":"+r+","+g+","+b); } }
4.2 颜色管理器
//管理颜色类,具有添加,取出颜色种类的方法 public class ColorProManage { private HashMap<String ,ColorProto> hm=new HashMap<String ,ColorProto>(); //放入颜色 public void putColor (ColorProto cp) { String colorName=cp.getColorName(); hm.put(colorName, cp); } //取出颜色 public ColorProto getColor(String colorName) { ColorProto cp=hm.get(colorName); if(cp!=null) return cp; else return null; } }
4.3 测试
public class Test { public static void main(String[] args) throws Exception { //新建颜色管理器 ColorProManage cm=new ColorProManage(); //为颜色管理器添加颜色 ColorProto cp1=new ColorProto("red", 255, 0, 0); ColorProto cp2=new ColorProto("green", 0, 255, 0); ColorProto cp3=new ColorProto("blue",0, 0, 255); cm.putColor(cp1); cm.putColor(cp2); cm.putColor(cp3); //克隆出颜色管理器里的红色 ColorProto cpclone= cm.getColor("red").clonenew(); cpclone.display(); } }
4.4 运行结果
red:255,0,0