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. linux初学者小记

    a开头的小命令 alias命令 # echo=' - - - ' > /sys/class/scsi_host/host0/scan这条命令是咱们在给虚拟机装了一块新的硬盘后,在不关机的前提下扫 ...

  2. Jupyter Notebook安装和使用详情(你不懂我......)

    一.Jupyter Notebook是什么? 1.notebook jupyter 简介 Jupyter Notebook是一个开源Web应用程序,允许您创建和共享包含实时代码,方程式,可视化效果和叙 ...

  3. windows核心编程 第8章201页旋转锁的代码在新版Visual Studio运行问题

    // 全局变量,用于指示共享的资源是否在使用 BOOL g_fResourceInUse = FALSE; void Func1() { //等待访问资源 while(InterlockedExcha ...

  4. 基于elasticsearch的自定义业务告警的设计思路

    A系统与B系统之间有很多接口交互,但是有一段时间接口经常报错,作为开发如果不能第一时间知道问题且及时解决的话就会收到业务投诉,当月绩效凉凉. 如果你也有这种场景,那么你就需要一个及时告警的功能. 实现 ...

  5. 学习VBA

    学习VBA VBA 就是 (Visual basic for Application) 用的比较多的是在Excel中处理数据,可以方便快捷地使用编程方式来对数据进行操作. VBA 数据类型 Integ ...

  6. __pycache__

    最近在使用python写一个串口模块的时候,偶然发现运行脚本之后,在工程文件夹下面出现了这样一个文件夹__pycache__,所以就特意到网上查了一下这个文件夹是怎么回事. 我们先在源文件中添加一些内 ...

  7. SoapUI 的几种常用参数化方式

    今天给大家来梳理下soapui这款工具关于参数化的几种方式以及具体的应用场景 1.properties 官方文档:https://www.soapui.org/docs/functional-test ...

  8. Asp.NetCore源码学习[2-1]:日志

    Asp.NetCore源码学习[2-1]:日志 在一个系统中,日志是不可或缺的部分.对于.net而言有许多成熟的日志框架,包括Log4Net.NLog.Serilog 等等.你可以在系统中直接使用这些 ...

  9. 记一次客户DB CPU短时间内冲高至99%处理

    问题背景: 客户反映DB CPU短时间内冲高,查询变得缓慢,记录此背景下的处理方式 1> 查看系统负载及相关sql 2> 查看相关sql的执行计划 3> 想看相关sql的执行计划是否 ...

  10. .NET Core ❤ gRPC

    这篇内容主要来自Microsoft .NET团队程序经理Sourabh Shirhatti的博客文章:https://grpc.io/blog/grpc-on-dotnetcore/, .NET Co ...