[Design Pattern] Prototype Pattern
Mục lục
- Phần 1: Factory Method
- Phần 2: Abstract Factory
- Phần 3: Builder
- Phần 4: Prototype
- Phần 5: Singleton
- Phần 6: Adapter
- Phần 7: Bridge
Phần 4: Prototype Pattern
Prototype là creational pattern
cho phép ta có thể copy object mà không cần phải phụ thuộc vào class của nó.
Vấn đề
Bạn muốn copy một object, điều đầu tiên cần làm đó là tạo một instance mới của class, sau đò duyệt qua toàn bộ các giá trị của các fields thuộc về object hiện có và gán giá trị đó cho object mới tạo. Cách làm này không sai nhưng không thể áp dụng khi object có những private fields
.
Ngoài ra còn có một vấn đề khác đó là bạn cần phải biết class tương ứng với object vừa tạo, điều này khiến code của bạn sẽ phụ thuộc vào một class. Hơn nữa có thể bạn chỉ biết mỗi interface của object chứ không biết được class cụ thể của nó.
Giải pháp
Prototype Pattern
sẽ uỷ thác việc clone object cho chính object được clone. Cụ thể là bạn có thể định nghĩa một interface chung cho các object mà bạn muốn clone. Đơn giản chỉ là định nghĩa interface
với method clone
.
Việc triển khai clone
method là hoàn toàn giống nhau ở các class. Cụ thể là tạo một object mới, sao lưu toàn bộ giá trị của các fields vào object mới. Bản thân mọi ngôn ngữ lập trình cũng cho phép các object có thể truy cập đến các private field của object khác nên ta hoàn toàn có thể sao lưu các giá trị private
một cách dễ dàng.
Một object hỗ trợ cloning sẽ được gọi là prototype
.
Khi object của bạn có nhiều fields cũng như các config khác thì việc clone chúng có thể được triển khai ở subclass.
Implementation
(1) Định nghĩa Prototype interface
với clone
method
(2) ConcretePrototype class sẽ implement Prototype
interface, ngoài việc copy object gốc, clone
method có thể có các xử lí khác nếu object cần clone là nested object.
(3) Client
có thể tạo ra một bản sao của bất kỳ object nào tuân theo prototype interface.
Pseudocode
Trong ví dụ này, mẫu Prototype cho phép bạn tạo ra các bản sao chính xác của các đối tượng hình học, mà không cần liên kết mã với các lớp của chúng.
Source code
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
class Prototype {
public primitive: any;
public component: object;
public circularReference: ComponentWithBackReference;
public clone(): this {
const clone = Object.create(this);
clone.component = Object.create(this.component);
// If object has nested object, change reference of nested object to
// original object to cloned object
clone.circularReference = {
...this.circularReference,
prototype: { ...this },
};
return clone;
}
}
class ComponentWithBackReference {
public prototype;
constructor(prototype: Prototype) {
this.prototype = prototype;
}
}
const clientCode = () => {
const p1 = new Prototype();
p1.primitive = 245;
p1.component = new Date();
p1.circularReference = new ComponentWithBackReference(p1);
const p2 = p1.clone();
if (p1.primitive === p2.primitive) {
console.log("Primitive is THE SAME");
} else {
console.log("Primitive is DIFF");
}
if (p1.component === p2.component) {
console.log("Component is THE SAME");
} else {
console.log("Component is DIFF");
}
if (p1.circularReference === p2.circularReference) {
console.log("CircularReference is THE SAME");
} else {
console.log("CircularReference is DIFF");
}
if (p1.circularReference.prototype === p2.circularReference.prototype) {
console.log("CircularReferencePrototype is THE SAME");
} else {
console.log("CircularReferencePrototype is DIFF");
}
};
clientCode();