前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >23天读懂23种设计模式:原型模式(创建型)

23天读懂23种设计模式:原型模式(创建型)

作者头像
后台技术汇
发布2022-05-28 12:56:03
2300
发布2022-05-28 12:56:03
举报
文章被收录于专栏:后台技术汇

创建型模式是用来创建对象的模式,抽象了实例化的过程,帮助一个系统独立于其他关联对象的创建、组合和表示方式。

原型模式目的:用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象,进而减少在创建新对象上的性能开销。

winter

原型模式也是创建型的设计模式之一,本文是设计模式系列(共24节)的第4篇文章。

设计模式都从六大原则出发进行总结:《第一节:设计模式的六大原则

创建型设计模式共5种:

原型模式是什么

Prototype(原型模式)属于创建型模式,既不是工厂也不是直接 New,而是以拷贝的方式创建对象。

原理:

Object 类的 clone() 方法是一个本地方法[参考:《JDK源码:Object类》],它可以直接操作内存中的二进制流,所以性能相对 new 实例化来说,更加优秀。(由于 Java 提供了对象拷贝的 clone() 方法,所以用 Java 实现原型模式很简单)

结构图:

Client 是发出指令的客户端,Prototype 是一个接口,描述了一个对象如何克隆自身,比如必须拥有 clone() 方法,而 ConcretePrototype 就是克隆具体的实现,不同对象有不同的实现来拷贝自身。

原型模式的应用

原型模式一般结合工厂方法模式一起使用,通过工厂方法暴露的API,返回某一类型对象的拷贝值(深拷贝&浅拷贝取决开发者实现)。

举例子1:

我们通过抽象类定义了三种图形形状:三角形、圆形、矩形。图形的抽象类 Shape 实现了 Cloneable 接口,并且覆盖了 clone 方法,是Java版本原型模式的通用做法。

代码语言:javascript
复制
public abstract class Shape implements Cloneable {
  protected String type;
  // 定义动作
  abstract void draw();
  public void setType(String type) {
    this.type = type;
  }
  public String getType(){
    return type;
  }
  //克隆方法
  public Object clone() {
    Object clone = null;
    try {
      clone = super.clone();
    } catch (CloneNotSupportedException e) {
      e.printStackTrace();
    }
    return clone;
  }
}
public class Circle extends Shape {
  public Circle(){
    type = "Circle";
  }
  @Override
  public void draw() {
    System.out.println("Inside Circle::draw() method.");

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

接着我们对外提供一个工厂方法类:ShapeCacheFactory,它的作用是:初始化缓存池的原型对象 & 对外提供创建新对象的工厂方法API。

代码语言:javascript
复制
public class ShapeCacheFactory {

  //缓存池,保存多种图形的唯一对象。
  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();
  }

  // 添加三种形状到缓存池:三角形、圆形、矩形
  public static void loadCache() {
    Circle circle = new Circle();
    circle.setType("Circle");
    shapeMap.put(circle.getType(),circle);

    Square square = new Square();
    square.setType("Square");
    shapeMap.put(square.getType(),square);

    Rectangle rectangle = new Rectangle();
    rectangle.setType("Rectangle");
    shapeMap.put(rectangle.getType(),rectangle);
  }
}

测试用例:

代码语言:javascript
复制
public class TestPrototypePattern {
  public static void main(String[] args) {
    //initialization
    ShapeCacheFactory.loadCache();

    //Circle Square Rectangle
    Shape clonedShape = (Shape) ShapeCacheFactory.getShape("Circle");
    System.out.println("Shape : " + clonedShape.getType());

    Shape clonedShape2 = (Shape) ShapeCacheFactory.getShape("Square");
    System.out.println("Shape : " + clonedShape2.getType());

    Shape clonedShape3 = (Shape) ShapeCacheFactory.getShape("Rectangle");
    System.out.println("Shape : " + clonedShape3.getType());
  }
}

结果输出:

代码语言:javascript
复制
Shape : Circle
Shape : Square
Shape : Rectangle

原型模式的优点

Java 自带的原型模式基于内存二进制流的复制,在性能上比直接 new 一个对象更加优良。因为相对 new 来说,clone() 少了调用构造函数。如果构造函数中存在大量属性初始化或大对象,则使用 clone() 的复制对象的方式性能会好一些。

原型模式的缺点

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

2、必须实现 Cloneable 接口。

原型模式在spring的使用

原型模式在开源框架中的应用也非常广泛,在使用了Spring的web工程中,除非特殊情况,我们都会选择使用Spring的IOC功能来管理Bean,而不是用到时去new一个。例如 Spring 中,@Service 默认都是单例的。

  Spring定义了多种作用域,可以基于这些作用域创建bean,包括:

  • 单例( Singleton):在整个应用中,只创建bean的一个实例。
  • 原型( Prototype):每次注入或者通过Spring应用上下文获取的时候,都会创建一个新的bean实例。

因为Spring管理的Bean默认是单例的(即Spring创建好Bean,需要时就拿来用,而不是每次用到时都去new,又快性能又好),但有时候单例并不满足要求(例如出现的线程安全问题,参考《单例模式》),这时可以使用@Scope("prototype")注解,可以通知Spring把被注解的Bean变成多例。(篇幅所限,后续讲解spring源码时再一起详细探讨)

总结

本节主要讲解了原型模式的实现方法和优缺点,另外补充了spring源码使用到的原型模式案例:@Scope("prototype")。一般开发中,我们遇到需要大量复制同一对象的场景,使用原型模式都是不错的选择,且效率好。

另外,创建型设计模式还包括:抽象工厂模式和建造者模式,待后续我们再细细解读。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-01-10,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 后台技术汇 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 原型模式是什么
  • 原型模式的应用
  • 原型模式在spring的使用
  • 总结
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档