407
|
1 package IMPL::Object::Factory;
|
|
2 use strict;
|
|
3
|
|
4 use IMPL::Const qw(:prop);
|
|
5
|
|
6 use IMPL::declare {
|
|
7 base => [
|
|
8 'IMPL::Object' => undef,
|
|
9 'IMPL::Object::Serializable' => undef
|
|
10 ],
|
|
11 props => [
|
|
12 factory => PROP_RO,
|
|
13 parameters => PROP_RO,
|
|
14 method => PROP_RO
|
|
15 ]
|
|
16 };
|
|
17
|
|
18 # custom factory, overrides default
|
|
19 sub new {
|
|
20 my $self = shift;
|
|
21
|
|
22 return ref $self ? $self->CreateObject(@_) : $self->IMPL::Object::new(@_);
|
|
23 }
|
|
24
|
|
25 sub CTOR {
|
|
26 my ($this,$factory,$parameters,$method) = @_;
|
|
27
|
|
28 $this->factory($factory) or die new IMPL::InvalidArgumentException("The argument 'factory' is mandatory");
|
|
29 $this->parameters($parameters) if $parameters;
|
|
30 $this->method($method) if $method;
|
|
31 }
|
|
32
|
|
33 # override default restore method
|
|
34 sub restore {
|
|
35 my ($class,$data,$surrogate) = @_;
|
|
36
|
|
37 my %args = @$data;
|
|
38
|
|
39 if ($surrogate) {
|
|
40 $surrogate->self::CTOR($args{factory},$args{parameters},$args{method});
|
|
41 return $surrogate;
|
|
42 } else {
|
|
43 return $class->new($args{factory},$args{parameters},$args{method});
|
|
44 }
|
|
45 }
|
|
46
|
|
47 sub CreateObject {
|
|
48 my $this = shift;
|
|
49
|
|
50 if (my $method = $this->method) {
|
|
51 $this->factory->$method($this->MergeParameters(@_));
|
|
52 } else {
|
|
53 $this->factory->new($this->MergeParameters(@_));
|
|
54 }
|
|
55 }
|
|
56
|
|
57 sub MergeParameters {
|
|
58 my $this = shift;
|
|
59
|
|
60 $this->parameters ? (_as_list($this->parameters),@_) : @_;
|
|
61 }
|
|
62
|
|
63
|
|
64 sub _as_list {
|
|
65 ref $_[0] ?
|
|
66 (ref $_[0] eq 'HASH' ?
|
|
67 %{$_[0]}
|
|
68 :
|
|
69 (ref $_[0] eq 'ARRAY'?
|
|
70 @{$_[0]}
|
|
71 :
|
|
72 $_[0]
|
|
73 )
|
|
74 )
|
|
75 :
|
|
76 ($_[0]);
|
|
77 }
|
|
78
|
|
79
|
|
80 1;
|
|
81
|
|
82 __END__
|
|
83
|
|
84 =pod
|
|
85
|
|
86 =head1 SYNOPSIS
|
|
87
|
|
88 =begin code
|
|
89
|
|
90 my $factory = new IMPL::Object::Factory(
|
|
91 'MyApp::User',
|
|
92 {
|
|
93 isAdmin => 1
|
|
94 }
|
|
95 );
|
|
96
|
|
97 my $class = 'MyApp::User';
|
|
98
|
|
99 my $user;
|
|
100
|
|
101 $user = $class->new(name => 'nobody'); # will create object MyApp::User
|
|
102 # and pass parameters (name=>'nobody')
|
|
103
|
|
104 $user = $factory->new(name => 'root'); # will create object MyApp::User
|
|
105 # and pass paremeters (isAdmin => 1, name => 'root')
|
|
106
|
|
107 =end code
|
|
108
|
|
109 Или сериализованная форма в XML.
|
|
110
|
|
111 =begin code xml
|
|
112
|
|
113 <factory type="IMPL::Object::Factory">
|
|
114 <factory>MyApp::User</factory>,
|
|
115 <parameters type="HASH">
|
|
116 <isAdmin>1</isAdmin>
|
|
117 </parameters>
|
|
118 </factory>
|
|
119
|
|
120 =end code xml
|
|
121
|
|
122 =head1 DESCRIPTION
|
|
123
|
|
124 C<[Serializable]>
|
|
125
|
|
126 Класс, реализующий фабрику классов.
|
|
127
|
|
128 Фабрика классов это любой объект, который имеет метод C< new > вызов которого приводит к созданию нового
|
|
129 объекта. Например каждый класс сам явялется фабрикой, поскольку, если у него вызвать метод
|
|
130 C< new >, то будет создан объект. Полученные объекты, в силу механизмов языка Perl, также
|
|
131 являются фабриками, притом такимиже, что и класс.
|
|
132
|
|
133 Данный класс меняет поведение метода C< new > в зависимости от контекста вызова: статического
|
|
134 метода или метода объекта. При вызове метода C< new > у класса происходит создание объекта
|
|
135 фабрики с определенными параметрами. Далее объект-фабрика может быть использована для создания
|
|
136 объектов уже на основе параметров фабрики.
|
|
137
|
|
138 =head1 MEMBERS
|
|
139
|
|
140 =over
|
|
141
|
|
142 =item C< CTOR($factory,$parameters,$method) >
|
|
143
|
|
144 Создает новый экземпляр фабрики.
|
|
145
|
|
146 =over
|
|
147
|
|
148 =item C<$factory>
|
|
149
|
|
150 Либо имя класса, либо другая фабрика.
|
|
151
|
|
152 =item C<$parameters>
|
|
153
|
|
154 Ссылка на параметры для создания объектов, может быть ссылкой на хеш, массив и т.д.
|
|
155
|
|
156 Если является ссылкой на хеш, то при создании объектов данной фабрикой этот хеш
|
|
157 будет развернут в список и передан параметрами методу C<new>.
|
|
158
|
|
159 Если является ссылкой на массив, то при создании объектов данной фабрикой этот массив
|
|
160 будет передан в списк и передан параметрами методу C<new>.
|
|
161
|
|
162 Если является любым другим объектом или скаляром, то будет передан параметром методу
|
|
163 C<new> как есть.
|
|
164
|
|
165 =item C<$method>
|
|
166
|
|
167 Имя метода (или ссылка на процедуру), который будет вызван у C<$factory> при создании
|
|
168 текущей фабрикой нового объекта.
|
|
169
|
|
170 =back
|
|
171
|
|
172 =item C< [get] factory >
|
|
173
|
|
174 Свойство, содержащее фабрику для создание новых объектов текущей фабрикой. Чаще всего оно содержит
|
|
175 имя класса.
|
|
176
|
|
177 =item C< [get] parameters >
|
|
178
|
|
179 Свойство, содержит ссылку на параметры для создания объектов, при создании объекта эти параметры будут
|
|
180 развернуты в список и переданы оператору C< new > фабрике из свойства C< factory >, за ними будут
|
|
181 следовать параметры непосредственно текущей фабрики.
|
|
182
|
|
183 =item C<MergeParameters(@params)>
|
|
184
|
|
185 Метод смешивающий фиксированные параметры с параметрами переданными методу C<new(@params)>. По умолчанию
|
|
186 добавляет пареметры фабрики в конец к фиксированным параметрам. Для изменения этого поведения требуется
|
|
187 переопределить данный метод. Также этот метод можно переопределить для передачи параметров, значения
|
|
188 которых вычисляются.
|
|
189
|
|
190 =item C<new(@params)>
|
|
191
|
|
192 Создает новый объект, используя свйство C<factory> как фабрику и передавая туда параметры
|
|
193 из свойства C<parameters> и списка C<@params>. Ниже приведен упрощенный пример, как это происходит.
|
|
194
|
|
195 =begin code
|
|
196
|
|
197 sub new {
|
|
198 my ($this,@params) = @_;
|
|
199
|
|
200 my $method = $this->method || 'new';
|
|
201
|
|
202 return $this->factory->$method(_as_list($this->parameters), @params);
|
|
203 }
|
|
204
|
|
205 =end code
|
|
206
|
|
207 =back
|
|
208
|
|
209 =cut
|