【图解设计模式】Prototype模式

不根据类来生成实例,而是根据实例来生成新实例。

在开发过程中,有时候也会有“在不指定类名的前提下生成实例”的需求。例如,在以下情况下,就不能根据类来生成实例,而要根据现有的实例来生成新的实例。

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

在Java语言中,可以使用clone创建出实例的副本。

示例

将字符串放入方框中显示出来或是加上下划线显示出来。

Product接口

1
2
3
4
5
6
package framework;

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

Manager类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package framework;

import java.util.HashMap;

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类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
import framework.Product;

public class MessageBox implements Product {
private char decochar;

public MessageBox(char decochar) {
this.decochar = decochar;
}

@Override
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("");
}

@Override
public Product createClone() {
Product p = null;

try {
p = (Product) clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}

return p;
}
}

UnderlinePen类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
import framework.Product;

public class UnderlinePen implements Product {
private char ulchar;

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

@Override
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("");
}

@Override
public Product createClone() {
Product p = null;

try {
p = (Product) clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}

return p;
}
}

Main类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import framework.Manager;
import 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 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.");
}
}

运行结果

1
2
3
4
5
6
7
8
"Hello, world."
~~~~~~~~~~~~~
*****************
* Hello, world. *
*****************
/////////////////
/ Hello, world. /
/////////////////

登场角色

Prototype(原型)

Prototype角色负责定义用于赋值现有实例来生成新实例的方法。在示例程序中,由Product接口扮演此角色。

ConcretePrototype(具体的原型)

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

Client(使用者)

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

类图

kc0FOg.png