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. Android Adapter的一些记录

    一.摘要 An Adapter object acts as a bridge between an AdapterView and the underlying data for that view ...

  2. TCP通信 -C/S中的Socket与ServerSocket

    客户端类:Socket类 TCP通信的客户端:向服务器发送连接请求,给服务器发送数据,读取服务器的数据,两次IO流 java.lang.Object 继承者 java.net.Socket 构造方法: ...

  3. python压测工具Locust

    python压测工具Locust Locust介绍 Locust作为基于Python语言的性能测试框架. 其优点在于他的并发量可以实现单机10倍于LoadRunner和Jmeter工具.他的工作原理为 ...

  4. 对于java的Sting.intern()的一些注意

    今天翻看书时遇到了这样一个问题,对于String.intern()方法又有了一些认识和看法.首先我们看它的api 大意就是intern()方法会在常量池中记录首次出现的实例引用,但是在jdk1.6中却 ...

  5. 获取Android设备标识符

    Android开发中有时候因业务需要客户端要产生一个唯一的标识符使服务器能识别某台Android设备,目前一般使用三种标识符分别为DeviceId.AndroidId.MAC地址. 获取DeviceI ...

  6. Flask基础(10)-->http的无状态协议解决办法一(客户端cookie)

    http的无状态协议 http是一种无状态协议,浏览器请求服务器时无状态的 什么是无状态? 无状态:指的是一次用户请求时,浏览器.服务器无法知道之前这个用户做过什么,每次请求都是一次新的请求. 无状态 ...

  7. MongoDB入门系列之科普篇

    ​ 目录 背景 对比 MongoDB的数据存储格式 背景 最近公司扩展了很多国外客户,那么一个很严重的问题就是翻译,对于国外客户来说,肯定看不懂中文,那就要项目中提供切换各自国家语言的功能. 由于每个 ...

  8. yii2 验证规则使用方法

    required : 必须值验证属性 [['字段名'],required,'requiredValue'=>'必填值','message'=>'提示信息']; #说明:CRequiredV ...

  9. MongoDB 学习笔记之 Aggregation Pipeline

    Aggregation Pipeline: 常用操作符介绍: $project:包含.排除.重命名和显示字段 $match:查询,需要同find()一样的参数 $limit:限制结果数量 $skip: ...

  10. 《构建之法》项目管理&典型用户和场景

    项目管理   PM的能力要求和任务: 1.观察.理解和快速学习能力 2.分析管理能力 3.一定的专业能力 4.自省的能力 在一个项目中,PM的具体任务: 1.带领团队形成团队的目标/远景,把抽象的目标 ...