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