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】

【设计模式 - 4】之原型模式(Prototype)的更多相关文章

  1. Net设计模式实例之原型模式( Prototype Pattern)

    一.原型模式简介(Brief Introduction) 原型模式(Prototype Pattern):用原型实例指定创建对象的种类,并通过拷贝这些原型创建新的对象. Specify the kin ...

  2. 设计模式系列之原型模式(Prototype Pattern)——对象的克隆

    说明:设计模式系列文章是读刘伟所著<设计模式的艺术之道(软件开发人员内功修炼之道)>一书的阅读笔记.个人感觉这本书讲的不错,有兴趣推荐读一读.详细内容也可以看看此书作者的博客https:/ ...

  3. 设计模式学习心得<原型模式 Prototype >

    原型模式(Prototype Pattern)是用于创建重复的对象,同时又能保证性能.这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式. 这种模式是实现了一个原型接口,该接口用于创建当 ...

  4. IOS设计模式浅析之原型模式(Prototype)

    原型模式的定义 “使用原型实例指定创建对象的种类,并通过复制这个原型创建新的对象”.最初的定义出现于<设计模式>(Addison-Wesley,1994). 简单来理解就是根据这个原型创建 ...

  5. 《JAVA设计模式》之原型模式(Prototype)

    在阎宏博士的<JAVA与模式>一书中开头是这样描述原型(Prototype)模式的: 原型模式属于对象的创建模式.通过给出一个原型对象来指明所有创建的对象的类型,然后用复制这个原型对象的办 ...

  6. 设计模式入门之原型模式Prototype

    //原型模式:用原型实例指定创建对象的种类,并通过拷贝这些原型创建新的对象 //简单来说,当进行面向接口编程时,假设须要复制这一接口对象时.因为不知道他的详细类型并且不能实例化一个接口 //这时就须要 ...

  7. [工作中的设计模式]原型模式prototype

    一.模式解析 提起prototype,最近看多了js相关的内容,第一印象首先是js的原型 var Person=function(name){ this.name=name; } Person.pro ...

  8. 设计模式(四)原型模式Prototype(创建型)

      设计模式(四)原型模式Prototype(创建型) 1.   概述 我们都知道,创建型模式一般是用来创建一个新的对象,然后我们使用这个对象完成一些对象的操作,我们通过原型模式可以快速的创建一个对象 ...

  9. 乐在其中设计模式(C#) - 原型模式(Prototype Pattern)

    原文:乐在其中设计模式(C#) - 原型模式(Prototype Pattern) [索引页][源码下载] 乐在其中设计模式(C#) - 原型模式(Prototype Pattern) 作者:weba ...

  10. PHP设计模式 原型模式(Prototype)

    定义 和工厂模式类似,用来创建对象.但实现机制不同,原型模式是先创建一个对象,采用clone的方式进行新对象的创建. 场景 大对象的创建. 优点 1.可以在运行时刻增加和删除产品 2.可以改变值或结构 ...

随机推荐

  1. 从外国html5网站上扒来一个鼠标经过的css3 效果,感觉很不错

    鼠标经过的时候,感觉有点像一张纸卷上去的感觉. 下面是代码 <div class="main-container types"> <div class=" ...

  2. kaptcha小案例(转)

    使用kaptcha生成验证码 kaptcha是一个简单好用的验证码生成工具,通过配置,可以自己定义验证码大小.颜色.显示的字符等等.下面就来讲一下如何使用kaptcha生成验证码以及在服务器端取出验证 ...

  3. Android学习3—电话拨号器

    本测试主要实现了一个Android的拨打电话的功能 一:界面预览 由图中可以看出,这个Activity需要3个控件:TextView.EditText.Button 其实实现一个功能要经过几个步骤: ...

  4. 练习SignalR使用

    前言 随着Ajax越来越普遍的使用,前端页面跟后台服务也越来越密切的进行交互,实现前后端进行实时的消息传递尤为重要,一文件上传为例,现在普遍使用ajax上传然后通过flash进行文件进度的显示,这是目 ...

  5. Ext.Date 方法

    1.Ext.Date.add(date,interval,value); 提供执行基本日期运算的简便方法; date 日期对象, interval 一个有效的日期间隔枚举值, value 向当前日期上 ...

  6. php约瑟夫环

    <?php function popChar($str , $m , $current = 0){ $number = count($str); $num = 1; if(count($str) ...

  7. TaskMgr C#技术拾遗

    1. DataGridView和ContextMenuStrip的绑定是发生在DataGridView的CellMouseClick事件,在事件中指定右键菜单弹出: 2. DataGridView的列 ...

  8. unity 基础之InputManager

    unity  基础之InputManager 说一下unity中的InputManager,先截个图 其中Axes指的是有几个轴向!Size指的是有几个轴,改变Size可以添加或者减少轴! Name指 ...

  9. JPA2.1 中三个提升应用性能的新功能

    经常在网上看到开发者们抱怨 JPA 性能低下的帖子或文章,但如果仔细查看这些性能问题,常会发现导致问题的根本原因大致包括以下几个: 使用过多的 SQL 查询从数据库中获取所需的实体信息,即我们常说的n ...

  10. 算法-KMP模式匹配算法

    1朴素算法:逐个比较 2 主要是解决多余比较的麻烦,通过处理比较字符串是否含有重复的字符的问题.