原型办法

一、界说

**摘自百度百科:**用原型实例指定创立目标的品种,并且经过仿制这些原型创立新的目标。


二、完成办法

原型办法要求目标具有一个能够克隆自己的办法,如此一来,当经过原型实例创立新目标时,就能够不用关怀实例自身,也无需经过new目标来完成。

深克隆与浅克隆的差异

深克隆和浅克隆都是指目标仿制的办法,但它们之间有一些差异。

深克隆创立一个新目标,并且将原始目标及其一切嵌套目标的数据仿制到新目标中。这意味着,新目标的一切特点都是不同的目标实例。这样,如果你改动原始目标中的任何特点,新目标的对应特点不会受到影响,并且反之亦然。深克隆通常需求更多的时间和资源来仿制一切特点和嵌套目标。

浅克隆只会仿制原始目标中的一切特点,可是一切嵌套的目标都将是原始目标中相应特点的引证。这意味着,新目标的特点和原始目标中的特点将同享目标实例。因此,如果你在新目标中更改一个嵌套目标的特点,则原始目标中相应的特点也会受到影响,反之亦然。相关于深克隆,浅克隆需求的时间和资源更少,但或许会导致意外的行为,由于目标引证或许会被同享并且相互影响。

原型办法详细有两种完成办法,一种是简略办法,另一种是挂号办法。我们就这两种办法来讨论一下原型办法的完成办法。

1.简略办法

(1)人物分类

  • 客户(Client)

    提出创立目标的请求的人物

  • 笼统原型(Prototype)

    规则详细原型类要完成的办法

  • 详细原型(Concrete Prototype)

    真正完成创立目标的人物

(2)UML图

【跟着Bummon重学设计模式】原型模式

(3)详细完成

笼统原型(Prototype)

public abstract class Prototype {
  private String name;
  public Prototype(String name){
    this.name = name;
  }
  public String getName(){
    return name;
  }
  public void setName(String name){
    this.name = name;
  }
  /**
  * 克隆办法
  * @return Prototype
  */
  public abstract Prototype clone();
}

详细原型A(Concrete Prototype A)

public class ConcretePrototypeA extends Prototype {
  public ConcretePrototypeA (String name) {
    super(name);
  }
  public Prototype clone() {
    return new ConcretePrototype(this.name);
  }
}

详细原型B(Concrete Prototype B)

public class ConcretePrototypeB extends Prototype {
  public ConcretePrototypeB (String name) {
    super(name);
  }
  public Prototype clone() {
    return new ConcretePrototype(this.name);
  }
}

客户(Client)

public static void main() {
  System.out.println("prototype1");
  ConcretePrototype1 prototype1 = new ConcretePrototype1("prototype1");
  Prototype clone1 = prototype1.clone();
  System.out.println("prototype1:" + prototype1);
  System.out.println("clone:" + clone1);
  System.out.println("prototype2");
  ConcretePrototype2 prototype2 = new ConcretePrototype2("prototype2");
  Prototype clone2 = prototype2.clone();
  System.out.println("prototype2:" + prototype2);
  System.out.println("clone:" + clone2);
}

运转成果

【跟着Bummon重学设计模式】原型模式

2.挂号办法

(1)人物分类

  • 客户(Client)

    提出创立目标的请求的人物

  • 笼统原型人物(Prototype)

    规则详细原型类要完成的办法

  • 详细原型人物(Concrete Prototype)

    真正完成创立目标的人物

  • 原型管理器(Prototype Manager)

    提供原型目标的创立以及其他管理的办法

(2)UML图

【跟着Bummon重学设计模式】原型模式

(3)详细完成

笼统原型目标(Prototype)

public interface Prototype {
  public Prototype clone();
  public String getName();
  public void setName(String name);
}

详细原型A(Concrete Prototype A)

public class ConcretePrototypeA implements Prototype {
  private String name;
  @Override
  public String getName() {
    return this.name;
  }
  @Override
  public void setName(String name) {
    this.name = name;
  }
  @Override
  public Prototype clone() {
    Prototype prototype = new ConcretePrototypeA();
    prototype.setName(this.name);
    return prototype;
  }
  @Override
  public String toString() {
    return "ConcretePrototypeA [name=" + name + "]";
  }
}

详细原型B(Concrete Prototype B)

public class ConcretePrototypeB implements Prototype {
  private String name;
  @Override
  public String getName() {
    return this.name;
  }
  @Override
  public void setName(String name) {
    this.name = name;
  }
  @Override
  public Prototype clone() {
    Prototype prototype = new ConcretePrototypeB();
    prototype.setName(this.name);
    return prototype;
  }
  @Override
  public String toString() {
    return "ConcretePrototypeB [name=" + name + "]";
  }
}

原型管理器(Prototype Manager)

public class PrototypeManager {
  /**
   * 记录原型的编号同原型实例的目标关系
   */
  private static Map<String, Prototype> map = new HashMap<>();
  /**
   *  私有化构造办法,防止从外部创立实例
   */
  private PrototypeManager(){};
  /**
   * 向原型管理器里边增加或许修正原型实例
   * 
   * @param prototypeId 原型编号
   * @param prototype 原型实例
   */
  public static void setPrototype(String prototypeId, Prototype prototype) {
    map.put(prototypeId, prototype);
  }
  /**
   * 根据原型编号删去原型实例
   *
   * @param prototypeId 原型编号
   */
  public static void removePrototype(String prototypeId) {
    map.remove(prototypeId);
  }
  /**
   * 根据原型编号获取原型实例
   *
   * @param prototypeId 原型编号
   * @return 原型实例目标
   * @throws RuntimeException 
   */
  public static Prototype getPrototype(String prototypeId) throws RuntimeException {
    Prototype prototype = map.get(prototypeId);
    if(Objects.isNull(prototype)){
      throw new RuntimeException("原型" + prototypeId + "不存在");
    }
    return prototype;
  }
}

