软件设计 原型模式 Prototype Pattern

原型模式 Prototype Pattern

 

原型模式实际上就是对象的拷贝。

原型模式使用原型实例指定待创建对象的类型,并且通过复制这个原型来创建新的对象。也就是说,原型对象作为模板,通过克隆操作,来产生更多的对象,就像细胞的复制一样。

原型模式的拷贝分为浅拷贝深拷贝

 

浅拷贝

对于类中基本数据类型,会直接复制值给拷贝对象。

对于类中引用类型,只会复制对象的地址,而实际上指向的还是原来的那个对象。

// 基本类型浅拷贝
int a = 10;
int b = a;
// 输出:true
System.out.println(a == b);

// 引用类型浅拷贝,拷贝的仅仅是对上面对象的引用
Object o = new Object();
Object k = o;
// 输出:true
System.out.println(o == k);


Java 中,就可以实现 Cloneable 接口提供的拷贝机制,来实现原型模式:
1、定义实体类实现 Cloneable 接口

/**
* 用户
* <p>注意需要实现 Cloneable 接口
*/
public class Student implements Cloneable {
   String name;
   
   public Student(String name){
       this.name = name;
  }
   
   public String getName() {
       return name;
  }
   
   /**
    * 提升clone方法的访问权限
    * @return 对象
    * @throws CloneNotSupportedException 不支持克隆异常
    */
   @Override
   public Object clone() throws CloneNotSupportedException {
       return super.clone();
  }
   
}

2、来看看克隆的对象是不是原来的对象

Student student0 = new Student();
Student student1 = (Student) student0.clone();
System.out.println(student0);
System.out.println(student1);
可以看到,通过 clone() 方法克隆的对象并不是原来的对象,
   
我们来看看如果对象内部有属性会不会一起进行克隆:
public class Student implements Cloneable{
   String name;
   public Student(String name){
       this.name = name;
  }
   public String getName() {
       return name;
  }
   @Override
   public Object clone() throws CloneNotSupportedException {
       return super.clone();
  }
}


Student student1 = new Student("程序航");
Student student2 = (Student) student1.clone();
// 输出:true
System.out.println(student1.getName() == student2.getName());
// 输出:false
System.out.println(student1 == student2);

可以看到,虽然 Student 对象成功拷贝,但是其内层对象并没有进行拷贝,依然只是对象引用的复制。所以 Java 为我们提供的 clone 方法只会进行浅拷贝。那么如何才能实现深拷贝呢?

 

深拷贝

无论是基本类型还是引用类型,深拷贝会将引用类型的所有内容,全部拷贝为一个新的对象,包括对象内部的所有成员变量,也会进行拷贝。

1、对成员变量也进行拷贝

@Override
public Object clone() throws CloneNotSupportedException {  
   Student student = (Student) super.clone();
   // 这里我们改进一下,针对成员变量也进行拷贝
   student.name = new String(name);
   // 成员拷贝完成后,再返回
   return student;  
}

2、再执行上述的代码

Student student1 = new Student("程序航");
Student student2 = (Student) student1.clone();
// 输出:false
System.out.println(student1.getName() == student2.getName());
// 输出:false
System.out.println(student1 == student2);
可以看到, Student 对象和其中的属性 name 都进行了拷贝,是完全不一样的对象了。这样就是拷贝生成了一个全新的对象,也就是深拷贝了。

 

优缺点;

优点

1、性能提高。

2、逃避构造函数的约束。

缺点

1、配备克隆方法需要对类的功能进行通盘考虑,这对于全新的类不是很难,但对于已有的类不一定很容易,特别当一个类引用不支持串行化的间接对象,或者引用含有循环结构的时候。

2、必须实现 Cloneable 接口。

 

使用场景:

1、资源优化场景。

2、类初始化需要消化非常多的资源,这个资源包括数据、硬件资源等。

3、性能和安全要求的场景。

4、通过 new 产生一个对象需要非常繁琐的数据准备或访问权限,则可以使用原型模式。

5、一个对象多个修改者的场景。

6、一个对象需要提供给其他对象访问,而且各个调用者可能都需要修改其值时,可以考虑使用原型模式拷贝多个对象供调用者使用。

7、在实际项目中,原型模式很少单独出现,一般是和工厂方法模式一起出现,通过 clone 的方法创建一个对象,然后由工厂方法提供给调用者。原型模式已经与 Java 融为浑然一体,可以随手拿来使用。

 

注意:

与通过对一个类进行实例化来构造新对象不同的是,原型模式是通过拷贝一个现有对象生成新对象的。浅拷贝实现 Cloneable,重写 clone 方法;深拷贝是通过实现 Serializable 读取二进制流。

 

产生新对象:1.构造器实例化对象;2.原型模式,拷贝现有对象生成新对象

 
posted @ 2022-12-15 00:12  kuaiquxie  阅读(93)  评论(0编辑  收藏  举报