view Lib/IMPL/Object/Factory.pm @ 134:44977efed303

Significant performance optimizations Fixed recursion problems due converting objects to JSON Added cache support for the templates Added discovery feature for the web methods
author wizard
date Mon, 21 Jun 2010 02:39:53 +0400
parents 7084af955c57
children 4267a2ac3d46
line wrap: on
line source

package IMPL::Object::Factory;
use strict;

use base qw(IMPL::Object IMPL::Object::Serializable);

use IMPL::Class::Property;

BEGIN {
	public property factory => prop_get | owner_set;
	public property parameters => prop_get | owner_set;
	public property method => prop_get | owner_set; 
}

# custom factory, overrides default
sub new {
	my $self = shift;
	
	return ref $self ? $self->CreateObject(@_) : $self->IMPL::Object::new(@_);
}

sub CTOR {
	my ($this,$factory,$parameters,$method) = @_;
	
	$this->factory($factory) or die new IMPL::InvalidArgumentException("The argument 'factory' is mandatory");
	$this->parameters($parameters) if $parameters;
	$this->method($method) if $method;
}

# override default restore method
sub restore {
	my ($class,$data,$surrogate) = @_;
	
	my %args = @$data;
	
	if ($surrogate) {
		$surrogate->callCTOR($args{factory},$args{parameters},$args{method});
		return $surrogate;
	} else {
		return $class->new($args{factory},$args{parameters},$args{method});
	}
}

sub CreateObject {
	my $this = shift;
	
	if (my $method = $this->method) {
		$this->factory->$method($this->parameters ? (_as_list($this->parameters),@_) : @_);	
	} else {
		$this->factory->new($this->parameters ? (_as_list($this->parameters),@_) : @_);		
	}
}

sub _as_list {
	ref $_[0] ?
		(ref $_[0] eq 'HASH' ?
			%{$_[0]}
			:
			(ref $_[0] eq 'ARRAY'?
				@{$_[0]}
				:
				$_[0]
			)
		)
		:
		($_[0]);
}


1;

__END__

=pod

=head1 SYNOPSIS

=begin code

my $factory = new IMPL::Object::Factory(
	'MyApp::User',
	{
		isAdmin => 1
	}
);

my $class = 'MyApp::User';

my $user;

$user = $class->new(name => 'nobody'); # will create object MyApp::User
                                       # and pass parameters (name=>'nobody')
											
$user = $factory->new(name => 'root'); # will create object MyApp::User
                                       # and pass paremeters (isAdmin => 1, name => 'root')

=end code

Или сериализованная форма в XML.

=begin code xml

<factory type="IMPL::Object::Factory">
	<factory>MyApp::User</factory>,
	<parameters type="HASH">
		<isAdmin>1</isAdmin>
	</parameters>
</factory>

=end code xml

=head1 DESCRIPTION

C<[Serializable]>

Класс, реализующий фабрику классов.

Фабрика классов это любой объект, который имеет метод C< new > вызов которого приводит к созданию нового
объекта. Например каждый класс сам явялется фабрикой, поскольку, если у него вызвать метод
C< new >, то будет создан объект. Полученные объекты, в силу механизмов языка Perl, также
являются фабриками, притом такимиже, что и класс.

Данный класс меняет поведение метода C< new > в зависимости от контекста вызова: статического
метода или метода объекта. При вызове метода C< new > у класса происходит создание объекта
фабрики с определенными параметрами. Далее объект-фабрика может быть использована для создания
объектов уже на основе параметров фабрики.

=head1 MEMBERS

=over

=item C< CTOR($factory,$parameters,$method) >

Создает новый экземпляр фабрики.

=over

=item C<$factory>

Либо имя класса, либо другая фабрика.

=item C<$parameters>

Ссылка на параметры для создания объектов, может быть ссылкой на хеш, массив и т.д.

Если является ссылкой на хеш, то при создании объектов данной фабрикой этот хеш
будет развернут в список и передан параметрами методу C<new>.

Если является ссылкой на массив, то при создании объектов данной фабрикой этот массив
будет передан в списк и передан параметрами методу C<new>.

Если является любым другим объектом или скаляром, то будет передан параметром методу
C<new> как есть.

=item C<$method>

Имя метода (или ссылка на процедуру), который будет вызван у C<$factory> при создании
текущей фабрикой нового объекта.

=back

=item C< [get] factory >

Свойство, содержащее фабрику для создание новых объектов текущей фабрикой. Чаще всего оно содержит
имя класса.

=item C< [get] parameters >

Свойство, содержит ссылку на параметры для создания объектов, при создании объекта эти параметры будут
развернуты в список и переданы оператору C< new > фабрике из свойства C< factory >, за ними будут
следовать параметры непосредственно текущей фабрики.

=item C<new(@params)>

Создает новый объект, используя свйство C<factory> как фабрику и передавая туда параметры
из свойства C<parameters> и списка C<@params>. Ниже приведен упрощенный пример, как это происходит.

=begin code

sub new {
	my ($this,@params) = @_;
	
	my $method = $this->method || 'new';
	
	return $this->factory->$method(_as_list($this->parameters), @params);
}

=end code

=back

=cut