使用Java实现原型模式
首先
我读了介绍了GoF设计模式的《增补改订版 Java语言设计模式入门》,并总结了所学内容。
原型模式
原型(Prototype)是指一个产品或设计的初始版本,用于进行测试和改进的模型。
用原型实例来复制(拷贝)其他类并创建新实例的模式被称为原型模式。通常在创建实例时会使用new关键字,但在原型模式中,不使用new,而是使用所有类的超类java.lang.Object类中定义的clone方法来进行实例创建。
角色进入场景
抽象类
Prototype
createCloneメソッドを定義するクラスです。
実装はサブクラスのConcreatePrototypeクラスで行います。
实现类
-
- ConcreatePrototype
-
- スーパークラスのPrototypeクラスで定義されたcreateCloneメソッドの実装を行います。
-
- Client
- createCloneメソッドを使用するクラスです。
具體例子
接口
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言語で学ぶデザインパターン入門