23种设计模式(六) —— 手写实现 Prototype 模式 (生成实例)

x33g5p2x  于2021-12-30 转载在 其他  
字(3.9k)|赞(0)|评价(0)|浏览(183)

Author:Gorit
Date:2021/1/13
Refer:《图解设计模式》
2021年发表博文: 15/50

一、通过复制生成的实例

在 java 中,我们可以通过 new 关键字来生成实例。我们通常这样生成的实例都是要指定类名的。

但是有时候,我们在开放的过程中,也有不指定类名来生成实例的需求。

1.1 以下情况不根据类来生成实例

在以下情况中,我们不能根据类来生成实例,而要根据已有的实例来生成新的实例。

  1. 对象种类繁多,无法将他们整合到一个类中。
  2. 难以根据类生成实例。
  3. 解耦框架与生成的实例时。

1.2 如何实现不依赖类来生成实例?

不根据类来生成实例,而是根据实例来生成实例的设计模式叫 Prototype 模式

Prototype 有原型,**模型 **的意思。在设计模式中,它是根据实例原型,实例模型来生成新的实例。

现在来回答标题提出的问题:
我们可以通过 clone 创建出实例的副本。我们还会用刀拍 clone 方法与 Cloneable 接口的使用方法。

二、示例程序

2.1 实现目标

我们要实现的程序功能是:将字符串放入方框,显示出来 或者 加上下划线显示出来

2.2 类和接口一览表

名字说明
frameworkProduct声明了抽象方法 use 和 createClone 接口
frameworkManager调用 createClone 方法复制实例类
MessageBox将字符串放入方框,并显示出来,实现 use 方法 和 createClone 方法
UnderlinePen给字符串加上上下划线并显示出来的类,实现了 use 和 createClone 方法
Main测试程序行为的类

Product 接口和 Message 类属于 framework包,负责复制实例。
Manager 类虽然会调用 createClone 方法,但是对于具体要复制哪个。并不知道。
但是只要实现了 Product 接口的类,调用它的 createClone 方法就可以复制出新的实例。

MessageBox 类 和 UnderlinePen 类是两个实现了 Product 接口的类。只用实现将这两个类“注册”到 Manager 类中,就可以随时复制新的实例。

2.3 代码实现

Product

package Prototype.framework;
// 继承复制的接口, Cloneable 通过调用 clone 实现对象的调用
public interface Product extends Cloneable{
    public abstract  void use(String s); // 具体是如何使用,交给子类去实现
    public abstract Product createClone();
}

Manager

package Prototype.framework;
import java.util.*;

/** * 使用 product 接口复制实例 */
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();
    }
}

MessageBox

package Prototype;

import Prototype.framework.Product;

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

package Prototype;

import Prototype.framework.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.println(" ");
        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;
    }
}

Main

package Prototype;

import Prototype.framework.Manager;
import Prototype.framework.Product;

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 msg",upen);
        manager.register("warning box",mbox);
        manager.register("slash box",sbox);

        // 生成
        Product p1 = manager.create("strong msg");
        p1.use("Hello World");
        Product p2 = manager.create("warning box");
        p2.use("Hello World");
        Product p3 = manager.create("slash box");
        p3.use("Hello World");

    }
}

执行效果

三、Prototype 模式中登场的角色-

  • Prototype(原型)

Product 角色负责定义用于复制现有实例来生成新实例的方法。 Product 接口扮演此角色

  • ConcretePrototupe(具体的原型)

ConcretePrototype 角色负责实现复制现有的实例并生成新实例的方法。在上述程序中, MessageBox类 和 UnderlinePen 类扮演此角色

  • Client (使用者)

Client 角色负责使用复制实例的方法生成新的实例。在示例中,由 Message类 扮演此角色。

四、补充

4.1 相关设计模式

  • Flyweight 模式(可以在不同地方使用同一个实例)
  • Memento 模式(可以保存当前实例状态,以实现快照和撤销功能)
  • Composite 模式 以及 Decorator 模式(动态创建复杂结构的实例,这里可以用 Prototype 模式快速生成实例)
  • Command 模式(该模式中出现的命令需要复制的时候,可以使用 Prototype)

4.2 clone 方法 和 java.lang.Cloneable 接口

要使用 clone 方法进行复制实例,就要实现 Cloneable 接口,否则就会出现 CloneNotSupportedException

java.lang 包是默认引入的。因此不必显示引入 java.lang 包调用 clone() 方法

4.3 clone() 方法在哪里定义的?

clone() 方法定义在 java.lang.Object 中,因为 Object 类是所有 java 类的父类。因此所有类都默认继承了 Object 类。

五、源代码以及原文档

原文链接 —— 以及其他系列文章整合
源代码

相关文章