设计模式(七)---原始模型模式

1、简介:

     原始模型模式属于对象的创建模式。通过给出一个原型对象来指明要创建对象的类型,然后用复制原型对象的方法来创建出更多同类型的对象。

     Java所有的类都是从java.lang.Object类继承来的,Object类提供clone()方法对对象进行复制。对象的复制有一个基本问题,就是对象通常都有对其它的对象的引用,

当使用Object类的clone()方法来复制一个对象时,此对象对其它对象的引用也会被复制一份

    java语言提供Cloneable接口只起一个作用,就是在运行期间通知java虚拟机可以安全的在这个类上使用clone()方法,通过调用这个clone()方法可以得到一个对象的复制。

由于Object类本身并不实现Cloneable接口,因此如果实现类没有实现Cloneable接口,调用clone()方法会抛出CloneNotSupportedException异常

    clone()方法将对象复制一份,并返还给调用者,一般调用clone()方法需要满足一下条件:

      (1)、对于任何对象x,都有:x.clone()!=x。也就是克隆的对象和原对象不是一个对象。

      (2)、对于任何对象x,都有:x.clone().getClass()=x.getClass()。也就是克隆对象与原对象是相同的类型。

      (3)、如果对象x的equal()方法定义恰当的话,那么x.clone().equal(x)应该成立。

2、原始模型模式:

    原始模型模式分为两种表现形式,1、简单形式,2、登记形式

  2.1、简单形式的原始模型模式类图

  2.2、这种形式涉及到三个角色:

      客户角色(client)          :客户类发起创建对象的请求。

      抽象原型角色(prototype)      :抽象角色,一般由java接口或是java抽象类实现,给出所有具体原型类所需的所有接口。

      具体原型角色(Concrete prototype):被复制的对象,需要实现抽象原型所需的接口。

  2.3、简单形式源代码:

    2.3.1、抽象原型角色代码

package prototype;
/**
 * ********************************************************  
* @ClassName: Prototype 
* @Description: 抽象原型角色
*  
**********************************************************
 */
public interface Prototype extends Cloneable {
    public Object clone() throws CloneNotSupportedException;
}

    2.3.2、具体原型角色代码

package prototype;
/**
 * ********************************************************  
* @ClassName: ConcretePrototype 
* @Description: 具体原型角色
*  
**********************************************************
 */
public class ConcretePrototype implements Prototype {

    @Override
    public Object clone() throws CloneNotSupportedException {
        try{
            return super.clone();
        }catch(CloneNotSupportedException e){
            return null;
        }
        
    }
}

    2.3.3、客户角色代码

package prototype;
/**
 * ********************************************************  
* @ClassName: Client 
* @Description: 客户角色
*  
**********************************************************
 */
public class Client {
        private Prototype prototype;
        
        public void operation(Prototype example) throws CloneNotSupportedException{
             Prototype p = (Prototype) example.clone();
        }
}

  2.4、登记形式的原始模型模型类图

  2.5、这种形式涉及到以下四个角色:

      客户角色(client)           :客户类发起创建对象的请求。

      抽象原型角色(prototype)       :抽象角色,一般由java接口或是java抽象类实现,给出所有具体原型类所需的所有接口。

      具体原型角色(Concrete prototype) :被复制的对象,需要实现抽象原型所需的接口。

      原型管理器角色(Prototype Manager):记录每一个被创建的对象。供外界获取已经登记过的对象

  2.6、登记形式源代码

      2.6.1、抽象原型角色代码

package Prototype.RegistPrototype;
/**
 * ********************************************************  
* @ClassName: Prototype 
* @Description: 登记形式抽象原型角色 
*  
**********************************************************
 */
public interface Prototype extends Cloneable {
     public Object clone() throws CloneNotSupportedException;
}

      2.6.2、具体原型角色代码

package Prototype.RegistPrototype;
/**
 * ********************************************************  
* @ClassName: ConcretePrototype 
* @Description: 登记形式具体原型角色
*  
**********************************************************
 */
public class ConcretePrototype implements Prototype {
    //克隆方法
    @Override
    public synchronized Object clone() throws CloneNotSupportedException {
        Prototype temp = null;
                  try {
                      temp = (Prototype) super.clone();
                  } catch (Exception e) {
                      System.out.println("复制失败");
                  }
                return temp;
    }

}

      2.6.3、原型管理器代码

package Prototype.RegistPrototype;

import java.util.Vector;
/**
 * ********************************************************  
* @ClassName: PrototypeManager 
* @Description: 原型管理器角色
*  
**********************************************************
 */
public class PrototypeManager {
    private Vector<Prototype> vector = new Vector<Prototype>();
          //增加一个对象
          public void add(Prototype e){
              vector.add(e);
          }
          //取出一个登记过的对象
          public Prototype get(int i){
              return (Prototype) vector.get(i);
         }
          //获取聚集的大小
          public int getSize(){
              return vector.size();
          }
}

      2.6.4、客户角色代码

package Prototype.RegistPrototype;
/**
 * ********************************************************  
* @ClassName: Client 
* @Description: 客户角色
*  
**********************************************************
 */

public class Client {
    private PrototypeManager pm;
         private Prototype p;
         
         public void registerPrototype(Prototype prototype) throws CloneNotSupportedException{
             //获取对象
             Prototype temp = (Prototype) prototype.clone();
             //将对象放入原型管理器中
             pm.add(temp);
         }
}

2.7、两种形式的比较

    可以看出,如果要创建的原型对象少且固定的话可以考虑使用简单形式的原型模式。如果要创建的原型对象不固定,可以使用登记形式的原型模式。

原型对象有原型管理器保管,如果其中有则直接拿出,没有则复制并加入其中。

2.8、模式的实现

  复制和克隆有两种方式,分别是深复制和浅复制

    2.8.1、浅复制:被复制对象的所有变量都与原来对象有相同的值,而所有对其对象的引用都指向原对象。浅复制只考虑复制所考虑的对象,而不复制它所引用的对象。

    2.8.2、深复制:被复制对象的所有变量都与原来对象有相同的值,那些引用其他对象的变量指向被复制的新对象。深复制中那些引用其他对象的变量将指向被复制过的新对象,

            也就是深复制把要复制的对象所引用的对象都复制了一遍。

2.9、总结

  原始模型模式的优缺点:

      优点:

        1、  原始模型模式允许动态地增加或减少产品类。由于创建产品类实例的方法是产品类内部具有的,因此,增加新产品的对整个结构没有影响。

        2、  原始模型模式提供简化的创建结构。工厂方法模式常常需要有一个与产品类等级相同的结构,而原始模型模式就不需要这样。

        3、  具有给一个应用软件动态加载新功能的能力。

        4、  产品类不需要非得有任何事先确定的等级结构,因为原始模型模式适用于任何的等级。

      缺点:

        1、原始模型模式最主要的缺点就是需要为每一个类都必须具备一个复制方法。

        2、如果在原型对象中有间接对象,可以将间接对象设置为transient不予以复制,或者自行创建出相当的同种对象。

原文地址:https://www.cnblogs.com/shun-gege/p/7485711.html