创建型-综合题-Prototype

题目

Java设计模式练习题:原型模式 - 周报克隆系统

一、案例背景

在一些企业中,员工需要每周提交工作周报,内容通常包括本周完成的任务、问题记录、附件等。通常每周的周报结构大致相同,员工只需要在上一周周报基础上稍作修改即可。为了避免每次都从头填写,企业希望实现一个“克隆周报”的系统,使员工可以复制上一份周报进行编辑。

该系统需要支持以下功能:

  • 创建一份原始周报;
  • 使用克隆方法复制周报对象;
  • 修改副本中的部分内容,不影响原始周报;
  • 附件对象也应被一并复制。

二、任务说明

1. 请使用原型设计模式完成如下功能:

· 定义周报类 WeeklyLog,包含字段:name、date、content 和附件 attachment(类型为 Attachment)。

· 实现深克隆功能,使克隆周报对象后,其附件对象与原始周报互不影响。

· 实现原型接口 Cloneable 或通过 Serializable + IO 实现深克隆。

· 编写测试类 Client,克隆一份周报并比较原对象与副本是否为不同对象,附件是否独立。

三、结构图(文字表示)

[WeeklyLog] ← 周报类,实现深克隆(包含附件)
[Attachment] ← 附件类
[Client] ← 客户端,进行克隆操作

四、示例运行结果

周报是否相同? false
附件是否相同? false
原始周报内容:张三 - 第12周 - 完成模块A设计
克隆周报内容:张三 - 第12周 - 完成模块A设计

五、提示建议

• 实现 Serializable 接口并使用对象流进行深克隆。
• 使用 clone() 方法实现浅克隆可用于对比理解。
• 比较原始对象和克隆对象的地址以及内部引用地址。

代码实现

PlantUML

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
38
39
40
41
42
43
44
45
46
47
48
49
50
@startuml
!theme plain

interface Serializable

class Attachment {
- name: String
- type: String
- size: long
+ Attachment(name: String, type: String, size: long)
+ getName(): String
+ setName(name: String): void
+ getType(): String
+ setType(type: String): void
+ getSize(): long
+ setSize(size: long): void
+ toString(): String
}

class WeeklyLog {
- name: String
- date: String
- content: String
- attachment: Attachment
+ WeeklyLog(name: String, date: String, content: String, attachment: Attachment)
+ getName(): String
+ setName(name: String): void
+ getDate(): String
+ setDate(date: String): void
+ getContent(): String
+ setContent(content: String): void
+ getAttachment(): Attachment
+ setAttachment(attachment: Attachment): void
+ deepClone(): WeeklyLog
+ toString(): String
}

class Client_4 {
+ {static} main(args: String[]): void
}

Serializable <|.. Attachment
Serializable <|.. WeeklyLog

WeeklyLog *-- Attachment : contains

Client_4 ..> WeeklyLog
Client_4 ..> Attachment

@enduml

源码

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
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
import java.io.*;  

// Java设计模式练习题:原型模式 - 周报克隆系统
// 原型模式
// Attachment Class - Needs to be Serializable for deep cloning
class Attachment implements Serializable {
private String name;
private String type;
private long size;

public Attachment(String name, String type, long size) {
this.name = name;
this.type = type;
this.size = size;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public String getType() {
return type;
}

public void setType(String type) {
this.type = type;
}

public long getSize() {
return size;
}

public void setSize(long size) {
this.size = size;
}

@Override
public String toString() {
return "Attachment [Name: " + name + ", Type: " + type + ", Size: " + size + " Bytes]";
}
}

// WeeklyLog Class - Implements deep cloning using Serialization
class WeeklyLog implements Serializable {
private String name;
private String date;
private String content;
private Attachment attachment; // Reference to the Attachment object

public WeeklyLog(String name, String date, String content, Attachment attachment) {
this.name = name;
this.date = date;
this.content = content;
this.attachment = attachment;
}

// Getters and Setters
public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public String getDate() {
return date;
}

public void setDate(String date) {
this.date = date;
}

public String getContent() {
return content;
}

public void setContent(String content) {
this.content = content;
}

public Attachment getAttachment() {
return attachment;
}

public void setAttachment(Attachment attachment) {
this.attachment = attachment;
}

// Deep Clone method using Serialization
public WeeklyLog deepClone() {
WeeklyLog clonedLog = null;
try {
// Write the object to a byte array
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(this); // Write 'this' object to the stream

// Read the object from the byte array ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bis);
clonedLog = (WeeklyLog) ois.readObject(); // Read a new object from the stream

oos.close();
bos.close();
ois.close();
bis.close();

} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
System.err.println("Deep cloning failed: " + e.getMessage());
}
return clonedLog;
}

@Override
public String toString() {
return name + " - " + date + " - " + content;
}
}

// Client Class - Tests the cloning functionality
public class Client_4 {
public static void main(String[] args) {
// 1. Create an original weekly log
Attachment originalAttachment = new Attachment("DesignDoc.pdf", "PDF", 102400);
WeeklyLog originalLog = new WeeklyLog("张三", "第12周", "完成模块A设计", originalAttachment);

System.out.println("Original Weekly Log:");
System.out.println(originalLog);
System.out.println(originalLog.getAttachment());
System.out.println("------------------------------------");

// 2. Clone the weekly log
WeeklyLog clonedLog = originalLog.deepClone();

// 3. Modify the cloned log's content and attachment
if (clonedLog != null) {
clonedLog.setContent("完成模块B开发");
// Change the attachment's name in the cloned log
clonedLog.getAttachment().setName("ImplementationReport.docx");
clonedLog.getAttachment().setType("DOCX");
clonedLog.getAttachment().setSize(204800);

System.out.println("Cloned Weekly Log (after modification):");
System.out.println(clonedLog);
System.out.println(clonedLog.getAttachment());
System.out.println("------------------------------------");

// 4. Compare original and cloned objects
System.out.println("Are WeeklyLogs the same object? " + (originalLog == clonedLog));
System.out.println("Are Attachments the same object? " + (originalLog.getAttachment() == clonedLog.getAttachment()));
System.out.println();

// 5. Display original and cloned content to verify independence
System.out.println("Original Weekly Log Content: " + originalLog);
System.out.println("Cloned Weekly Log Content: " + clonedLog);
System.out.println("Original Attachment: " + originalLog.getAttachment());
System.out.println("Cloned Attachment: " + clonedLog.getAttachment());
}
}
}