天天看点

原型模式_设计模式_java

复制粘贴功能我们都用过,我们可以把一个文件从一个地方复制到另外一个地方,复制完成之后这个文件和之前的文件也没有一点差别,这就是原型模式的思想:首先创建一个实例,然后通过这个实例去拷贝创建新的实例。这篇文章就好好地分析一下原型模式。

文章目录

  • ​​1.认识原型模式​​
  • ​​2.代码实现原型模式​​
  • ​​1.浅拷贝:​​
  • ​​2.深拷贝:​​
  • ​​3.分析原型模式​​
  • ​​1、克隆对象不会调用构造方法​​
  • ​​2、访问权限对原型模式无效​​
  • ​​3、使用场景​​

1.认识原型模式

1、概念

就比如克隆羊,用原型实例指定创建对象的种类,并通过拷贝这些原型创建新的对象。

java上分析:

原型模式_设计模式_java

首先我们可以看到一共有三个角色:

(1)客户(Client)角色:客户类提出创建对象的请求;也就是我们用户使用复制粘贴的功能。

(2)抽象原型(Prototype)角色:此角色定义了的具体原型类所需的实现的方法。也就是定义一个文件,说明一下它有被克隆复制的功能。

(3)具体原型(Concrete Prototype)角色:实现抽象原型角色的克隆接口。就是我们的文件实现了可以被复制的功能。

我们会发现其实原型模式的核心就是Prototype(抽象原型),他需要继承Cloneable接口,并且重写Object类中的clone方法才能有复制粘贴的功能。

2.、分类

既然我们知道原型模式的核心就是拷贝对象,那么我们能拷贝一个对象实例的什么内容呢?这就要区分深拷贝和浅拷贝之分了。

(1)浅拷贝:我们只拷贝对象中的基本数据类型(8种),对于数组、容器、引用对象等都不会拷贝

(2)深拷贝:不仅能拷贝基本数据类型,还能拷贝那些数组、容器、引用对象等,

下面我们就使用代码去实现一下原型模式。这里实现的是不仅有基本数据类型,还有数组和容器,所以实现的是深拷贝。

2.代码实现原型模式

1.浅拷贝:

public class Sheep implements Cloneable{
  private String name;
  private int age;
  private String color;
  public Sheep friend;
  public Sheep(String name, int age, String color) {
    this.age = age;
    this.name = name;
    this.color = color;
  }
  public String getName() {
    return name;
  }
  public void setName(String name) {
    this.name = name;
  }
  public int getAge() {
    return age;
  }
  public void setAge(int age) {
    this.age = age;
  }
  public String getColor() {
    return color;
  }
  public void setColor(String color) {
    this.color = color;
  }
  @Override
  public String toString() {
    return "Sheep [name=" + name + ", age=" + age + ", color=" + color + "]";
  }
  @Override
  protected Object clone() {
    // TODO 自动生成的方法存根
    Sheep sheep = null;
    try {
      sheep = (Sheep)super.clone();
    }catch(Exception e){
      System.out.println(e.getMessage());
    }
    return sheep;
  }

}
      
public class ClientDemo02 {
  @Test
  public void test1() {
    
    Sheep sheep = new Sheep("tom", 1, "白色");
    Sheep sheep2 = (Sheep)sheep.clone();
    System.out.println(sheep == sheep2);
  }
  

}
      

false

public class Client {
  public static void main(String[] args) {
    Sheep sheep = new Sheep("tom", 1, "白色");
    
    sheep.friend = new Sheep("jacy", 2, "黑色");
    
    Sheep sheep2 = (Sheep)sheep.clone();
    Sheep sheep3 = (Sheep)sheep.clone();
    
    
    System.out.println(sheep.friend.hashCode());
    System.out.println(sheep2.friend.hashCode());
    System.out.println(sheep.friend == sheep2.friend);
    
  }

}
      
原型模式_设计模式_java

2.深拷贝:

import java.io.Serializable;

public class DeepCloneableTarget implements Serializable,Cloneable{
  
  private String className;
  private String classClass;
  private static final long serialVersionUID = 1L;
  
  public DeepCloneableTarget(String className, String classClass) {
    this.classClass = classClass;
    this.className = className;
    
  }
  @Override
  protected Object clone() throws CloneNotSupportedException {
    // TODO 自动生成的方法存根
    return super.clone();
  }

}
      
import java.io.Serializable;

public class DeepProtoType implements Serializable,Cloneable{
  public String name;
  public DeepCloneableTarget deepCloneableTarget;
  public DeepProtoType() {
    
  }
  //深拷贝实现
  //1.重写克隆方法
  @Override
  protected Object clone() throws CloneNotSupportedException {
    Object deep = null;
    deep = super.clone();
    DeepProtoType deepProtoType = (DeepProtoType)deep;
    deepProtoType.deepCloneableTarget = (DeepCloneableTarget)deepCloneableTarget.clone();
    
    // TODO 自动生成的方法存根
    return deepProtoType;
  }
  //2.

}
      
public class Client {
  public static void main(String[] args) throws Exception {
    DeepProtoType deepProtoType = new DeepProtoType();
    deepProtoType.name = "松江";
    deepProtoType.deepCloneableTarget = new DeepCloneableTarget("大牛", "类");
    
    //方式1.深拷贝
    DeepProtoType p1 = (DeepProtoType)deepProtoType.clone();
    System.out.println(deepProtoType.deepCloneableTarget == p1.deepCloneableTarget);
    
  }

}
      

false

3.分析原型模式

对于原型模式有几个问题需要我们去注意一下

1、克隆对象不会调用构造方法

从上面的输出其实我们也可以发现,构造方法只在一开始我们创建原型的时候输出了,fileB和fileC都没有调用构造方法,这是因为执行clone方法的时候是直接从内存中去获取数据的,在第一次创建对象的时候就会把数据在内存保留一份,克隆的时候直接调用就好了

2、访问权限对原型模式无效

原理也很简单,我们是从内存中直接复制的,所以克隆起来也会直接无视,复制相应的内容就好了。

3、使用场景

(1)当我们的类初始化需要消耗很多的资源时,就可以使用原型模式,因为我们的克隆不会执行构造方法,避免了初始化占有的时间和空间。

继续阅读