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. Spring 梳理 - filter、interceptor、aop实现与区别 -第二篇

    spring mvc中的Interceptor可以理解为是Spring MVC框架对AOP的一种实现方式.一般简单的功能又是通用的,每个请求都要去处理的,比如判断token是否失效可以使用spring ...

  2. map转换成com.google.gson.JsonObject

    String json =new Gson().toJson(map); JsonObject jsonObject =new JsonParser().parse(json).getAsJsonOb ...

  3. Python爬虫(一):爬虫伪装

    1 简介 对于一些有一定规模或盈利性质比较强的网站,几乎都会做一些防爬措施,防爬措施一般来说有两种:一种是做身份验证,直接把虫子挡在了门口,另一种是在网站设置各种反爬机制,让虫子知难而返. 2 伪装策 ...

  4. gitbook 入门教程之从零到壹发布自己的插件

    什么是插件 Gitbook 插件是扩展 Gitbook 功能的最佳方式,如果 Gitbook 没有想要的功能或者说网络上也没有现成的解决方案时,那么只剩下自食其力这条道路,让我们一起来自力更生开发插件 ...

  5. 学习WEBAPI(DOM)第二天

    目录 第二天学习目标: 一.阻止超链接的默认跳转行为 二.鼠标进入事件和鼠标离开事件 三.根据name属性值获取元素==>表单标签,返回的是伪数组 四.根据类样式的名字来获取元素,返回的是伪数组 ...

  6. Mysql高手系列 - 第18篇:mysql流程控制语句详解(高手进阶)

    Mysql系列的目标是:通过这个系列从入门到全面掌握一个高级开发所需要的全部技能. 这是Mysql系列第18篇. 环境:mysql5.7.25,cmd命令中进行演示. 代码中被[]包含的表示可选,|符 ...

  7. Akka实现WordCount(Scala)

    Akka实现WordCount(Scala): 架构图: 项目结构: pom.xml <project xmlns="http://maven.apache.org/POM/4.0.0 ...

  8. Scala 数组和List

    Scala 数组和List: import scala.collection.mutable.ArrayBuffer import scala.collection.mutable.Buffer ob ...

  9. DrawerLayout(抽屉效果)

    DrawerLayout是V4包下提供的一种左滑右滑抽屉布局效果. 实现效果如下: 因为是官方提供的,所以使用起来也相对的比较简单. DrawerLayout 提供 1.当界面弹出的时候,主要内容区会 ...

  10. springboot结合mybatis

    idea中新建springboot项目 pom.xml依赖部分如下 <dependencies> <dependency> <groupId>org.springf ...