原型模式 - 创建者模式

个人理解:    

模式类型:

    Prototype 原型模式 - 创建者模式

意图:
    specifying the kind of objects to create using a prototypical instance
    creating new objects by copying this prototype

    
概述:
    原型模式是一种创建型设计模式,它通过复制一个已经存在的实例来返回新的实例,而不是新建实例.被复制的实例就是我们所称的原型,这个原型是可定制的.
    原型模式多用于创建复杂的或者耗时的实例, 因为这种情况下,复制一个已经存在的实例可以使程序运行更高效,或者创建值相等,只是命名不一样的同类数据.

    
    原型模式中的拷贝分为"浅拷贝"和"深拷贝":
    浅拷贝: 对值类型的成员变量进行值的复制,对引用类型的成员变量只复制引用,不复制引用的对象.
    深拷贝: 对值类型的成员变量进行值的复制,对引用类型的成员变量也进行引用对象的复制.

    
    注:使用原型模式复制对象不会调用类的构造方法。因为对象的复制是通过调用Object类的clone方法来完成的,它直接在内存中复制数据,因此不会调用到类的构造方法。不但构造方法中的代码不会执行,甚至连访问权限都对原型模式无效。还记得单例模式吗?单例模式中,只要将构造方法的访问权限设置为private型,就可以实现单例。但是clone方法直接无视构造方法的权限,所以,单例模式与原型模式是冲突的,在使用时要特别注意。
    
    不是基本类型,所以成员变量不会被拷贝,需要我们自己实现深拷贝。
    深拷贝与浅拷贝问题中,会发生深拷贝的有java中的8中基本类型以及他们的封装类型,另外还有String类型。其余的都是浅拷贝。


角色:

Client - creates a new object by asking a prototype to clone itself.
Prototype - declares an interface for cloning itself.
ConcretePrototype - implements the operation for cloning itself.

模式的应用场景:
       使用原型模式创建对象比直接new一个对象在性能上要好的多,因为Object类的clone方法是一个本地方法,它直接操作内存中的二进制流,特别是复制大对象时,性能的差别非常明显。
       使用原型模式的另一个好处是简化对象的创建,使得创建对象就像我们在编辑文档时的复制粘贴一样简单。
       因为以上优点,所以在需要重复地创建相似对象时可以考虑使用原型模式。比如需要在一个循环体内创建对象,假如对象创建过程比较复杂或者循环次数很多的话,使用原型模式不但可以简化创建过程,而且可以使系统的整体性能提高很多。

结构图:



模式的优缺点:



注意事项:
    使用原型模式复制对象不会调用类的构造方法。因为对象的复制是通过调用Object类的clone方法来完成的,它直接在内存中复制数据,因此不会调用到类的构造方法。不但构造方法中的代码不会执行,甚至连访问权限都对原型模式无效。还记得单例模式吗?单例模式中,只要将构造方法的访问权限设置为private型,就可以实现单例。但是clone方法直接无视构造方法的权限,所以,单例模式与原型模式是冲突的,在使用时要特别注意。
    深拷贝与浅拷贝。Object类的clone方法只会拷贝对象中的基本的数据类型,对于数组、容器对象、引用对象等都不会拷贝,这就是浅拷贝。如果要实现深拷贝,必须将原型模式中的数组、容器对象、引用对象等另行拷贝。
   
代码(其实读UML图要比代码还要一目了然):


1、Shape.java

public abstract class Shape implements Cloneable {
   
   private String id;
   protected String type;
   
   abstract void draw();
   
   public String getType(){
      return type;
   }
   
   public String getId() {
      return id;
   }
   
   public void setId(String id) {
      this.id = id;
   }
   
   public Object clone() {
      Object clone = null;
      
      try {
         clone = super.clone();
         
      } catch (CloneNotSupportedException e) {
         e.printStackTrace();
      }
      
      return clone;
   }
}

2 、Rectangle.java

public class Rectangle extends Shape {

   public Rectangle(){
     type = "Rectangle";
   }

   @Override
   public void draw() {
      System.out.println("Inside Rectangle::draw() method.");
   }
}

Square.java

public class Square extends Shape {

   public Square(){
     type = "Square";
   }

   @Override
   public void draw() {
      System.out.println("Inside Square::draw() method.");
   }
}

Circle.java

public class Circle extends Shape {

   public Circle(){
     type = "Circle";
   }

   @Override
   public void draw() {
      System.out.println("Inside Circle::draw() method.");
   }
}

3、 ShapeCache.javaCreate a class to get concrete classes from database and store them in a  Hashtable .

import java.util.Hashtable;

public class ShapeCache {
	
   private static Hashtable<String, Shape> shapeMap  = new Hashtable<String, Shape>();

   public static Shape getShape(String shapeId) {
      Shape cachedShape = shapeMap.get(shapeId);
      //---这句是重点!!,返回的是对象的克隆!----
      return (Shape) cachedShape.clone();
   }

   // for each shape run database query and create shape
   // shapeMap.put(shapeKey, shape);
   // for example, we are adding three shapes
   
   public static void loadCache() {
      Circle circle = new Circle();
      circle.setId("1");
      shapeMap.put(circle.getId(),circle);

      Square square = new Square();
      square.setId("2");
      shapeMap.put(square.getId(),square);

      Rectangle rectangle = new Rectangle();
      rectangle.setId("3");
      shapeMap.put(rectangle.getId(), rectangle);
   }
}

