设计模式——原型模式(ProtoType)

定义

用于创建重复的对象,同时又能保证性能。它属于创建型设计模式,它提供了一种创建对象的最佳方法。

模板

Prototype (原型)
  Product 角色负责定义用于复制现有实例来生成新实例的方法。在示例程序中,由 Product 接口扮演此角色。
  
ConcretePrototype(具体的原型)
  ConcretePrototype 角色负责实现复制现有实例并生成新实例的方法。在示例程序中,由 MessageBox 类和 UnderlinePen 类扮演此角色。

Client(使用者)
  Client 角色负责使用复制实例的方法生成新的实例。在示例程序中,由 Manager 类扮演此角色。

实例

  1. 创建一个实现了Cloneable接口的抽象类 Shape(Prototype):
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;
   }
}
  1. 定义具体的实现类(ConcretePrototype)
//Rectangle
public class Rectangle extends Shape {
 
   public Rectangle(){
     type = "Rectangle";
   }
 
   @Override
   public void draw() {
      System.out.println("Inside Rectangle::draw() method.");
   }
}

//Square
public class Square extends Shape {
 
   public Square(){
     type = "Square";
   }
 
   @Override
   public void draw() {
      System.out.println("Inside Square::draw() method.");
   }
}

//Circle
public class Circle extends Shape {
 
   public Circle(){
     type = "Circle";
   }
 
   @Override
   public void draw() {
      System.out.println("Inside Circle::draw() method.");
   }
}
  1. 管理类(相当于Client)
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();
   }
 
   // 对每种形状都运行数据库查询,并创建该形状
   // shapeMap.put(shapeKey, shape);
   // 例如,我们要添加三种形状
  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);
   }
}
  1. 测试程序
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());        
   }
}

输出结果如下:

Shape : Circle
Shape : Square
Shape : Rectangle

优点

下文的适用场景其实也是它的优点

缺点

  1. 创建多个类,增加代码阅读复杂性(所有设计模式通病)
  2. clone方法只是浅拷贝,除五种基础类型之外类型都只是简单的指向引用,不会重新创建成员变量,如需实现需要自定义clone方法。
  3. 通过clone方法不会调用类的构造函数,部分场景(在构造函数中做一些初始化操作的)需要做额外的处理

适用场景

(1)对象种类繁多,无法将它们整合到一个类中时
(2)难以根据类生成实例时
生成实例的过程太过复杂,很难根据类来 生成实例,通常,在想生成一个和之前用户通过操作所创建出来的实例完全一样的实例的时候,我们会事先将用户通过操作所创建出来的实例保存起来,然后在需要时通过复制来生成新的实例。
(3)想解耦框架与生成的实例时
想要让生成实例的框架不依赖于具体的类,这时,不能指定类名来生成实例,要事先”注册一个原型的“实例,然后通过复制该实例来生成新的实例。

其它实例:

  1. 初始化消耗资源较多场景,可以将原有的资源引用到新的对象中去。

参考:

https://www.runoob.com/design-pattern/prototype-pattern.html

posted @ 2019-11-30 13:31  NeilZhang  阅读(856)  评论(0编辑  收藏  举报