четверг, 20 августа 2009 г.

Паттерн Adapter

Да, собрался с силами и нашел время, чтобы написать, а скорее самому разобраться, с этим паттерном.

Adapter

Применяется (кратко):
  • изменение интерфейса существующего класса
  • объединение интерфейсов нескольких классов
За более подробной информацией идем сюда. Мне интересна только реализация с использование Perl.

Задача:
Что есть: реализуется простой, быстрый web-framework.
Что требуется: возможность быстрой замены шаблонизатора.
По умолчанию используем HTML::Template::Pro, но в будующем надеемся перейти на HTML::CTPP2, либо что-нибудь еще более быстрое ))

К сожалению в Perl нет интерфейсов, хотя можно сделать, что то вроде абстрактного класса (зачем?? :) ). Из этого следует что Class Adapter нам точно не подходит. Поэтому быстро и просто сделать Object Adapter (лучше всегда двигаться по пути наименьшего сопротивления).

Что получили (адаптируем HTML::Template::Pro):


package HTMLTemplateProTemplate;
use strict;

use HTML::Template::Pro;
use File::Spec;

sub new
{
my $class = shift;

return bless {
tmpl => new HTML::Template::Pro(filename => ''),
cache => {},
}, $class;
}

sub set_path
{
my ($self, $path) = @_;

$self->{tmpl}->{path} = $path;
}

sub get
{
my ($self, $tmplname) = @_;

return undef unless $self->_find_template($tmplname);

$self->{tmpl}->{filename} = $tmplname;

return $self;
}

sub _find_template
{
my ($self, $tmplname) = @_;

return $self->{cache}{$tmplname}
if defined $self->{cache}{$tmplname};

for my $dir ( @{$self->{tmpl}->{path}} ){
my $fname = File::Spec->catfile($dir, $tmplname);
if (-e $fname){
$self->{cache}{$tmplname} = $fname;
return $fname;
}
}
return undef;
}

1;


Клиет для этого класса:


package Template;
use HTMLTemplateProTemplate;
use Moose;

has path => ( is => 'ro', default => sub { [] } );
has engine => ( is => 'ro' );

sub new
{
my $class = shift;

my $self = bless { @_ }, $class;

$self->_init;

return $self;
}

sub _init
{
my $self = shift;

$self->{engine} = new HTMLTemplateProTemplate()
unless $self->{engine};

$self->{engine}->set_path( $self->path );
}

sub get
{
my ( $self, $tmplname) = @_;

$self->{engine}->get($tmplname);

return $self->{engine};
}

sub render
{
my ( $self, $context ) = shift;

return $self->{tmpl}->render($context);
}
1;




Когда мы решим использовать HTML::CTPP2 мы адаптируем его для нашего клиента и будем счастливы.