-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathprototype.swift
160 lines (128 loc) · 4.58 KB
/
prototype.swift
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
// Prototype Design Pattern
// https://medium.com/dev-genius/creational-pattern-series-prototype-aae9c50d553d
// ------------------------------------------------------
// The Prototype pattern is a creational design pattern that
// allows you to create new objects by cloning an existing
// object. This is useful when you want to create a new
// object that is similar to an existing object, but you
// don't want to go through the trouble of creating a new
// object from scratch.
// The Prototype pattern delegates the cloning process
// to the actual objects that are being cloned.
// Problem:
// Suppose you are creating a game that involves
// creating different types of monsters with different
// abilities. Instead of creating each monster from scratch
// every time, you can use the Prototype pattern to clone
// an existing monster and modify its attributes to create
// a new one.
// The prototype protocol defines the clone method that will
// return a copy of the prototype
protocol Monster {
func clone() -> Monster
}
// The concrete prototype class that implements the clone method
class Orc: Monster {
var name: String
var health: Int
var strength: Int
init(name: String, health: Int, strength: Int) {
self.name = name
self.health = health
self.strength = strength
}
// The clone method creates a copy of the current object
func clone() -> Monster {
return Orc(name: self.name, health: self.health, strength: self.strength)
}
}
// The client code that uses the prototype to create new monsters
class MonsterSpawner {
private var prototypes: [String: Monster] = [:]
init() {
// Store the prototypes in a dictionary for easy access
prototypes["orc"] = Orc(name: "Orc", health: 50, strength: 10)
}
func spawnMonster(type: String, name: String) -> Monster? {
// Look up the prototype and clone it to create a new object
guard let prototype = prototypes[type] else {
return nil
}
let monster = prototype.clone()
monster.name = name
return monster
}
}
let spawner = MonsterSpawner()
let orc1 = spawner.spawnMonster(type: "orc", name: "Gronk")
let orc2 = spawner.spawnMonster(type: "orc", name: "Krogg")
print(orc1?.name)
print(orc2?.name)
// ====================
// Another Implementation:
// ====================
// NSCopying is a protocol that defines the copy method.
// The copy method returns a copy of the object.
// The copy method is used to create a new object that is
// a copy of the current object.
class NPC: NSCopying {
var name: String
var type: String
var level: Int
init(name: String, type: String, level: Int) {
self.name = name
self.type = type
self.level = level
}
// NSZone is a class that represents a memory zone. It is
// used to allocate memory for objects. The default zone
// is the default zone for the current thread.
func copy(with zone: NSZone? = nil) -> Any {
let copy = type(of: self).init(name: name, type: type, level: level)
return copy
}
}
class Human: NPC {
var race: String
init(name: String, type: String, level: Int, race: String) {
self.race = race
super.init(name: name, type: type, level: level)
}
override func copy(with zone: NSZone? = nil) -> Any {
let copy = super.copy(with: zone) as! Human
copy.race = race
return copy
}
}
class Elf: NPC {
var magicType: String
init(name: String, type: String, level: Int, magicType: String) {
self.magicType = magicType
super.init(name: name, type: type, level: level)
}
override func copy(with zone: NSZone? = nil) -> Any {
let copy = super.copy(with: zone) as! Elf
copy.magicType = magicType
return copy
}
}
class NPCSpawner {
var npc: NPC
init(npc: NPC) {
self.npc = npc
}
func spawnNPC() -> NPC {
return npc.copy() as! NPC
}
}
let human = Human(name: "Bilal", type: "Warrior", level: 10, race: "Human")
let elf = Elf(name: "Osama", type: "Mage", level: 5, magicType: "Fire")
let humanSpawner = NPCSpawner(npc: human)
let elfSpawner = NPCSpawner(npc: elf)
let newHuman = humanSpawner.spawnNPC() as! Human
let newElf = elfSpawner.spawnNPC() as! Elf
// Use the Prototype pattern when your code shouldn’t depend
// on the concrete classes of objects that you need to copy.
// Use the pattern when you want to reduce the number of
// subclasses that only differ in the way they initialize
// their respective objects.