Как избежать глобальности в программировании на Perl Tk (Tkx) с использованием модели MVC
У меня есть старое и очень большое приложение на Perl Tk с графическим интерфейсом, которое я реорганизую в Tkx. Я хочу разделить интерфейс на несколько пакетов, чтобы создать модульный интерфейс приложения. Кроме того, я хочу отделить представление от модели, используя контроллер для обеспечения интерфейса между ними.
Мне кажется, что единственный способ спроектировать это с помощью двух огромных глобальных переменных, одна из которых содержит модель ($MODEL), а другая содержит ссылки на виджеты ($UI), которые распределены по многим пакетам. Затем контроллер связывает их с помощью ряда команд, подобных следующим:
$UI->{'entry_widget'}->configure(-variable=>\$MODEL->{'entry_value'});
$UI->{'button_widget'}->configure(-command=>sub {$MODEL->{'entry_value'} = "New Value"} );
Мой вопрос: есть ли лучший способ для разработки приложения, которое позволяет избежать использования этих двух больших глобальных переменных ($ UI и $MODEL)? Любые предложения будут очень приветствоваться.
2 ответа
Вы не хотите избегать глобальных переменных, вы хотите использовать методы, то есть заменить $hashref->{data}
с $model->data
или же $self->model->data
, где $model
или же $self
, является аргументом (или "синглтоном", как демонстрирует Аксеман), переданным обработчику сигнала /callback/ команде, а не хешем, к которому вы обращаетесь напрямую
Вы используете методы для изменения $model
потому что методы могут отказаться обновлять модель бессмысленными / неверными данными, они гарантируют, что вы не пытаетесь платить монопольными деньгами
Ваше приложение всегда будет создавать переменную модели и переменную представления и соединять их (возможно, через посредника, контроллер) посредством передачи аргументов.
Они не должны быть фактическими глобальными переменными в смысле perl ( справиться со Scoping), они могут быть my $variables
и по-прежнему отлично работают, как вы используете их сейчас (через замыкания), и вы избегаете проблем http://perl.plover.com/varvarname.html, но вы не получаете преимуществ интеллектуальных моделей, которые знать, какое топливо им нужно (дизельное или неэтилированное); и подключение ваших взглядов к вашей модели больше печатать
Смотрите также ответы и ссылки из Что такое Model View Presenter?
Я думаю, что методы пакета - это способ сделать что-то глобально доступным, но не глобальную переменную. Так что-то вроде этого, будет работать:
package MVC;
use strict;
use warnings;
use Scalar::Util qw<refaddr>;
my %MVCs;
sub _domain {
my ( $domain_name, $ref, $value ) = @_;
my $r = \$MVCs{ $key }{ $domain_name };
return unless $$r or ref( $value );
if ( ref $value ) {
$$r = $value;
}
return $$r;
}
sub model { shift; return _domain( 'model', @_ ); }
sub controller { shift; return _domain( 'controller', @_ ); }
sub view { shift; return _domain( 'view', @_ ); }
Поэтому вне пакета вам просто нужно вызвать это:
my $controller = MVC->controller( $self );
Чтобы получить контроллер, связанный с объектом.
Вы могли бы даже поместить некоторую логику экспорта в аксессоры, например:
unless ( $ref->can( $domain_name )) {
not strict 'refs';
*{ ref( $ref ) . "::$domain_name" }
= sub { _domain( $domain_name, $ref ) }
;
}
Так что вы можете просто сделать это:
$self->view->view_method( @args );