设计模式之原型模式(Prototype 模式)引入原型模式原型模式的实例小结为什么需要使用原型模式

  • 引入原型模式
  • 原型模式的实例
  • 为什么需要使用原型模式

引入原型模式

如果读者很熟悉javascript的话,对原型这个词应该不会陌生。

原型是用来生成实例的,但不是利用类来生成实例,而是通过实例来生成实例。

为什么我们需要用过类来生成实例呢?

联想到浏览器中,如果我们生成了一个button实例,这个button实例经过一系列操作,携带了各种信息,比如button加颜色,加背景图,加文字,加事件等等。如果我们这时候需要和这个button实例完全一样的一个实例,仅仅通过类new 一个button出来是远远不够的,因为我们还要对它进行一系列的操作,所以这个生成一个完全一样的实例的过程是非常复杂的,所以这时候我们就想到可不可以直接根据这个实例,然后生成一个一模一样的实例呢?

实际上,这就是原型模式的基本思想,根据实例原型和实例模式来生成新的实例。

介绍完基本思想后,下面我们就通过一个实例来具体理解一下原型实例。

我们实现一段将字符串加上方框中打印出来或者是加入下划线显示出来。

Java中要实现原型模式,也就是实例的复制,我们可以直接利用clone方法,需要实现cloneable接口。

原型模式的实例

我们先定义一个接口,Product接口,这个接口是复制功能的接口,继承了cloneable接口

public interface Product extends Cloneable {
    public abstract void use(String s);
    public abstract Product createClone();
}

createClone是用来复制实例的方法,use方法是用来使用实例方法的。这些方法具体都交给子类去实现。

我们实现一个具体的子类,MessageBox,它的作用是可以给字符创添加类似方框的边界的图案。 这个类实现了product接口,createClone是用于复制自己,生成一个新的一模一样的实例,也就是原型模式的思想。use方法将结果显示出来。

public class MessageBox implements Product {
    private char decochar;
    public MessageBox(char decochar) {
        this.decochar = decochar;
    }
    public void use(String s) {
        int length = s.getBytes().length;
        for (int i = 0; i < length + 4; i++) {
            System.out.print(decochar);
        }
        System.out.println("");
        System.out.println(decochar + " "  + s + " " + decochar);
        for (int i = 0; i < length + 4; i++) {
            System.out.print(decochar);
        }
        System.out.println("");
    }
    public Product createClone() {
        Product p = null;
        try {
            p = (Product)clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return p;
    }
}

同样的我们实现可以给字符串添加下划线的类UnderlinePen 这个类同样实现了product接口,并且可以复制自己生成一个新的实例。

public class UnderlinePen implements Product {
    private char ulchar;
    public UnderlinePen(char ulchar) {
        this.ulchar = ulchar;
    }
    public void use(String s) {
        int length = s.getBytes().length;
        System.out.println("\""  + s + "\"");
        System.out.print(" ");
        for (int i = 0; i < length; i++) {
            System.out.print(ulchar);
        }
        System.out.println("");
    }
    public Product createClone() {
        Product p = null;
        try {
            p = (Product)clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return p;
    }
}

最后我们新建一个管理类Manager来管理这些对象的创建,复制和使用。 Manager类中有一个map字段,用来存储product对象。create方法根据对象的名字在map找到对象的实例,然后调用实例的createClone方法,从而复制出一个实例。

public class Manager {
    private HashMap showcase = new HashMap();
    public void register(String name, Product proto) {
        showcase.put(name, proto);
    }
    public Product create(String protoname) {
        Product p = (Product)showcase.get(protoname);
        return p.createClone();
    }
}

我们来测试一下:

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 p1 = manager.create("strong message");
        p1.use("Hello, world.");
        Product p2 = manager.create("warning box");
        p2.use("Hello, world.");
        Product p3 = manager.create("slash box");
        p3.use("Hello, world.");
    }
}

运行结果:

image.png

上述代码一个简易的类图:

image.png

小结

下面我们来总结Prototype原型模式

首先,我们给出Prototype原型模式的类图

image.png

