使用Java实现原型模式

首先

我读了介绍了GoF设计模式的《增补改订版 Java语言设计模式入门》,并总结了所学内容。

原型模式

原型(Prototype)是指一个产品或设计的初始版本,用于进行测试和改进的模型。

用原型实例来复制(拷贝)其他类并创建新实例的模式被称为原型模式。通常在创建实例时会使用new关键字,但在原型模式中,不使用new,而是使用所有类的超类java.lang.Object类中定义的clone方法来进行实例创建。

角色进入场景

image.png

抽象类

Prototype
createCloneメソッドを定義するクラスです。
実装はサブクラスのConcreatePrototypeクラスで行います。

实现类

    • ConcreatePrototype

 

    • スーパークラスのPrototypeクラスで定義されたcreateCloneメソッドの実装を行います。

 

    • Client

 

    createCloneメソッドを使用するクラスです。

具體例子

image.png

接口

Productインタフェース

package framework;

import java.lang.Cloneable;

// 1. java.lang.Cloneableを継承
public interface Product extends Cloneable {
    public abstract void display(String s);

//2. createCloneメソッドを宣言
    public abstract Product createClone();
}

以下是两个要点:
1. 通过实现java.lang.Cloneable接口,可以使用clone方法进行复制。
2. 声明了createClone方法。

我将进行补充说明。
clone方法在所有类的超类java.lang.Object中定义。
要执行这个clone方法,被复制的类必须实现java.lang.Cloneable接口。
如果未实现java.lang.Cloneable接口,则会抛出CloneNotSupportedException异常。
另外,关于createClone方法是用于使用clone方法的方法,但实现是由子类的Surround类和UnderLine类来完成。

实现类

    Clientクラス
package framework;

import java.util.*;

public class Client {
    private HashMap<String, Product> stringName = new HashMap<>();

    // 1. HashMapに登録
    public void register(String name, Product pro) {
        stringName.put(name, pro);
    }

    // 2. createCloneメソッドを使用
    public Product create(String proname) {
        Product p = (Product) stringName.get(proname);
        return p.createClone();
    }
}

Client类是一个用于使用复制方法的类。
重点有以下两点:
1. 在register方法中,将实现了Product接口的实例注册到HashMap中。
2. 在create方法内使用了createClone()方法。

Surroundクラス

import framework.*;

public class Surround implements Product {
    private char srchar;

    public Surround(char srchar) {
        this.srchar = srchar;
    }

    // 1. displayメソッドの実装
    @Override
    public void display(String s) {
        int length = s.getBytes().length;
        for (int i = 0; i < length + 4; i++) {
            System.out.print(srchar);
        }
        System.out.println("");
        System.out.println(srchar + " " + s + " " + srchar);
        for (int i = 0; i < length + 4; i++) {
            System.out.print(srchar);
        }
        System.out.println("\n");
    }

    // 2. createCloneメソッドの実装
    @Override
    public Product createClone() {
        Product p = null;
        try {
            p = (Product) clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return p;
    }
}

Surround类是一个用于实现复制方法的类。
重点在于以下两点:
1. 在构造函数中接收的字符,通过调用display方法时,将接收到的字符串包围并显示。实现了display方法。
2. 实现了createClone方法。

关于这一点的补充说明。有两个要点。

第一个要点是被try-catch语句包围的部分。
如同在Product接口中所解释的那样,clone方法需要实现java.lang.Cloneable接口。
如果没有实现,就会抛出CloneNotSupportedException异常,因此我们将其包围在try-catch语句中以考虑异常的情况。

第二个要点是在createClone方法内调用clone方法。
只能从自己的类(或子类)中调用clone方法。
因此,为了从Client类中调用clone方法,我们需要通过像createClone这样的另一个方法进行调用。

Underlineクラス

import framework.*;

public class Underline implements Product {
    private char ulchar;

    public Underline(char ulchar) {
        this.ulchar = ulchar;
    }

    // 1. displayメソッドの実装
    @Override
    public void display(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("\n");
    }

    // 2. createCloneメソッドの実装
    @Override
    public Product createClone() {
        Product p = null;
        try {
            p = (Product) clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return p;
    }
}

Underline类是一个用于实现复制方法的类,类似于Surround类。要点如下:
1. 在构造函数中接收的字符,在调用display方法时,以接收到的字符串下方以下划线的形式显示。
2. 实现了createClone方法。

由于这个补充说明与Surround类相似,因此省略不提。

执行类 kè)

Mainクラス

import framework.*;

public class Main {
    public static void main(String[] args) {
        // 準備
        Client manager = new Client();
        Underline ul1 = new Underline('-');
        Underline ul2 = new Underline('~');
        Surround sr1 = new Surround('#');
        Surround sr2 = new Surround('@');
        manager.register("underLine text1", ul1);
        manager.register("underLine text2", ul2);
        manager.register("surround text1", sr1);
        manager.register("surround text2", sr2);

        // 生成
        Product p1 = manager.create("underLine text1");
        p1.display("Hello, world.");
        Product p2 = manager.create("underLine text2");
        p2.display("Hello, world.");
        Product p3 = manager.create("surround text1");
        p3.display("Hello, world.");
        Product p4 = manager.create("surround text2");
        p4.display("Hello, world.");
    }
}

在准备阶段,通过register方法对Underline和Surround实例进行登记。
在生成阶段,调用create方法创建实例的副本,然后调用display方法。

执行结果

运行Main.java的结果如下所示。
可以确认每个给定的字符都能够用下划线或者框起来显示。

"Hello, world."
 -------------

"Hello, world."
 ~~~~~~~~~~~~~ 

#################
# Hello, world. #
#################

@@@@@@@@@@@@@@@@@
@ Hello, world. @
@@@@@@@@@@@@@@@@@

如果只使用Markdown,它可能无法将其识别为代码,所以我在后面加了一个全角空格。如果有一种逃逸的方法,请告诉我,将不胜感激…

※补充说明 2018/11/8
非常感谢links_2_3_4提供了在末尾添加全角空格的方法。
感谢。

优点

以下有三点:
1. 当存在多个相似类的实例时,不需要分开管理类,管理变得便利。
2. 当从类中生成实例难以实现时,可以方便地创建实例。
3. 可以将框架和生成的实例分开。

总结

我学习了原型模式,它使用原始实例来复制其他类并创建新实例。如果方便的话,请参考下面提供的示例代码。

    Prototypeサンプルコード

另外,关于其他设计模式的总结可以在下面找到,也请参考。

    [随時更新]Javaでデザインパターンまとめ

请列出您所使用的参考资料

    増補改訂版 Java言語で学ぶデザインパターン入門
广告
将在 10 秒后关闭
bannerAds