【设计模式

1、模式简介

原型模式的定义:

  通过复制一个现有的对象(原型)来得到一个相似的对象。

原型模式的UML图如下图所示:

 

  从上图中可以看到,所有的对象实体类都是继承自一个Prototype的父类,而prototype类有一个可以复制对象的方法clone(),可以复制其任意子类。这样,所有Prototype类的子类在整个程序中只需要new一次,其他情况下只需要从这几个类中clone即可。

原型模式的适用场景:

  • 当系统中需要重复的使用某一些类的对象时;
  • 当这些对象的差别不是很大或完全相同时;
  • 当一个类的对象必须在某几种状态之中时;
  • 当系统需要对对象进行缓存时。

原型模式的优点:

  • 克隆一般是在内存中以流的形式进行的,比创建一个对象速度快,因此原型模式可以提高系统的性能;
  • 克隆对象的时候可以完全忽略类中的构造方法的访问权限,因此逃避构造函数的约束。

原型模式的缺点:

  • 克隆并不是对所有的数据类型都适用,有些内部类(如ArrayList)是不支持克隆的;
  • 克隆会忽略构造函数的约束,因此对于一些单例的类也会生成克隆对象,容易导致系统错误。

2、案例代码

需求:

  有三种形状圆形(Circle)、矩形(Rectangle)和三角形(Triangle)。多次调用这些形状排成一个队列集合。

分析:

  我们可以把这个题目中的几个逻辑想象成如下图所示的关系:

 

  我们让圆形(Circle)、矩形(Rectangle)和三角形(Triangle)三种图形继承Shape父类,然后在缓存ShapeCache类中的HashMap中分别缓存三种形状,当主函数中需要某种形状的时候,我们就从缓存中克隆一个使用。

说明:

  在JAVA中有一个Cloneable接口,是专门用来实现原型模式的。只需要让一个类实现这个接口,重写Object类的clone()方法,就可以方便的实现原型模式了。

代码:

1)  原型父类Shape:

public class Shape implements Cloneable {
            protected String type;
 
            @Override
            protected Object clone() {
                 Shape shape = null;
                 try {
                       shape = (Shape) super.clone();
                  }catch (CloneNotSupportedException e) {
                       e.printStackTrace();
                 }
                 return shape;
            }
 
            public void introduce() {
                 System.out.println("This is a " + type);
            }
}

2)  Shape的子类(以Circle类为例):

public class Circle extends Shape {
 
            public Circle() {
                 super.type = "Circle";
            }
}

3)  缓存类ShapeCache:

public class ShapeCache {
            private Map<String, Shape> shapes;
 
            public ShapeCache() {
                 loadCache();
            }
 
            private void loadCache() {
                  shapes = new HashMap<>();
                 shapes.put("circle", new Circle());
                 shapes.put("rectangle", new Rectangle());
                 shapes.put("triangle", new Triangle());
            }
 
            public Shape getShape(String id) {
                 Shape shape = shapes.get(id);
                 return (Shape) shape.clone();
            }
}

4)  测试类Test:

public class Test {
            public static void main(String[] args) {
                 List<Shape> shapeList = new ArrayList<>();
 
                  ShapeCachecache = new ShapeCache();
                 shapeList.add(cache.getShape("triangle"));
                 shapeList.add(cache.getShape("circle"));
                 shapeList.add(cache.getShape("rectangle"));
                 shapeList.add(cache.getShape("circle"));
                 shapeList.add(cache.getShape("rectangle"));
                 shapeList.add(cache.getShape("triangle"));
                 shapeList.add(cache.getShape("rectangle"));
                 shapeList.add(cache.getShape("circle"));
 
                 for (Shape shape : shapeList) {
                       shape.introduce();
                 }
            }
}

5)  运行结果如下图所示:

3、扩展

  上面说过,JAVA中为我们提供了一个Cloneable接口,只有实现了这个接口之后,重写Object类中的clone()方法才有效,否则会报CloneNotSupportedException异常。

  使用原型模式复制对象时不会调用类的构造方法,因为复制出来的对象是原型对象复制粘贴出来的,是直接在内存中复制数据,因此不会调用到类的构造方法,甚至连访问权限都对原型模式无效,这一点在编程时需要特别注意。

  Object类的clone()方法只能拷贝对象中的8种基本数据类型,对于数组、容器、引用对象等都不会拷贝,这种现象被成为浅拷贝。与浅拷贝对应的是深拷贝,即在对对象进行浅拷贝之后,将对象中的数组、容器、引用对象单独进行拷贝。

  最后贴出原型模式的GitHub地址:【GitHub - Prototype】

原文地址:https://www.cnblogs.com/itgungnir/p/6211092.html