/ld27

To get this branch, use:
bzr branch http://9ix.org/bzr/ld27
1 by Josh C
zoetrope 1.4
1
-- Class: Factory
2
-- A factory allows for simple object pooling; that is,
3
-- reusing object instances instead of creating them and deleting
4
-- them as needed. This approach saves CPU and memory.
5
--
6
-- Be careful of accidentally adding an instance to a view twice.
7
-- This will manifest itself as the sprite moving twice as fast, for
8
-- example, each time it is recycled. The easiest way to avoid this
9
-- problem is for the object to add itself to the view in its onNew
10
-- handler, since that will only be called once.
11
--
12
-- If you only want a certain number of instances of a class ever
13
-- created, first call preload() to create as many instances as you want,
14
-- then freeze() to prevent any new instances from being created.
15
-- If a factory is ever asked to make a new instance of a frozen class
16
-- but none are available for recycling, it returns nil.
17
--
18
-- Event: onReset
19
-- Called not on the factory, but the object is creates whenever
20
-- it is either initially created or recycled via create(). 
21
--
22
-- Extends:
23
--		<Class>
24
25
Factory = Class:extend{
26
	-- private property: objects ready to be recycled, stored by prototype
27
	_recycled = {},
28
29
	-- private property: tracks which pools cannot be added to, stored by prototype.
30
	_frozen = {},
31
32
	-- Method: create
33
	-- Creates a fresh object, either by reusing a previously
34
	-- recycled one or creating a new instance. If the object has
35
	-- a revive method, it calls it.
36
	--
37
	-- Arguments:
38
	--		prototype - <Class> object
39
	--		props - table of properties to mix into the class
40
	--
41
	-- Returns:
42
	-- 		fresh object
43
44
	create = function (self, prototype, props)
45
		local newObj
46
47
		if STRICT then
48
			assert(prototype.instanceOf and prototype:instanceOf(Class), 'asked to create something that isn\'t a class')
49
		end
50
		
51
		if self._recycled[prototype] and #self._recycled[prototype] > 0 then
52
			newObj = table.remove(self._recycled[prototype])
53
			if props then newObj:mixin(props) end
54
		else
55
			-- create a new instance if we're allowed to
56
57
			if not self._frozen[prototype] then
58
				newObj = prototype:new(props)
59
			else
60
				return nil
61
			end
62
		end
63
64
		if newObj.revive then newObj:revive() end
65
		if newObj.onReset then newObj:onReset() end
66
		return newObj
67
	end,
68
69
	-- Method: recycle
70
	-- Marks an object as ready to be recycled. If the object
71
	-- has a die method, then this function it.
72
	--
73
	-- Arguments:
74
	-- 		object - object to recycle
75
	--
76
	-- Returns:
77
	--		nothing
78
79
	recycle = function (self, object)
80
		if not self._recycled[object.prototype] then
81
			self._recycled[object.prototype] = {}
82
		end
83
84
		table.insert(self._recycled[object.prototype], object)
85
86
		if object.die then object:die() end
87
	end,
88
89
	-- Method: preload
90
	-- Preloads the factory with a certain number of instances of a class.
91
	--
92
	-- Arguments:
93
	--		prototype - class object
94
	--		count - number of objects to create
95
	--
96
	-- Returns:
97
	--		nothing
98
99
	preload = function (self, prototype, count)
100
		if not self._recycled[prototype] then
101
			self._recycled[prototype] = {}
102
		end
103
104
		local i
105
106
		for i = 1, count do
107
			table.insert(self._recycled[prototype], prototype:new())
108
		end
109
	end,
110
111
	-- Method: freeze
112
	-- Prevents any new instances of a class from being created via create().
113
	--
114
	-- Arguments:
115
	-- 		prototype - class object
116
	--
117
	-- Returns:
118
	--		nothing
119
120
	freeze = function (self, prototype)
121
		self._frozen[prototype] = true
122
	end,
123
124
	-- Method: unfreeze
125
	-- Allows new instances of a class to be created via create().
126
	--
127
	-- Arguments:
128
	--		prototype - class object
129
	--
130
	-- Returns:
131
	--		nothing
132
133
	unfreeze = function (self, prototype)
134
		self._frozen[prototype] = false
135
	end
136
}