Prototype模式就是不根据类来生成实例,而是根据实例来生成新实例。至于为什么不能根据类来生成实例,在最后会讲到。

  还是根据实例程序来理解这种设计模式吧。

  

  下面是实例代码。

 package BigJunOba.bjtu.framework;

 public interface Product extends Cloneable{

     public abstract void use (String string);
public abstract Product createClone();
}

  Product接口是复制功能的接口。Product接口继承了Cloneable接口,也就是说实现了Cloneable接口的类的实例可以调用clone方法来自动复制实例。

 package BigJunOba.bjtu.framework;

 import java.util.HashMap;

 public class Manager {

     private HashMap<String, Object> showcase = new HashMap<>();

     public void register(String name, Product proto) {
showcase.put(name, proto);
} public Product create(String protoname) {
Product product = (Product) showcase.get(protoname);
return product.createClone();
}
}

  Manager类使用了Product接口并且通过create方法来复制实例。

  showcase字段是HashMap类型的,这里是用来保存实例的“名字”和“实例”之间的对应关系。

  register方法将实例名字和实现了Product接口的类的实例注册到showcase当中。

 package BigJunOba.bjtu.concretePrototype;

 import BigJunOba.bjtu.framework.Product;

 public class MessageBox implements Product{

     private char decochar;

     public MessageBox(char decochar) {
this.decochar = decochar;
} @Override
public void use(String string) {
int length = string.getBytes().length;
for (int i = 0; i < length + 3 ; i++) {
System.out.print(decochar);
}
System.out.println("");
System.out.println(decochar + " " + string + decochar);
for (int i = 0; i < length + 3; i++) {
System.out.print(decochar);
}
System.out.println("");
} @Override
public Product createClone() {
Product product = null;
try {
product = (Product) clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return product;
} }

  MessageBox类实现了Product接口来对字符串进行加框操作。use方法用来进行加框操作。

  createClone方法用来复制自己。它内部所调用的clone方法时java语言中定义的方法。在进行复制时,原来实例中的字段的值也会被复制到新的实例中。我们之所以可以调用clone方法进行复制,仅仅是因为该类实现了Cloneable接口。如果没有实现这个接口,在运行程序时将会抛出CloneNotSupportedException异常,因此必须捕获这个异常。在这里虽然 MessageBox类只实现了Product接口,但是Product接口继承了Cloneable接口,因此程序不会出现异常。只有类自己(或是它的子类)能够调用java语言中定义的clone方法,当其他类要求复制实例时,必须先调用createClone这样的方法,然后在该方法内部再调用clone方法。

 package BigJunOba.bjtu.concretePrototype;

 import BigJunOba.bjtu.framework.Product;

 public class UnderlinePen implements Product {

     private char ulchar;

     public UnderlinePen(char ulchar) {
this.ulchar = ulchar;
} @Override
public void use(String string) {
int length = string.getBytes().length;
// 这个转义字符\"表示双引号
System.out.println("\"" + string + "\"");
System.out.print(" ");
for (int i = 0; i < length; i++) {
System.out.print(ulchar);
}
System.out.println("");
} @Override
public Product createClone() {
Product product = null;
try {
product = (Product) clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return product;
} }

  UnderlinePen类实现了Product接口用来对字符串进行加波浪线操作。具体实现不多说。

 package BigJunOba.bjtu.test;

 import BigJunOba.bjtu.concretePrototype.MessageBox;
import BigJunOba.bjtu.concretePrototype.UnderlinePen;
import BigJunOba.bjtu.framework.*; public class Main {
public static void main(String[] args) { //准备工作
Manager manager = new Manager();
UnderlinePen uPen = new UnderlinePen('~');
MessageBox mBox = new MessageBox('*');
MessageBox sBox = new MessageBox('/');
manager.register("strong message", uPen);
manager.register("warning box", mBox);
manager.register("slash box", sBox); //生成输出
Product product1 = manager.create("strong message");
product1.use("Hello, world.");
Product product2 = manager.create("warning box");
product2.use("Hello, world.");
Product product3 = manager.create("slash box");
product3.use("Hello, world.");
}
}

  main方法用来进行测试。分为两个部分。在准备工作中,首先生成了Manager的实例,然后通过生成了UnderlinePen的一个实例和MessageBox的两个实例,然后将这三个实例的名字和实例对象注册到manager中。在生成输出中,通过调用create方法,根据hashmap中的name属性,然后再通过clone方法来复制自己也就是现有的实例来得到复制之后的实例。

"Hello, world."
~~~~~~~~~~~~~
****************
* Hello, world.*
****************
////////////////
/ Hello, world./
////////////////

  测试结果如上图。

  分析:总结来说,有三种不能根据类来生成实例的情况。

  1.对象种类繁多,无法将它们整合到一个类中时。

  这种情况是需要处理的对象太多,如果将它们分别作为一个类,必须要编写很多个类文件。在示例程序中,包括三种字符串样式,如果将每种样式都编写为一个类,类的数量会非常庞大。源程序的管理也会非常困难。

  2.难以根据类生成实例时。

  这种情况发生在生成实例的过程太过复杂,很难根据类来生成实例。比如一个用鼠标操作的应用程序,在创建一个通过一系列鼠标操作所创建出来的实例完全一样的实例时就会很复杂。

  3.想解耦框架与生成的实例时。

  这种情况是想要让生成实例的框架不依赖于具体的类。那么怎么能实现呢?思路就是不能指定类名来生成实例,而是要事先“注册”一个“原型”实例,然后通过复制该实例来生成新的实例。在示例程序中,将复制clone实例的部分封装在framework包中,在Manager类的create方法中,没有使用类名,而是使用“strong message”、“warning box”和“slash box”等字符串为生成的实例命名。相比较“new 类名()”这种方式具有更好地通用性。

  这里要说明一下,一旦在代码中出现要使用的类的名字,就无法与该类分离开来,也就无法实现复用。原则就是,那些需要被独立出来作为组件复用的类的名字不要出现在代码中。

  Prototype模式的类图如下:

  类图说明:

  Client:负责使用复制实例的方法生成新的示例。

  Prototype:负责定义用于复制现有实例来生成新实例的方法。

  ConcretePrototype:负责实现复制现有实例并生成新实例的方法。

 

设计模式(六)Prototype模式的更多相关文章

  1. 设计模式之Prototype模式

    通常我们会使用new 类名()的方法会去生成一个新的实例,但在开发过程中,有时候也会有"在不指定类名的前提下生成实例"的需求,那样,就只能根据现有实例来生成新的实例. 有三种情况, ...

  2. 设计模式--原型(Prototype)模式

    写这些也许有人认为“为了模式而模式”.Insus.NET所想到的,每个大师成为大师之前,也许都得这样做. 走路,从小就开始学,直至现在,谁还不是为了走路而走路?一直重复着...... 很多人没有分享自 ...

  3. JS 设计模式六 -- 代理模式

    概念 为一个对象提供一个代用品或占位符,以便控制对它的访问. 当客户不方便直接访问一个对象的时候,需要提供一个替身对象来控制对这个对象的访问. 替身对象对请求做出一些处理之后, 再把请求转交给本体对象 ...

  4. php设计模式六----桥接模式

    1.简介 桥接(Bridge)是用于把抽象化与实现化解耦,使得二者可以独立变化.这种类型的设计模式属于结构型模式,它通过提供抽象化和实现化之间的桥接结构,来实现二者的解耦. 这种模式涉及到一个作为桥接 ...

  5. 设计模式:prototype模式

    使用场景:在不能根据类创建对象的时候,根据已有的对象创建对象 不能根据类创建对象的情况: 创建一个类的对象时,需要根据多种对象来创建,创建的过程非常复杂 难以根据类生成对象 例子: class Pro ...

  6. swift设计模式学习 - 原型模式

    移动端访问不佳,请访问我的个人博客 设计模式学习的demo地址,欢迎大家学习交流 原型模式 用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象. 定义 用原型实例指定创建对象的种类,并且通 ...

  7. Java 实现原型(Prototype)模式

    public class BaseSpoon implements Cloneable {//spoon 匙, 调羹 String name; public String getName() { re ...

  8. 设计模式---对象创建模式之原型模式(prototype)

    一:概念 原型模式(Prototype Pattern) 实际上就是动态抽取当前对象运行时的状态 Prototype模式是一种对象创建型模式,它采取复制原型对象的方法来创建对象的实例.使用Protot ...

  9. 设计模式_11_原型模式(prototype)深拷贝、浅拷贝

    设计模式_11_原型模式(prototype) 浅拷贝: package designPatternOf23; /** * 定义:用原型实例,指定创建对象的种类,并通过拷贝这些原型创建新的对象 * P ...

随机推荐

  1. [技术栈]CRC校验原理及C#代码实现CRC16、CRC32计算FCS校验码

    1.CRC.FCS是什么 CRC,全称Cyclic Redundancy Check,中文名称为循环冗余校验,是一种根据网络数据包或计算机文件等数据产生简短固定位数校验码的一种信道编码技术,主要用来检 ...

  2. DeleteFolder

    import java.io.IOException; import java.net.URI; import java.net.URISyntaxException; /*** * @author ...

  3. Spring Data JPA 梳理 - 使用方法

    1.下载需要的包. 需要先 下载Spring Data JPA 的发布包(需要同时下载 Spring Data Commons 和 Spring Data JPA 两个发布包,Commons 是 Sp ...

  4. vue 条件渲染方式

    1.通过class绑定 <div :class="{'div-class': this.align == 'center'}"></div> 对应的css ...

  5. mysql having和using使用

    1.having当用到聚合函数sum,count后,又需要筛选条件时,就可以考虑使用having,因为where是在聚合前筛选记录的,无法和统计函数一起使用,而having在聚合后筛选记录,可以和统计 ...

  6. TensorFlow2.0(四):填充与复制

    .caret, .dropup > .btn > .caret { border-top-color: #000 !important; } .label { border: 1px so ...

  7. jetbrains全系列可用2018

    转自 https://blog.csdn.net/u014044812/article/details/78727496 仅记录前两种方法 1.授权服务器激活 优点:方便快捷 缺点:激活的人数多了就容 ...

  8. 在 Cocos Creator 中使用 Protobufjs(一)

    一. 环境准备 我一直在探索Cocos H5正确的开发姿势,目前做javascript项目已经离不开 nodejs.npm或grunt等脚手架工具了. 1.初始化package.json文件 npm ...

  9. JVM(四)类加载机制

    1.静态绑定和动态绑定 静态绑定:即前期绑定,在程序执行前方法已经被绑定,此时由编译器或者其他连接程序实现,针对Java,可以理解为编译期的绑定,java中只有final.static.private ...

  10. Flutter学习笔记(29)--Flutter如何与native进行通信

    如需转载,请注明出处:Flutter学习笔记(29)--Flutter如何与native进行通信 前言:在我们开发Flutter项目的时候,难免会遇到需要调用native api或者是其他的情况,这时 ...