原型模式(原型设计模式)详解-mile米乐体育

在有些系统中,存在大量相同或相似对象的创建问题,如果用传统的构造函数来创建对象,会比较复杂且耗时耗资源,用原型模式生成对象就很高效,就像孙悟空拔下猴毛轻轻一吹就变出很多孙悟空一样简单。

原型模式的定义与特点

原型(prototype)模式的定义如下:用一个已经创建的实例作为原型,通过复制该原型对象来创建一个和原型相同或相似的新对象。在这里,原型实例指定了要创建的对象的种类。用这种方式创建对象非常高效,根本无须知道对象创建的细节。例如,windows 操作系统的安装通常较耗时,如果复制就快了很多。在生活中复制的例子非常多,这里不一一列举了。

原型模式的优点:

  • java 自带的原型模式基于内存二进制流的复制,在性能上比直接 new 一个对象更加优良。
  • 可以使用深克隆方式保存对象的状态,使用原型模式将对象复制一份,并将其状态保存起来,简化了创建对象的过程,以便在需要的时候使用(例如恢复到历史某一状态),可辅助实现撤销操作。

原型模式的缺点:

  • 需要为每一个类都配置一个 clone 方法
  • clone 方法位于类的内部,当对已有类进行改造的时候,需要修改代码,违背了开闭原则。
  • 当实现深克隆时,需要编写较为复杂的代码,而且当对象之间存在多重嵌套引用时,为了实现深克隆,每一层对象对应的类都必须支持深克隆,实现起来会比较麻烦。因此,深克隆、浅克隆需要运用得当。

原型模式的结构与实现

由于 java 提供了对象的 clone() 方法,所以用 java 实现原型模式很简单。

1. 模式的结构

原型模式包含以下主要角色。
  1. 抽象原型类:规定了具体原型对象必须实现的接口。
  2. 具体原型类:实现抽象原型类的 clone() 方法,它是可被复制的对象。
  3. 访问类:使用具体原型类中的 clone() 方法来复制新的对象。
其结构图如图 1 所示。 图1 原型模式的结构图

2. 模式的实现

原型模式的克隆分为浅克隆深克隆
  • 浅克隆:创建一个新对象,新对象的属性和原来对象完全相同,对于非基本类型属性,仍指向原有属性所指向的对象的内存地址。
  • 深克隆:创建一个新对象,属性中引用的其他对象也会被克隆,不再指向原有对象地址。
java 中的 object 类提供了浅克隆的 clone() 方法,具体原型类只要实现 cloneable 接口就可实现对象的浅克隆,这里的 cloneable 接口就是抽象原型类。其代码如下:
 //具体原型类 class realizetype implements cloneable {     realizetype() {         system.out.println("具体原型创建成功!");     }      public object clone() throws clonenotsupportedexception {         system.out.println("具体原型复制成功!");         return (realizetype) super.clone();     } }  //原型模式的测试类 public class prototypetest {     public static void main(string[] args) throws clonenotsupportedexception {         realizetype obj1 = new realizetype();         realizetype obj2 = (realizetype) obj1.clone();         system.out.println("obj1==obj2?"   (obj1 == obj2));     } }
程序的运行结果如下:
 具体原型创建成功! 具体原型复制成功! obj1==obj2?false

原型模式的应用实例

【例1】用原型模式模拟“孙悟空”复制自己。 分析:孙悟空拔下猴毛轻轻一吹就变出很多孙悟空,这实际上是用到了原型模式。这里的孙悟空类 sunwukong 是具体原型类,而 java 中的 cloneable 接口是抽象原型类。 同前面介绍的猪八戒实例一样,由于要显示孙悟空的图像(点击此处下载该程序所要显示的孙悟空的图片),所以将孙悟空类定义成面板 jpanel 的子类,里面包含了标签,用于保存孙悟空的图像。 另外,重写了 cloneable 接口的 clone() 方法,用于复制新的孙悟空。访问类可以通过调用孙悟空的 clone() 方法复制多个孙悟空,并在框架窗体 jframe 中显示。图 2 所示是其结构图。 图2 孙悟空生成器的结构图 程序代码如下:
 import java.awt.*; import javax.swing.*;  class sunwukong extends jpanel implements cloneable {     private static final long serialversionuid = 5543049531872119328l;      public sunwukong() {         jlabel l1 = new jlabel(new imageicon("src/wukong.jpg"));         this.add(l1);     }      public object clone() {         sunwukong w = null;         try {             w = (sunwukong) super.clone();         } catch (clonenotsupportedexception e) {             system.out.println("拷贝悟空失败!");         }         return w;     } }  public class prototypewukong {     public static void main(string[] args) {         jframe jf = new jframe("原型模式测试");         jf.setlayout(new gridlayout(1, 2));         container contentpane = jf.getcontentpane();         sunwukong obj1 = new sunwukong();         contentpane.add(obj1);         sunwukong obj2 = (sunwukong) obj1.clone();         contentpane.add(obj2);         jf.pack();         jf.setvisible(true);         jf.setdefaultcloseoperation(jframe.exit_on_close);     } }