通常会有一个原型接口或者类,定义clone方法,就像此例中的Product接口,然后会有具体的原型实例去实现或者继承自这个接口,就像这个例子中的UnderlinePen类和MessageBox

学到这里我们基本把原型模式讲完了。

为什么需要使用原型模式

但读者可能还能会有疑问,我们直接通过类new出一个实例不就可以了,为什么要搞这么复杂? new Sth(); 在本文的开头,我们就举了需要用到原型模式的例子,现在我们结合实例程序再来谈一下:

  • 对象总类繁多,无法将他们整合到一个类中 例如例子中的有用‘~’作为下划线,有的用‘*’或者‘/’。 本例比较简单,只生成了三种样式,不过想要做,不论多少种样式都可以实现,但是如果为每个样式实现一个类,就会变得非常复杂。类的数量会非常多。
  • 难以根据类生成实例 本例中可能感觉不到这一点。大家可以试想一下开发一个用户可以使用鼠标操作的,类似于图形编辑器的应用,假如我们想生成一个和用户通过一系列鼠标点击创建出来的实例,这个时候,显然无法根据类来生成实例,会变的非常复杂,但我们可以采取原型模式,根据实例生成实例,直接复制出一个实例就可以了。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏C语言及其他语言

实例说明

上一节,我们大致总揽了一个简单C程序的框架,程序如下: #include<stdio.h> /*引入头文件*/ int main(void) /*一个简单的C程...

2868
来自专栏每日一篇技术文章

Java_面向对象_04

面向对象是Java的核心,面向对象的核心是用人类解决问题的方法对复杂的客观问题进行分析,组织和解答,对于程序员而言,难点在于尽可能正确描述问题的抽象。面向对象的...

823
来自专栏老九学堂

【超全】C语言初学者必须掌握的关键字!

其实小伙伴在写代码的时候,关键字还是用的比较多的,老九主要就平常中用到的常用关键字进行总结,便于小伙伴们更全面的理解其在代码中的意图。 C语言关键字总结 sta...

3776
来自专栏Python爬虫与数据挖掘

Python正则表达式初识(一)

首先跟大家简单唠叨两句为什么要学习正则表达式,为什么在网络爬虫的时候离不开正则表达式。正则表达式在处理字符串的时候扮演着非常重要的角色,在网络爬虫的时候也十分常...

1415
来自专栏北京马哥教育

Python 开发者不得不知的魔术方法(Magic Method)

来源:j_hao104 my.oschina.net/jhao104/blog/779743 介绍 在Python中,所有以“__”双下划线包起来的方法,都统...

2987
来自专栏HTML5学堂

轻松但深入的学习闭包原理 —— 曾让几乎所有JS新手痛恨的知识

HTML5学堂-码匠:这或许是你看过的,最浅显易懂的一篇关于闭包原理的讲解! 闭包的官方定义 官方定义:闭包是一个拥有许多变量和绑定了这些变量的环境的表达式(通...

3886
来自专栏python3

python3--变量,布尔值,用户交互 input,if语句,while循环

已经运行了第一个python程序,即:终端---->cmd----->python 文件路劲。回车搞定~

2392
来自专栏算法修养

位运算总结

用了那么多位运算,这里总结一下把。 先看常用的位运算有哪些吧: 1 & a&b 就是a的二进制形式与b的二进制形式,相同的位置必须两个都是1,那么结果...

3458
来自专栏C/C++基础

控制对象的创建方式(禁止创建栈对象or堆对象)和创建的数量

我们知道,C++将内存划分为三个逻辑区域:堆、栈和静态存储区。既然如此,我称位于它们之中的对象分别为堆对象,栈对象以及静态对象。通常情况下,对象创建在堆上还是在...

962
来自专栏Golang语言社区

初学者需要注意的问题-变量的作用域

go语言支持多变量同时赋值或者初始化,这是一个很方便的特性。它也允许使用:=操作符同时声明部分新变量,并且给已有变量赋值,这会带来一些需要注意的问题,一不小心就...

4137

扫码关注云+社区

领取腾讯云代金券