4、 PrototypePatternDemo.javaPrototypePatternDemo  uses  ShapeCache  class to get clones of shapes stored in a Hashtable .

public class PrototypePatternDemo {
   public static void main(String[] args) {
      ShapeCache.loadCache();

      Shape clonedShape = (Shape) ShapeCache.getShape("1");
      System.out.println("Shape : " + clonedShape.getType());		

      Shape clonedShape2 = (Shape) ShapeCache.getShape("2");
      System.out.println("Shape : " + clonedShape2.getType());		

      Shape clonedShape3 = (Shape) ShapeCache.getShape("3");
      System.out.println("Shape : " + clonedShape3.getType());		
   }
}

5、输出:

Shape : Circle
Shape : Square
Shape : Rectangle


--===========================深拷备的分割线===============================--

深拷备是2种方法:

1、利用super.clone(); 后,再给不属于基本变量的类型属性赋值

package com.lee.desingerPattener23.prototype.example3;

class Professor implements Cloneable{  
    String name;  
    int age;  
    Professor(String name,int age){  
        this.name=name;  
        this.age=age;  
    }  
    public Object clone(){  
        Object o=null;  
        try{  
            o=super.clone();  
        }catch(CloneNotSupportedException e){  
            System.out.println(e.toString());  
        }  
        return o;  
    }  
}  
public class Student implements Cloneable{  
    String name;  
    int age;  
    Professor p;  
    Student(String name,int age,Professor p){  
        this.name=name;  
        this.age=age;  
        this.p=p;  
    }  
    public Object clone(){  
        Student o=null;  
        try{  
            o=(Student)super.clone();  
        }catch(CloneNotSupportedException e){  
            System.out.println(e.toString());  
        }  
       // --- 重点!:调用Professor类的clone()方法实现深拷贝 --- 
        o.p=(Professor)this.p.clone();  
        return o;  
    }  
    
    public static void main(String[] args){  
        Professor p=new Professor("wangwu",50);  
        Student s1=new Student("zhangsan",18,p);  
        Student s2=(Student)s1.clone();  
        s2.p.name="lisi";  
       s2.p.age=30;  
       //学生1的教授不改变  
       System.out.println("name="+s1.p.name+","+"age="+s1.p.age);
       System.out.println("name="+s2.p.name+","+"age="+s2.p.age);  
  }  
}  



2、利用序列化实现深度拷贝

把对象写到流里的过程是串行化(Serilization)过程,又叫对象序列化,而把对象从流中读出来的(Deserialization)过程叫反序列化。应当指出的是,写在流里的是对象的一个拷贝,而原对象仍然存在于JVM里面,因此在Java语言里深复制一个对象,常常可以先使对象实现Serializable接口,然后把对象(实际上只是对象的一个拷贝)写到一个流里,再从流里读出来便可以重建对象。


package com.lee.desingerPattener23.prototype.example3;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OptionalDataException;
import java.io.Serializable;

class Profess implements Serializable{  
    String name;  
    int age;  
    Profess(String name,int age){  
        this.name=name;  
        this.age=age;  
    }  
}  
public class StudentDeep implements Serializable{  
    String name;  
    int age;  
    Profess p;  
    StudentDeep(String name,int age,Profess p){  
        this.name=name;  
        this.age=age;  
        this.p=p;  
    }  
    public Object deepClone() throws IOException,OptionalDataException,ClassNotFoundException{
    	Object o = null;
    	try{
		    //将对象写到流里  
		    ByteArrayOutputStream bo=new ByteArrayOutputStream();  
		    ObjectOutputStream oo=new ObjectOutputStream(bo);  
		    oo.writeObject(this);// object of studnet  
		    oo.close();
		    //从流里读出来  
		    ByteArrayInputStream bi=new ByteArrayInputStream(bo.toByteArray());  
		    ObjectInputStream oi=new ObjectInputStream(bi);  
		    o = oi.readObject();
		    oi.close();
    	}catch (IOException e)  {  
            e.printStackTrace();  
        } catch (ClassNotFoundException e){  
            e.printStackTrace();  
        }  
        return o; 
    }   
    public static void main(String[] args) throws OptionalDataException, ClassNotFoundException, IOException{  
        Profess p=new Profess("wangwu",50);  
        StudentDeep s1=new StudentDeep("zhangsan",18,p);  
        StudentDeep s2=(StudentDeep)s1.deepClone();  
        s2.p.name="lisi";  
        s2.p.age=30;  
     //学生1的教授不改变  
     System.out.println("name="+s1.p.name+","+"age="+s1.p.age);
     System.out.println("name="+s2.p.name+","+"age="+s2.p.age);   
  }  
}  

输出结果:

name=wangwu,age=50
name=lisi,age=30


所有模式:
     创建型模式,共五种:工厂方法模式、抽象工厂模式单例模式建造者模式原型模式
结构型模式,共七种:适配器模式装饰器模式代理模式外观模式桥接模式组合模式享元模式
    行为型模式,共十一种:策略模式模板方法模式观察者模式迭代子模式责任链模式命令模式备忘录模式状态模式访问者模式中介者模式解释器模式
    补充模式:空对象模式


参考/转自:

http://blog.csdn.net/zhengzhb/article/details/7393528
http://www.tutorialspoint.com/design_pattern/prototype_pattern.htm
http://www.oodesign.com/prototype-pattern.html
http://blog.csdn.net/chjttony/article/details/7477346


转载请注明:http://blog.csdn.net/paincupid/article/details/46860283



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值