Mercurial > pub > Impl
comparison lib/IMPL/Object/Factory.pm @ 407:c6e90e02dd17 ref20150831
renamed Lib->lib
| author | cin |
|---|---|
| date | Fri, 04 Sep 2015 19:40:23 +0300 |
| parents | |
| children |
comparison
equal
deleted
inserted
replaced
| 406:f23fcb19d3c1 | 407:c6e90e02dd17 |
|---|---|
| 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 |