客户(Client)

public class Client {
  public static void main(String[] args){
    try {
      // 创立实例
      Prototype prototypeA = new ConcretePrototypeA();
      // 注册实例
      PrototypeManager.setPrototype("prototypeA",prototypeA);
      // 克隆
      Prototype prototypeC = PrototypeManager.getPrototype("prototypeA").clone();
      prototypeC.setName("张三");
      System.out.println("第一个实例副本:" + prototypeC);
      // 创立实例
      Prototype prototypeB = new ConcretePrototypeB();
      // 注册实例
      PrototypeManager.setPrototype("prototypeB",prototypeB);
      // 克隆
      Prototype prototypeD = PrototypeManager.getPrototype("prototypeB").clone();
      prototypeD.setName("李四");
      System.out.println("第二个实例副本:" + prototypeD);
      // 毁掉第一个实例
      PrototypeManager.removePrototype("prototypeA");
      // 再次克隆第一个实例
      Prototype prototypeE = PrototypeManager.getPrototype("prototypeA").clone();
      prototypeE.setName("王五");
      System.out.println("第一个实例副本:" + prototypeE);
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
}

运转成果

【跟着Bummon重学设计模式】原型模式


三、运用场景

以下部分内容摘自菜鸟教程

目的:用原型实例指定创立目标的品种,并且经过仿制这些原型创立新的目标。

首要处理:在运转期树立和删去原型。

何时运用: 1、当一个体系应该独立于它的产品创立,构成和表明时。 2、当要实例化的类是在运转时刻指守时,例如,经过动态装载。 3、为了防止创立一个与产品类层次平行的工厂类层次时。 4、当一个类的实例只能有几个不同状况组合中的一种时。树立相应数目的原型并克隆它们或许比每次用适宜的状况手艺实例化该类更方便一些。

如何处理:运用已有的一个原型目标,快速地生成和原型目标相同的实例。

要害代码:

  1. 完成克隆操作,在 JAVA 完成 Cloneable 接口,重写 clone(),在 .NET 中能够运用 Object 类的 MemberwiseClone() 办法来完成目标的浅仿制或经过序列化的办法来完成深仿制。
  2. 原型办法相同用于阻隔类目标的运用者和详细类型(易变类)之间的耦合关系,它相同要求这些”易变类”具有安稳的接口。

运用实例:

  1. 细胞分裂。
  2. JAVA 中的 Object clone() 办法。

长处:

  1. 功能提高。
  2. 逃避构造函数的束缚。

缺陷:

  1. 装备克隆办法需求对类的功能进行通盘考虑,这关于全新的类不是很难,但关于已有的类不一定很容易,特别当一个类引证不支撑串行化的间接目标,或许引证含有循环结构的时分。
  2. 有必要完成 Cloneable 接口。

运用场景:

  1. 资源优化场景。
  2. 类初始化需求消化十分多的资源,这个资源包括数据、硬件资源等。
  3. 功能和安全要求的场景。
  4. 经过 new 产生一个目标需求十分繁琐的数据预备或访问权限,则能够运用原型办法。
  5. 一个目标多个修正者的场景。
  6. 一个目标需求提供给其他目标访问,并且各个调用者或许都需求修正其值时,能够考虑运用原型办法仿制多个目标供调用者运用。
  7. 在实际项目中,原型办法很少单独出现,一般是和工厂办法办法一同出现,经过 clone 的办法创立一个目标,然后由工厂办法提供给调用者。原型办法现已与 Java 融为浑然一体,大家能够随手拿来运用。

需求留意的是,原型办法的运用场景应遵循以下几个条件:

  • 目标的创立本钱较高,而仿制目标的本钱较低
  • 目标的初始化进程相对安稳,不会经常发生变化。
  • 目标的特点和状况能够经过浅克隆(仿制引证)或深克隆(仿制值)来进行仿制。

总而言之,原型办法在需求高效创立目标副本、保护目标状况、动态配置目标等场景下是十分有用的。它提供了一种灵活的办法来创立和仿制目标,防止了传统实例化的开支和杂乱性。


四、优缺陷

长处

  • 功能提升(相比new一个目标)。当创立新的目标实例较为杂乱时,运用原型办法能够简化目标的创立进程,经过仿制一个已有实例能够提高新实例的创立效率
  • 在克隆目标时无需与原始目标所属的详细类相耦合。

缺陷

  • 有必要完成Cloneable接口或许完成序列化Serializable接口,每一个类都有必要要装备一个克隆办法,装备克隆办法需求对类的功能进行通盘考虑
  • 在完成深仿制时需求编写较为杂乱的代码,并且当目标之间存在多重的嵌套引证时,为了完成深仿制,每一次目标的类对有必要支撑深仿制,完成起来或许比较麻烦。

重视大众号和博客获取最新文章

Bummon’s Blog

【跟着Bummon重学设计模式】原型模式