程序的运行结果如图 3 所示。 图3 孙悟空克隆器的运行结果 用原型模式除了可以生成相同的对象,还可以生成相似的对象,请看以下实例。 【例2】用原型模式生成“三好学生”奖状。 分析:同一学校的“三好学生”奖状除了获奖人姓名不同,其他都相同,属于相似对象的复制,同样可以用原型模式创建,然后再做简单修改就可以了。图 4 所示是三好学生奖状生成器的结构图。 图4 奖状生成器的结构图 程序代码如下:
 public class prototypecitation {     public static void main(string[] args) throws clonenotsupportedexception {         citation obj1 = new citation("张三", "同学:在2016学年第一学期中表现优秀,被评为三好学生。", "韶关学院");         obj1.display();         citation obj2 = (citation) obj1.clone();         obj2.setname("李四");         obj2.display();     } }  //奖状类 class citation implements cloneable {     string name;     string info;     string college;      citation(string name, string info, string college) {         this.name = name;         this.info = info;         this.college = college;         system.out.println("奖状创建成功!");     }      void setname(string name) {         this.name = name;     }      string getname() {         return (this.name);     }      void display() {         system.out.println(name   info   college);     }      public object clone() throws clonenotsupportedexception {         system.out.println("奖状拷贝成功!");         return (citation) super.clone();     } }
程序运行结果如下:
 奖状创建成功! 张三同学:在2016学年第一学期中表现优秀,被评为三好学生。韶关学院 奖状拷贝成功! 李四同学:在2016学年第一学期中表现优秀,被评为三好学生。韶关学院

原型模式的应用场景

原型模式通常适用于以下场景。
  • 对象之间相同或相似,即只是个别的几个属性不同的时候。
  • 创建对象成本较大,例如初始化时间长,占用cpu太多,或者占用网络资源太多等,需要优化资源。
  • 创建一个对象需要繁琐的数据准备或访问权限等,需要提高性能或者提高安全性。
  • 系统中大量使用该类对象,且各个调用者都需要给它的属性重新赋值。
在 spring 中,原型模式应用的非常广泛,例如 scope='prototype'、json.parseobject() 等都是原型模式的具体应用。

原型模式的扩展

原型模式可扩展为带原型管理器的原型模式,它在原型模式的基础上增加了一个原型管理器 prototypemanager 类。该类用 hashmap 保存多个复制的原型,client 类可以通过管理器的 get(string id) 方法从中获取复制的原型。其结构图如图 5 所示。 图5 带原型管理器的原型模式的结构图 【例3】用带原型管理器的原型模式来生成包含“圆”和“正方形”等图形的原型,并计算其面积。分析:本实例中由于存在不同的图形类,例如,“圆”和“正方形”,它们计算面积的方法不一样,所以需要用一个原型管理器来管理它们,图 6 所示是其结构图。 图6 图形生成器的结构图 程序代码如下:
 import java.util.*;  interface shape extends cloneable {     public object clone();    //拷贝      public void countarea();    //计算面积 }  class circle implements shape {     public object clone() {         circle w = null;         try {             w = (circle) super.clone();         } catch (clonenotsupportedexception e) {             system.out.println("拷贝圆失败!");         }         return w;     }      public void countarea() {         int r = 0;         system.out.print("这是一个圆,请输入圆的半径:");         scanner input = new scanner(system.in);         r = input.nextint();         system.out.println("该圆的面积="   3.1415 * r * r   "\n");     } }  class square implements shape {     public object clone() {         square b = null;         try {             b = (square) super.clone();         } catch (clonenotsupportedexception e) {             system.out.println("拷贝正方形失败!");         }         return b;     }      public void countarea() {         int a = 0;         system.out.print("这是一个正方形,请输入它的边长:");         scanner input = new scanner(system.in);         a = input.nextint();         system.out.println("该正方形的面积="   a * a   "\n");     } }  class prototypemanager {     private hashmap ht = new hashmap();      public prototypemanager() {         ht.put("circle", new circle());         ht.put("square", new square());     }      public void addshape(string key, shape obj) {         ht.put(key, obj);     }      public shape getshape(string key) {         shape temp = ht.get(key);         return (shape) temp.clone();     } }  public class prototypeshape {     public static void main(string[] args) {         prototypemanager pm = new prototypemanager();         shape obj1 = (circle) pm.getshape("circle");         obj1.countarea();         shape obj2 = (shape) pm.getshape("square");         obj2.countarea();     } }
运行结果如下所示:
 这是一个圆,请输入圆的半径:3 该圆的面积=28.2735  这是一个正方形,请输入它的边长:3 该正方形的面积=9
展开全文
内容来源于互联网和用户投稿,文章中一旦含有米乐app官网登录的联系方式务必识别真假,本站仅做信息展示不承担任何相关责任,如有侵权或涉及法律问题请联系米乐app官网登录删除

最新文章

网站地图