原型模式:做到是原型,那肯定是自己本身才是原型,原型模式属于对象的创建模式。
关于原型模式的实现方式分2种:
(1)简单形式、(2)登记形式,这两种表现形式仅仅是原型模式的不同实现。
1 package inter.method; 2 /** 3 * 提供一个具有复制本身的接口 4 * @author zengrong 5 * 6 */ 7 public interface Prototype { 8 9 public Object clone(); 10 }
1 package impl.method; 2 3 import inter.method.Prototype; 4 5 public class ConcretePrototype1 implements Prototype { 6 /** 7 * 接口类对象使用了object,所有在复写时候,类型就随便都是可以的 8 */ 9 public Prototype clone(){ 10 //最简单的克隆,新建一个自身对象,由于没有属性就不再复制值了 11 Prototype prototype = new ConcretePrototype1(); 12 return prototype; 13 } 14 }
1 package impl.method; 2 3 import inter.method.Prototype; 4 5 /** 6 * 客户端 7 * @author zengrong 8 * 9 */ 10 public class Client { 11 12 /** 13 * 需要创建的原型 14 */ 15 16 private Prototype prototype; 17 18 public Client( Prototype prototype){ 19 this.prototype=prototype; 20 } 21 /** 22 * 创建原型 23 */ 24 public void create () { 25 Prototype cloneprototype = (Prototype) prototype.clone(); 26 } 27 }
第二种原型模式:登记模式。就是价将原先进行实例的方式是客户端和原型直接联系,这样耦合性高,解决办法就是设置一个管理器进行来管理生成这些原型,
1 package inter.pro.two; 2 3 import java.util.HashMap; 4 import java.util.Map; 5 6 /** 7 * 原型管理器 8 * @author zengrong 9 *,作为对所有原型对象的登记, 10 *这个角色提供必要的方法, 11 *供外界增加新的原型对象和取得已经登记过的原型对象。 12 */ 13 public class PromManger { 14 /** 15 * 用来记录原型 16 */ 17 private static Map<String,PrototypeTwo> map = new HashMap<String,PrototypeTwo>(); 18 19 private PromManger(){}//私有化构造 20 21 /** 22 * 设置一个方法来进行向原型集合中添加 23 */ 24 public synchronized static void setPrototypes(String prototypeId,PrototypeTwo prototypeTwo) { 25 map.put(prototypeId, prototypeTwo); 26 27 } 28 /** 29 * 从原型管理器里面删除某个原型注册 30 * @param prototypeId 原型编号 31 */ 32 public synchronized static void removePrototype(String prototypeId){ 33 map.remove(prototypeId); 34 } 35 36 /** 37 * 获取原型 38 */ 39 public synchronized static PrototypeTwo getPrototypeTwo( String prototypeId) { 40 PrototypeTwo prototypeTwo = map.get(prototypeId); 41 if(prototypeTwo==null){ 42 System.out.println("该原型还没有进行登记注册------无法获取---"); 43 } 44 return prototypeTwo; 45 } 46 47 48 49 }
1 package inter.pro.two; 2 3 public class PrototypeCol implements PrototypeTwo { 4 private String name; 5 public PrototypeTwo clone(){ 6 PrototypeCol prototype = new PrototypeCol(); 7 prototype.setName(this.name); 8 return prototype; 9 } 10 public String toString(){ 11 return "Now in Prototype1 , name = " + this.name; 12 } 13 @Override 14 public String getName() { 15 return name; 16 } 17 18 @Override 19 public void setName(String name) { 20 this.name = name; 21 } 22 }
1 package inter.pro.two; 2 /** 3 * 4 * @author zengrong 5 * 6 */ 7 public interface PrototypeTwo { 8 /** 9 * 具体的原型 10 * @return 11 */ 12 public PrototypeTwo clone(); 13 public String getName(); 14 public void setName(String name); 15 16 17 }
简单原型和登记原型对比:
在原型数量很少的情况下,采用第一种方式,客户端呢保存原型,
但是在数量不确定的情况下,采用第二中方式,在复制一个原型对象之前,客户端可以查看管理员对象是否已经有一个满足要求的原型对象。如果有,可以直接从管理员类取得这个对象引用;如果没有,客户端就需要自行复制此原型对象。
在Java中有个方法和这个其实是一样的,Java中得克隆方法;
Java的所有类都是从java.lang.Object类继承而来的,而Object类提供protected Object clone()方法对对象进行复制,子类当然也可以把这个方法置换掉,提供满足自己需要的复制方法。对象的复制有一个基本问题,就是对象通常都有对其他的对象的引用。当使用Object类的clone()方法来复制一个对象时,此对象对其他对象的引用也同时会被复制一份
Java语言提供的Cloneable接口只起一个作用,就是在运行时期通知Java虚拟机可以安全地在这个类上使用clone()方法。通过调用这个clone()方法可以得到一个对象的复制。由于Object类本身并不实现Cloneable接口,因此如果所考虑的类没有实现Cloneable接口时,调用clone()方法会抛出CloneNotSupportedException异常。
克隆满足的条件
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()方法时,也应当遵守着三个条件。一般来说,上面的三个条件中的前两个是必需的,而第三个是可选的。
在这里其实涉及到一个值传递和引用传递!